☰
基于Burpsuite的越权与未授权漏洞自动化检测插件实战解析
2026/10/20 22:10:26 网站建设 项目流程

做安全测试的兄弟应该都有过这种体验:测一个业务站点,光越权漏洞就得手工注册两个账号来回切、改ID、比对返回包,翻来覆去折腾半天,最后还不一定把接口覆盖全。未授权漏洞也一样,一个个接口去试,全靠手工点,脑子稍微一乱,要么漏掉要么重复。我当年在测试一个后台管理系统的时候,因为接口太多,手工测越权测到凌晨,结果第二天复盘才发现漏掉了两个风险点。也就是那时候下定决心,必须搞一个能自动干这活的Burpsuite插件。

陆陆续续写了不少版本,最近把它更新到了适配新版Burpsuite的状态,顺手把一些积累了挺久的想法也加了进去。这篇文章就把这款自动化检测越权、未授权漏洞的插件全貌拆开聊一聊,包括设计思路、核心实现、使用教程和踩坑记录,给需要做这类检测的朋友一个参考。

1. 越权和未授权漏洞为什么会成为测试重点

1.1 两种漏洞的定义和区别

先说清楚一个容易混淆的点。越权漏洞指的是:一个已经登录的普通用户,通过修改请求参数、修改请求地址等手段,访问到了本不该有权限访问的数据或功能。比如把购物订单号换掉,查看别人的订单详情,这种属于水平越权;普通用户通过构造请求调用了管理员的删除接口,这种属于垂直越权。

未授权漏洞则不一样。它指的是:完全不需要登录,或者绕过登录校验,就能直接访问到后台接口、敏感接口。最典型的就是管理后台的API接口没有任何鉴权中间件,直接裸奔在公网上,任何人拿个Http请求工具就能调。

很多人把这两个混为一谈,但检测思路差别挺大的。越权检测的关键在于"身份切换后的访问结果对比",而未授权检测的关键在于"未携带身份信息时能否直接拿到有效响应"。所以插件必须把这两套逻辑分开设计。

1.2 它们为什么容易出现在实际业务中

实战中碰到最多的两个场景,一是前后端分离项目,前端只做了按钮隐藏,没有真正做权限控制;二是接口文档管理混乱,内网接口忘了加权限校验就部署到了生产环境。尤其是现在微服务架构流行,一个网关后面挂几十个服务,权限校验经常出现漏配的情况。

我在测试一个跨平台系统(某企业内部的OA系统,这里就不提具体名字了)的时候就发现,他们的用户信息查询接口完全没有在网关层做鉴权,任何人只要知道接口路径,直接GET请求就能拉回一批用户手机号。这种问题光靠人工测试,如果不知道路径就测不出来,但有了自动化插件,只要从历史请求里把路径捞出来,再逐个去掉身份信息重放,很快就能暴露。

1.3 手工测试的难点在哪里

手工测越权的痛点其实就三个:第一个是账号切换成本高,尤其遇到短信验证码登录的系统,每注册一个测试账号都要收一次码,来回倒腾非常崩溃;第二个是请求量太大,一个接口可能要测好几个ID、好几种角色,单靠人在Burp里手动改包根本点不过来;第三个是响应比对靠肉眼,两个返回包若是只有某个字段不同,肉眼很容易漏判。

所以做这个插件的核心目标很明确:把"登录两个账号"变成"自动切换身份",把"肉眼比对响应"变成"算法算相似度",把"一个个试接口"变成"批量重放所有接口"。这个思路就是整个插件的灵魂。

2. 插件整体设计思路

2.1 先确定功能边界

写工具最怕的就是什么都想塞进去。最开始我想把更多检测能力都塞进这个插件里,比如SQL注入检测、XSS检测,但后来发现这样一来插件会变得特别臃肿,而且不好维护。最后我砍掉了所有其他漏洞检测的模块,只保留两个核心功能:越权检测和未授权检测。

明确了边界之后,整个插件的架构其实就清晰了。它需要做的只有三件事:收集流量、修改请求并重放、对比响应判断漏洞。收集流量这个动作依靠Burpsuite的代理日志来获取,插件只需要把用户标记过的请求存起来就行。修改请求和重放是整个插件的核心工作,需要设计好改包的逻辑。响应对比则需要选择合适的算法。

2.2 核心模块划分

插件的功能结构我分成了五个模块。

第一个是流量收集模块,负责把经过Burp代理的请求按照用户指定的作用域过滤出来,同时去掉一些明显不需要测的静态资源请求,比如图片、CSS、JS文件。第二个是策略配置模块,用户在这里配置测试账号、目标接口、请求头的处理规则等等。第三个是重放引擎模块,这是最重要的模块,它负责根据策略生成新的请求,用当前登录的Session发起重放。第四个是响应分析模块,负责对比原始请求和重放请求的响应结果。第五个是报告生成模块,把检测结果整理成表格,方便导出。

这五个模块之间互相独立,通过接口通信。这样的好处是,如果我想优化某个部分,不用把整个插件重写一遍。

2.3 为什么选择基于Burp扩展API开发

其实在做这个插件之前,我也想过用别的方案,比如直接用Python写一个独立的扫描器。但仔细一想,独立扫描器需要自己去处理代理、抓包、Session管理这一堆破事,开发成本太高了。而Burpsuite本身已经解决了流量获取和中间人代理的问题,我只需要把精力放在请求分析和改包重放上,效率完全不同。

另外还有一个重要的原因,Burpsuite的扩展API里自带了Session处理机制和Cookies管理,这意味着我可以直接复用Burp的会话能力,不用自己去写登录态的获取和维持代码。这对一个个人开发者来说,省下的工作量不是一点半点。

新版Burpsuite的扩展API也做了不少调整,比如Montoya API的要理清楚了。老版的IBurpExtender接口虽然还能用,但官方已经越来越不推荐了,所以我这次更新就是把这套旧的API全部换掉,这在后面我会细说。

3. 核心逻辑实现细节

3.1 请求拦截与流量标记

插件的入口是Burp的HTTP处理器(HttpHandler)。所有经过代理的请求,都会被插件拦截到。但我不会对每一个请求都做处理,那样性能会崩。我会先做一个筛选:只处理用户配置的作用域内的请求,并且Content-Type是JSON、表单、XML这类业务请求的才进入后续流程。

筛选通过之后,请求会进入一个滑动窗口缓存。我维护了一个请求队列,每个请求记录下完整的URL、请求方法、请求头和请求体,方便后续修改重放。同时,在Burp的UI面板上,我会给这些请求加一个高亮标记,打上"Potential"标签,方便用户在中转过程中直观地看到哪些请求已经被缓存。

有几个细节要特别注意:第一,HTTPS请求一定要能正常处理,证书信任问题要提前配好;第二,文件上传接口不要进重放池,因为重放文件上传请求可能会产生一堆垃圾文件;第三,带Token的请求要把Token从请求头里剥离,否则后续重放时可能会被服务端拒绝。这些都是我在实际测试中踩过的坑。

3.2 水平越权测试逻辑

水平越权的检测逻辑是插件最核心的部分。我这里的方法是"两账号比对法":用户需要至少配置两个测试账号(A账号和B账号)。首先用A账号正常访问目标接口,拿到一个基准响应;然后用A账号的Session去重放这个请求,但把请求中与用户身份相关的参数替换成B账号的资源ID;最后对比两次响应。

什么是"用户身份相关的参数"?这里我用了一套基于规则的提取方式。优先从路径中提取,比如/api/user/{id}/info这种RESTful风格的接口,路径参数就是身份标识。其次从查询参数中提取,比如?userId=123。再就是请求体中的字段,比如JSON里的owner_id。用户可以在插件界面上手动指定要替换的参数名,也可以让我自动提取。

替换逻辑说穿了很简单:把原始请求中的那个ID值,替换成另外一个账号的资源ID。但难点在于如何构造第二个账号的资源ID。我是这样做的:先用B账号登录,然后让插件自动请求一个配置好的"个人信息接口",把B账号的资源ID从响应中提取出来,存到内存里。替换的时候就拿这个ID去换A请求里的ID。

响应对比用了两部分:状态码和响应体。如果状态码相同,响应体也长得差不多,那基本可以判断存在水平越权。但如果状态码变化明显,或者响应体出现了"无权限"之类的字眼,那就说明没有越权。

3.3 垂直越权测试逻辑

垂直越权的逻辑和水平越权有点不一样。垂直越权关注的是低权限用户能不能调用高权限接口。所以我会让用户配置两个角色账号,一般是一个普通用户和一个管理员。然后用普通用户的Session去重放管理员的请求,看能不能成功。

这里有两种情况需要区分。第一种是接口本身没有做权限控制,普通用户直接访问管理员接口就成功了,这种属于典型的水平权限提升。第二种是接口做了前端控制,但后端没有校验,这种情况往往请求还能通,但返回数据不完整,或者某些字段为空。我通过检测返回体中的字段数量差异来辅助判断,如果返回体的JSON字段数比预期少了很多,会标记为"疑似垂直越权"。

垂直越权检测有个很大的坑在于:管理员接口怎么找?我采用的办法是从流量中智能识别。如果一个请求的URL里包含admin、manage、system、user-management等关键词,我就会把它归入"高权限接口池"。用户也可以手动添加URL前缀来指定哪些接口算高权限接口。

3.4 未授权访问检测逻辑

未授权访问的检测思路相对直接,但仍然需要考虑两个不同的方向。第一个方向是"去认证"重放:取出原始请求,把Cookie头、Authorization头等所有身份凭证信息全部剥掉,直接重放。如果响应里还包含完整的业务数据,那说明接口存在未授权访问。第二个方向是"换无效Token"重放:把Authorization替换成"InvalidToken"之类的占位符,看服务端会不会直接拒绝。如果返回200或者直接返回业务数据,那就说明Token校验形同虚设。

这里有一个关键是:未授权检测不能简单粗暴地把所有请求头都删掉,因为有些接口虽然不做权限校验,但做了CSRF校验或者其他的非身份校验。如果直接把所有头删掉,可能会因为缺少某些必要的头而返回400,造成误报。所以我提供了一个配置项,让用户决定哪些头要保留,哪些头要删除。默认配置是:只删除Cookie和Authorization,保留其他所有的请求头。

未授权访问的响应判定,我采用了一个更保守的策略。只有同时满足以下三个条件,才标记为未授权漏洞:第一,响应状态码与原始请求一致;第二,响应Content-Type是JSON等业务类型;第三,响应体长度大于某个阈值(可配置,默认500字节)。这样做的目的是尽量降低误报率,因为很多登录页本身也会返回一堆HTML代码,但那些不是业务数据。

3.5 响应对比与相似度计算

响应对比是整个检测流程的最后一步,也是最容易出问题的一步。一开始我用了最简单的方案:两个响应体完全一致,就判定为越权。但后来发现这个方案根本不行。因为很多动态接口会在响应中包含时间戳、随机数、当前用户昵称等动态字段,导致服务端正常响应时,两次返回的响应体也会不一样。

后来我换成了基于Token的差异率计算。把两个响应体的文本进行分词,然后计算不同的Token数量占总Token数量的比例。如果差异率低于用户设定的阈值(默认10%),就认为是"基本一致",即存在越权。如果差异率在10%到50%之间,标记为"疑似",需要人工复核。如果差异率超过50%,则认为是不同内容,不存在越权。

这个方法在实际测试中效果还不错。但有一个问题是一些动态字段(如前端的随机ID)会导致差异率虚高。所以我加了一个"忽略字段"的功能。用户可以把动态字段名加进去,插件在对比时会把这些字段的值统一替换成固定占位符再进行Token比较。

如果你对算法有更好的想法,比如用SimHash或者向量化相似度,我觉得也是完全可以的。对于个人插件而言,这个基于Token差异率的方法已经能覆盖绝大多数场景了。

4. 使用教程与配置参数

4.1 安装与环境要求

新版本插件基于最新的Burp Montoya API开发,所以需要较新版本的Burpsuite才能跑起来。建议使用官方最新版。开发语言是Java,你需要确保本地有Java 17以上环境,不然插件在加载阶段就会报ClassNotFoundException。

安装过程非常简单:打开Burp -> Extensions -> Add -> 选择插件Jar包 -> Next。但要注意,插件加载后会自动创建一个新的Tab页,如果Burp界面没看到这个Tab,说明加载失败了,可以去Errors面板看报错信息。常见的原因是JDK版本不兼容以及Jar包缺依赖。我这次更新把依赖都打进了Fat Jar里,所以一般情况下不需要额外装依赖。

插件本身没有独立的下载热门链接,因为直接把下载地址贴出来很容易被滥用。我建议你在自己用的代码托管平台里搜插件名称,找发布版本的Release页面去下载。或者从源码自己编译,也就一条命令的事。

4.2 策略配置说明

插件的配置界面设计得比较简洁。主界面上有几个核心配置项:

  • 作用域(Scope):限定插件只处理哪些域名,支持通配符。
  • 检测类型:勾选要执行的检测,可以单选或者全选。
  • 越权测试账号:配置A账号和B账号的登录入口以及身份标识参数。
  • 未授权检测配置:选择要剥离的请求头,默认剥离Cookie和Authorization。
  • 响应判断阈值:差异率阈值、最小响应长度阈值。
  • 忽略字段:填写需要忽略的动态字段名,多个用逗号分隔。

这里特别强调一下账号配置。插件本身不负责登录,你需要先在Burp里用A账号登录目标系统,捕获登录后的请求,然后右键发送到插件,插件会自动提取当前的Cookie和Session标识,保存为"A账号Session"。然后你再退出登录,切B账号登录,同样操作,保存为"B账号Session"。之后插件在检测时就会自动切换这两个Session。

4.3 实操流程演示

我举个实际例子,假设现在要对一个模拟业务系统(某跨平台系统的订单管理模块)做越权检测。

第一步,设置Scope为example.com,检测类型勾选"水平越权+垂直越权+未授权访问"。

第二步,在Burp代理中正常操作A账号,浏览订单列表、查看订单详情、修改个人资料等,让插件缓存一批请求。这里要注意,操作覆盖面尽量广,把带ID参数的接口多触发几个。

第三步,切换到B账号,在插件配置页里绑定B账号Session,然后在"越权测试"页面点击"开始检测"。插件会自动遍历所有缓存的请求,找到带身份参数的接口,用B账号的资源ID替换,并用A账号的Session重放。

第四步,等待跑完,看结果列表。插件会把每个检测项标记为"存在越权"、"疑似存在"或"未发现"。点击每一项可以看到原始请求、重放请求和响应差异率的详情。

第五步,对于标记为"存在"的项,我建议你在Burp的Repeater里手动复测一遍,确认一下是否真的可以利用。自动化工具的作用是辅助你定位可能的问题,最终的验证一定不能省。

4.4 结果解读与报告输出

检测结果的展示我做了分类和统计。除了列表之外,还会生成一个简单的统计面板,列出总共检测了多少个接口、发现多少高危、多少中危、多少疑似。报告可以导出成Markdown或者CSV格式,方便直接贴进测试报告。

我建议你按风险等级来处理:高危的是那种响应体完全一致且包含完整业务数据的越权或未授权访问,这种必须当天就提到缺陷系统里;中危的是响应有一定差异但能访问到核心字段的,需要进一步人工验证;低危和疑似可以攒起来,等下一次测试的时候一起复测。

结果解读这块有一个很重要的原则:漏洞判断要结合业务上下文。比如某些接口虽然没做权限控制,但返回的数据本身就是公开信息,那就算不上漏洞。所以插件的判定只能作为参考,真正定性一定需要人工结合业务场景来判断。

5. 新版本更新内容与优化

5.1 适配新版API

这次更新最大的变化,就是彻底从老的IBurpExtender接口迁移到了Montoya API。老接口在最新版Burp上已经不能使用了,而且官方也不太可能再做长期维护。Montoya API的设计更现代,接口划分更清晰,尤其在HTTP处理这块,提供了更灵活的请求编辑能力。

迁移过程其实挺痛苦的,不少接口的调用方式变了。比如老的IExtensionHelpers变成了HttpService和RequestResponse的组合,请求的修改也从字符串拼接变成了HttpRequest对象层面的操作。这让我重写了不少代码。不过换来的好处也很明显:插件的稳定性和性能都提升了,尤其是在处理HTTPS并发请求时,明显感觉更顺畅。

5.2 检测逻辑增强

新版增加了两个比较实用的功能。第一个是"级联ID提取",针对那种资源ID不是一个而是多个参数的情况,比如订单接口同时包含orderId和subOrderId,插件会同时提取和替换,而不是只处理第一个匹配项。第二个是"动态路径感知",针对路径参数,不再是死板地把路径里的数字全换掉,而会结合参数名来判断哪些数字更像资源ID。

另外,新版还优化了未授权检测的判定逻辑。老版本经常会把返回登录页误判为未授权访问,因为登录页状态码也是200。这次我增加了内容指纹库,把常见的登录页关键字(如login、password、验证码等)单独过滤掉,误报率降了一半还不止。

5.3 性能与稳定性优化

性能方面,之前老版本跑100个接口的检测可能要五分钟,现在做了并发控制,把线程数调到默认8,并且设置了每个接口的超时时间(默认10秒),整个流程跑下来两三分钟就搞定了。同时,缓存了一些DNS解析结果,避免了频繁重复DNS查询带来的延迟。

稳定性方面,加了三个之前没考虑到的细节:第一是内存保护,请求缓存设置了最大条数,超出上限会自动丢弃最旧的请求,防止跑测试的时候Burp内存爆炸;第二是异常重试机制,网络超时或者连接重置时自动重试一次,避免因为临时网络抖动产生误报;第三是日志系统,所有插件的关键操作都记录到文件,方便排查问题。

5.4 后续规划

接下来我打算给插件加一个"批量Target"支持,也就是同时检测多个域名,而不是只限定一个Scope。另外,还想加入对WebSocket接口的越权检测支持,目前市面上对WebSocket的越权检测工具比较少,这个方向也是不少朋友私下问过我的。

说实话,做一个自己够用的插件和做一个能让别人也顺手用的插件,完全是两码事。后面我会继续维护,如果有新的想法或者大家有需求,也会持续更新下去。

6. 常见问题与排查技巧

6.1 插件加载失败的常见原因

加载失败是最常见的问题。如果你在Extensions面板里看到插件报错,我建议按这个顺序排查:

  • 确认Burp版本是否够新,Montoya API需要较新的版本。
  • 确认本地JDK版本,Java 17以下会直接加载不了。
  • 看Error面板的最新报错,如果是ClassNotFoundException,大概率是依赖没有打包全;如果是UnsupportedClassVersionError,就是JDK版本问题。
  • 把插件Jar包下载完整,不要用不稳定的网盘文件,最好是从源码仓库的Release页面下载。

6.2 检测结果大量误报的原因和对策

误报率高的原因,我总结了四种:第一种,响应体里有大量动态字段,比如时间戳、随机数、当前用户ID,导致相似度计算不准。这种情况就把这些字段名加入到"忽略字段"里,重新检测。第二种,接口本身返回的是固定页面(比如统一异常页面),不管有没有权限返回的内容都一样,插件就会误判为越权。需要你把统一异常页面的特征加到过滤规则里。第三种,账户配置有问题,B账号和A账号的身份标识没有正确提取,导致替换的时候替换了不相关的内容。第四种,请求头里除了Cookie和Authorization还有其他的身份标识参数,比如自定义的X-Token,需要在配置里额外指定。

如果你遇到的是漏报而不是误报,常见原因则是:接口的身份参数比较隐蔽,比如藏在路径里的UUID,插件可能没有识别出来需要替换的参数名,这时候需要你在配置里手动添加身份参数名。

6.3 检测速度慢怎么优化

如果检测速度太慢,优先做三件事:第一,把并发线程数调到16或者更高(前提是你的带宽和服务端扛得住);第二,把超时时间从10秒调低到5秒,太慢的接口直接跳过;第三,减少Scope里的访问量,只保留真正需要检测的接口,别把所有静态资源都带着。

另外,如果检测过程中Burp的CPU占用率居高不下,通常是响应体太大导致的。可以加一个"最大响应体大小"的限制,超过比如1MB的响应直接不参与比对,这个问题会缓解很多。

6.4 说一句掏心窝的话

写了这个插件之后,我自己最直观的感受是:测越权和未授权漏洞的效率至少翻了三倍。以前一个项目要花一整天手工测,现在插件先粗筛一轮,把明显有问题的标出来,我再针对性地做人工复验,半天基本就够了。而且因为覆盖范围广,漏测的概率也小了不少。

不过我也想给用这个插件的朋友提个醒:自动化工具做得再好,也只是辅助。越权漏洞的最终确认,一定要靠人去理解业务上下文。你调通的接口到底是不是越权,得看这个资源到底应不应该被当前身份访问。这个判断,目前没有任何工具能完全替代人去完成。

最后再分享一个小技巧:在做大规模检测之前,先用两三个接口跑一次小测试,确认插件行为符合预期,再全量铺开。这样既不用反复修改配置,也不用担心因为配置问题导致大量漏报的情况。这个习惯我保持了挺久,实测下来能省很多事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询