扩展BurpSuite的乐趣与收益——Montoya方式——第8部分:BChecks——快速扩展Active和PassiveScanner

admin 2026-05-14 12:51:06 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍BurpSuite的BChecks功能,这是一种基于YAML语法的轻量级扫描规则扩展方式,无需开发完整插件即可实现主动和被动扫描。通过SQL注入检测、盲注验证和SSRF利用Collaborator等实战案例演示BChecks的应用,同时指出其局限性如无法获取响应时间、操作字节数组等复杂场景仍需传统扩展实现。 综合评分: 85 文章分类: 渗透测试,WEB安全,安全工具,漏洞分析,红队


cover_image

扩展Burp Suite的乐趣与收益——Montoya方式——第8部分:BChecks——快速扩展Active和Passive Scanner

幻泉之洲

2026年5月13日 13:04 北京

在小说阅读器读本章

去阅读

BChecks是Burp Suite去年推出的一种轻量级扫描规则扩展方式,用类似YAML的语言编写,无需开发完整扩展。本文通过SQL注入、盲注、SSRF等真实案例,带你快速上手BChecks,同时指出它的局限性:无法获取响应时间、不能操作字节数组,复杂场景还是得用传统扩展。

BChecks是什么?为什么还需要传统扩展?

前面两篇文章我们讲了怎么用Montoya API扩展Burp的Active和Passive Scanner,以及怎么在插件里用Collaborator。今天换个路子——BChecks。

BChecks是PortSwigger去年加进来的新功能,让你不用写插件就能给Scanner加检测规则。规则文件是.bcheck后缀,语法有点像YAML,写起来很快。但别以为它能包打天下。说实话,前两篇文章里我写的那些主动扫描检测规则,一个都没法用BChecks实现。为啥?因为BChecks目前拿不到响应时间(Part 6需要这个),也不能操作字节数组(Part 7构造payload需要)。所以它更适合那些简单的、基于字符串匹配或请求响应的检测。

先列几个有用的链接:

  • BCheck定义参考(https://portswigger.net/burp/documentation/scanner/bchecks/bcheck-definition-reference):最权威的手册。
  • BCheck示例(https://portswigger.net/burp/documentation/scanner/bchecks/worked-examples):PortSwigger官方示例。
  • BCheck GitHub仓库(https://github.com/PortSwigger/BChecks):官方和社区贡献的规则,你也可以提交自己的。

环境搭建:一个带SQL注入的Flask应用

老规矩,先搭靶子。写个简单的Flask应用,暴露一个GET接口,直接拼接SQL查询,典型注入点。

import flask from flask import request import sqlite3

app = flask.Flask(__name__)

@app.route(‘/’, methods=[‘GET’]) def handle_request():    name = request.args.get(‘name’)    if name:        dbfile = ‘test.db’        con = sqlite3.connect(dbfile)        cur = con.cursor()        cur.execute(“SELECT * FROM items WHERE name='” + name + “‘;”)        items = cur.fetchall();        con.close()        return items;    else:        return “Missing parameters”;

app.run(host=”127.0.0.1″, port=5000, debug=True)

创建数据库并插入测试数据:

$ sqlite3 test.db SQLite version 3.46.0 2024-05-23 13:25:27 Enter “.help” for usage hints. sqlite> create table items(id int, name text, value int); sqlite> insert into items values(1,’spoon’,5); sqlite> insert into items values(2,’fork’,5); sqlite> insert into items values(3,’table’,500); sqlite> insert into items values(4,’tv’,200); sqlite> select * from items; 1|spoon|5 2|fork|5 3|table|500 4|tv|200 sqlite> .quit

启动Flask后用浏览器访问,加个单引号看看效果:

OK,确认注入存在。

BCheck入门:被动检测SQL错误

先翻翻官方文档的结构:metadata、control flow(核心是given…then块)、conditionals(if/then/else)、actions(发送请求、报告问题)、reserved variables(request、response等)、functions(字符串、正则、编码、哈希,还能生成Collaborator地址)、以及一些杂项。每个BCheck必须有且只有一个given…then块。

第一个规则很简单:被动检查响应里有没有SQL错误关键字。metadata部分:

metadata:    language: v2-beta    name: “SQL error”    description: “Passive detection for SQL errors”    author: “Federico Dotta”    tags: “SQL injection”, “passive”, “SQL”

注意language目前必须是v2-beta。然后写given response then,因为我们只关心响应。

given response then

   if {to_lower(latest.response.body)} matches “mysql|mariadb|sqlite|mssql|db2|pgsql|sql” then

       report issue:            name: “SQL exception – Potential SQL Injection”            severity: info            confidence: tentative            detail: “The response body potentially includes a SQL exception. Check for SQL injections.”            remediation: “Remove verbose errors and apply parameterized query to all SQL queries.”    end if

这里用了to_lower函数把响应体转小写,再用正则匹配。如果命中,就报一个info级别的issue。用内置IDE测试一下:

工作正常。

主动检测:加单引号看反应

被动检测只能等错误出现,主动检测更激进——我们主动发送带payload的请求。这次改成given any insertion point,然后send payload append一个单引号。

metadata:    language: v2-beta    name: “SQL Injection”    description: “Active detection of SQL Injection”    author: “Federico Dotta”    tags: “SQL injection”, “SQL”

given any insertion point then

   send payload:        appending: “‘”

       if {to_lower(latest.response.body)} matches “mysql|mariadb|sqlite|mssql|db2|pgsql|sql” then

           report issue:                name: “SQL Injection”                severity: high                confidence: tentative                detail: “The parameter seems to be vulnerable to SQL Injection”                remediation: “Apply parameterized query to all SQL queries.”        end if

这里注意:我们用了latest.response.body,因为新发了一个请求。base.response.body是原始响应的结果。如果扫到关键字就报high级别的issue。

能跑。

减少误报:用两个单引号做二次验证

上面那个规则误报率可能有点高——如果服务器本来就有“sql”这种单词在正常响应里,就会误报。我个人做渗透测试时,宁可多出几个假阳性,也不想漏掉任何一个漏洞。但有些场景下(比如自动化CI/CD管道),假阳性多了就烦了。所以可以优化一下:先发一个单引号,如果关键字命中,再发两个单引号。两个单引号在SQL里是转义后的单个引号,不会引发错误。如果第二次响应里没有关键字,那就更可能是真的SQL注入。

metadata:    language: v2-beta    name: “SQL Injection (less FP)”    description: “Active detection of SQL Injection with less false positives”    author: “Federico Dotta”    tags: “SQL injection”, “SQL”

given any insertion point then

   send payload:        appending: “‘”

       if {to_lower(latest.response.body)} matches “mysql|mariadb|sqlite|mssql|db2|pssql|sql” then

           send payload:            appending: “””

           if not({to_lower(latest.response.body)} matches “mysql|mariadb|sqlite|mssql|db2|pssql|sql”) then

               report issue:                    name: “SQL Injection (less FP)”                    severity: high                    confidence: firm                    detail: “The parameter seems to be vulnerable to SQL Injection”                    remediation: “Apply parameterized query to all SQL queries.”            end if        end if

这里用了not函数反转条件。如果单引号触发关键字,而双引号不触发,就报issue,confidence升级为firm。

盲SQL注入检测:布尔盲注

布尔盲注的关键是构造两个条件:一个永远为真,一个永远为假。通过比较响应体是否一致来判断。BCheck里可以用define块定义变量,避免硬编码。

metadata:    language: v2-beta    name: “Blind SQL Injection”    description: “Active detection of blind SQL Injection”    author: “Federico Dotta”    tags: “SQL injection”, “blind”, “SQL”

define:    blind_payload_true = “‘ AND ‘534’=’534”    blind_payload_false = “‘ AND ‘534’=’535”

given any insertion point then

   send payload called positive:        appending: {blind_payload_true}

   if {base.response.body} is {positive.response.body} then

       send payload called negative:            appending: {blind_payload_false}

       if not({positive.response.body} is {negative.response.body}) then

           report issue:                name: “SQL Injection”                severity: high                confidence: firm                detail: “The parameter seems to be vulnerable to SQL Injection (blind boolean based)”                remediation: “Apply parameterized query to all SQL queries.”        end if    end if

这里用了send payload called给请求命名,方便后续比较。先发真条件,如果响应体和原始响应一样(说明真条件没破坏原有数据),再发假条件。如果假条件和真条件响应不一样,就报漏洞。注意:这个规则只适用于字符串类型的注入点,如果参数是数字,需要去掉单引号。

SSRF检测:用Collaborator捕获外联

最后玩个高级的——检测SSRF。先改一下Flask后端,加一个url参数,如果传了url,服务端会请求那个URL。

import flask from flask import request import sqlite3 import socket import requests

app = flask.Flask(__name__)

@app.route(‘/’, methods=[‘GET’]) def handle_request():    name = request.args.get(‘name’)    url = request.args.get(‘url’)    if name:        …    else:        if url:            r = requests.get(url = url)            return r.text        else:            return “Missing parameters”;

app.run(host=”127.0.0.1″, port=5000, debug=True)

手动测试一下:从Burp的Collaborator标签生成一个地址,贴进去。

果然收到了交互。现在写BCheck:用generate_collaborator_address()生成地址,替换掉参数值,然后检查是否有HTTP交互。

metadata:    language: v2-beta    name: “SSRF”    description: “Active detection of SSRF with Collaborator”    author: “Federico Dotta”    tags: “SSRF”, “Collaborator”, “External interaction”

given any insertion point then

   send payload:        replacing: http://{generate\_collaborator\_address()}

       if http interactions then

           report issue:                name: “SSRF (HTTP interaction)”                severity: high                confidence: firm                detail: “The parameter is vulnerable to SSRF. An HTTP interaction has been received.”                remediation: “Avoid contacting arbitrary URL supplied by user”        end if

注意两点:用反引号拼接字符串,用generator_collaborator_address()。send payload用了replacing,因为要替换掉原参数值,而不是追加。然后检查http interactions条件。

效果不错。但有些场景下出站HTTP被防火墙拦截,只有DNS能出去。所以可以改进一下:先检查HTTP交互,如果没有,再检查DNS交互,降低漏洞等级。

metadata:    language: v2-beta    name: “SSRF (improved)”    description: “Active detection of SSRF with Collaborator”    author: “Federico Dotta”    tags: “SSRF”, “Collaborator”, “External interaction”

given any insertion point then

   send payload:        replacing: http://{generate\_collaborator\_address()}

       if http interactions then

           report issue:                name: “SSRF”                severity: high                confidence: firm                detail: “The parameter is vulnerable to SSRF. An HTTP interaction has been received.”                remediation: “Avoid contacting arbitrary URL supplied by user”        else if dns interactions then

           report issue:                name: “SSRF”                severity: medium                confidence: firm                detail: “The parameter may be vulnerable to SSRF. Only DNS interaction has been received, maybe for egress filtering.”                remediation: “Avoid contacting arbitrary URL supplied by user”        end if

这样如果只有DNS交互,报medium级别,提醒可能被出站过滤了。

测试小技巧:用Burp Scanner单独跑BCheck

用内置IDE的“Run test”每次只能测试一个插入点,效率低。更聪明的方法是:在Burp Scanner里创建一个只跑BCheck的扫描配置,然后用Intruder的“Scan defined insertion point”功能只扫单个参数。参考Part 6里讲过这种方法。

渗透测试时也可以直接用这个配置扫全站,只跑BCheck规则,比完整的Burp扫描快很多。

总结

BChecks确实很香——写几行就能加一个扫描规则,适合那些简单的、基于字符串匹配或请求/响应对比的检测。但别指望它能替代完整扩展,它拿不到响应时间、操作不了字节数组,复杂逻辑还得老老实实写Java代码。

强烈建议去GitHub仓库看看社区贡献的BChecks,很多针对已知CVE的规则,Burp自带的主动检查里没有这些。

所有后端代码和插件代码都在我的GitHub仓库里:https://github.com/federicodotta/Burp-Suite-Extender-Montoya-Course。


参考资料

[1] https://hnsecurity.it/blog/extending-burp-suite-for-fun-and-profit-the-montoya-way-part-8/


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:幻泉之洲 《扩展Burp Suite的乐趣与收益——Montoya方式——第8部分:BChecks——快速扩展Active和Passive Scanner》

评论:0   参与:  0