spray:下一代目录爆破工具
repo: https://github.com/chainreactors/spray
spray主要为了解决自动有效目录识别, 极限性能, 多目标以及分布式目录爆破中可能会遇到的问题. 并为解决这些问题保留了及其丰富的拓展能力. 提供了一站式的目录爆破/信息收集解决方案.
spray = [feroxbuster(高性能目录爆破)] + [指纹识别] + [httpx(http基本信息解析)] + [dirmap(字典生成)] + 自带的大量目录爆破相关功能
设计理念:尽可能把能自动化的工作都交给工具, 但为所有场景保留可控制的接口.
spray 的总体设计
- 智能化, 目录爆破中 99.9%的尝试都是无效的, 不能让人把精力放在这些无效的数据处理上. 需要找到一个通用的解决方案智能去除无效设计
- 适应性, 每个目标都有着自己的规则, 根据目标去获取信息, 构造字典是智能化的基石. 尽可能的做到根据每个目标构造不同的字典.
- 自动化与分布式, spray 面对的场景包括了大规模高并发的目录探测, 这样的场景并不太适合人工使用 spray, 为此 spray 设计了一些方式来适配这样的场景.
- 辅助性, spary 并不能做到发现漏洞, 但它将尽可能的帮助人类去分析相关的信息.
- spray 基于目录爆破实现, 但目录爆破并不是 spray 的目标.
spray 最终的目标是对单个站点深入的信息分析与提取, 去辅助红队人员进一步的渗透攻击.
智能化
背景
绝大多数目录爆破工具过度简化了现实世界中可能遇到的场景, 导致只能在理想状况下实现过滤无效页面. 当面对复杂的真实场景, 他们的这种方式既会导致误报, 又会导致漏报. 而 spray 要做的是尽可能减少误报与漏报.
这里指的智能化, 实际上是添加复杂的规则, 代替人类进行绝大多数重复无效的劳动. 主要是将我们对目录爆破这个领域的经验转为代码.
spray 的智能判断是我们认为的最佳解决方案, 但不一定是实际上的最佳解决方案. 有可能因为智能判断反而导致了一些漏判误判. 也为此提供了多种补救与缓解方案. 我们也在不断改进我们的逻辑并不断将新的经验沉淀到 spray 的代码中.
在 feroxbuster 与 dirsearch 中, 对有效目录的判断主要通过状态码与 body length. 这样的简单判断在很多场景下是不起作用的. 需要通过手动配置麻烦的filter, 通过人工介入的二次判断. 这种解决方案在单个目标上能通过几次交互修改找到一个特定的配置解决过滤的问题, 操作起来较为麻烦.
如果我们想一次性对多个目标进行扫描, dirsearch 与 feroxbuster 的手动 filter 逻辑将会失效, 不同网站之间完全不能使用同一个 filter 策略. 并且 feroxbuster 采用多进程的方式进行多目标并发, 几乎破坏了它原本非常优雅直观的输出界面. 总而言之, 开源的工具在 filter 上都不够智能.
而 ffuf 与 httpx 更是只用来获取原始数据, 几乎 100%的需要人工介入的方式进行二次数据处理. 它们虽然也提供了各种的 filter 之类的功能, 但在实际使用场景上的定位更接近发包器.
spray 采用的方式是, 获取两个 baseline(index 页面与随机页面)的方式, 动态的根据每个网站自身建立基准值的模型. 然后在后续处理中, 都会根据这两个基准值进行判断. 基本上解决了 90%的场景.
当然现实世界中不会如此简单, 只需要两个 baseline 不可能解决所有的问题, 为了解决后面的 10%的问题以及为了性能上的优化, spray 并设计了一个三段式的过滤逻辑, 每个阶段中都有大量的判断逻辑进行尽可能的智能判断. 具体的逻辑可以文档中的细节看到.
当然三个三段式的逻辑加上 baseline 解决了 99%的问题, 但为了最后的 1%, 设计的 spray 真正最复杂功能.
这些功能包括
- 通过模糊 hash, 对网页相似度进行对比
- 通过模糊状态码进行更进一步的动态 baseline. 即模糊状态码列表中的结果会与相同状态的 baseline 进行对比
- 手动维护的智能过滤状态码列表, 一定程度调整三段式逻辑
- --match与--filter的表达式语言进行手动的规则配置 通过这几个对三段式智能过滤的补充, 我们才确定 spray 有了应对 100%场景的能力 (欢迎找一些奇葩网站提issue).
当使用到 3 和 4 这两个高级功能时, 实际上 spray 就遇到了和 feroxbuster 与 dirsearch 类似的困境, 需要一定程度的人工手动配置了. 当然也不是没有解决办法, 只不过解决方案在 spray 之外, 需要引入更加庞大的分析引擎去实现. 这也是 spray 作为工件的意义所在.
而通过 baseline, 三段式过滤, 以及补充功能的 1 与 2. 在非人工干预的情况下, spray 能覆盖到 99.9%的场景. spray 已经做到了对同类工具的跨越式突破.
无效的 200 页面
这个相对比较好理解, 例如实际上的 404 页面返回 200 状态码. 例如泛解析的目录, 所有页面都返回了 200 状态码.
是在实战中比较多见的情况, 可能针对单一情况其他工具能进行手动配置的过滤, 但是如果一个站有好几种不同的 200 状态码, 过滤起来还是比较麻烦的.
在单一 200 页面的情况下, 假如 200 页面是动态的, spray 也能完美的进行过滤. 但是对于多个泛解析目录同时存在, 且返回的页面都不同. spray 也只能通过手动配置去解决. 相对比其他工具的手足无措已经有了很大进步.
有效的 404 页面
这个情况知道的人可能少一些. 其实也和工具有关, 使用市面上的所有目录爆破工具去 fuzz. 遇到 404 状态码, 都会选择过滤, 使用者根本无法判断有没有可能存在有效的 404 页面. 在真实世界中, 这样的情况在现代化的网站中并不少见.
举个例子, 某个网站给/api配置了泛解析, 但除非访问到/api/getUser是返回 200, 其他页面均为404.
这种情况, 这个/api的路由实际上是有效的, 可以构造字典进行 fuzz, 或者寻找 api 文档进行深度测试.
大部分工具只有/api这个路由被配置为 403 或者 200 的时候才有可能发现. 但在真实世界中, api 通常会被重写其所有的输出, 以保证统一格式为 json 之类的结构化数据. 状态码不再是 http 状态码, 而是 json 中的一个字段.
还有一种情况, 在反代的场景中. 随机目录的 404 页面是由反代服务器返回的. 但当命中的反代的配置, 流量打到某个业务上时, 如果业务的这个目录恰巧返回的时 404, 那么这个 404 页面也是有效的, 而且通常是高价值的.
刚才也提到了, 之所以这种情况少见不是因为它真的少见, 而是所有工具都会忽略这种情况.
在 spray 中, 404 页面将被认为是需要模糊对比的页面. 如果发现的 404 页面与 random baseline 中的页面完全不同, 这个时候就会将其作为有效结果输出.
403/500/503 页面的细节
这三个状态码是很常见的用来处理一些未授权/错误页面的状态码. 它们不同于 404 页面的只可能由中间件与业务提供, 这三个状态码可能是中间件|业务|框架|CDN|WAF. 造成的原因也多种多样, 可能是触发了 WAF 告警, 可能是中间件的统一配置, 可能是业务的错误处理页面, 可能是 Cookie 权限不够, 可能是框架的一些配置.
很多时候会发现/etc/password/*这样的路由都会发现通配符的这个页面. 通配符不再是单一的目录之后的场景, 而是可能在任意位置出现.
面对这种情况, 其他工具能做的也只有手动配置. 如果同时出现了上述多种情况, 手动配置就无能为力了, 只能首尾不顾, 或者选择使用 ffuf 配上一个脚本手动处理数据.
而 spray 实际上能做的也不多, 如果这些特例恰巧对应的不同的状态码, spray 是能通过基于状态码的动态 baseline 去智能过滤的. 但如果这个站的所有特例都是 403 状态码. spray 也只能手动编写一个复杂的表达式去处理. 好在 spray 也不是无能为力.
隐患
对 spray 来说, 智能过滤是最具代表性的智能化. 实际上, spray 在很多其他细节上也有类似的智能设计. 但这是存在隐患的, 过度的智能导致某些东西被隐含了, 除非是这个领域的专家, 否则可能用了几年都理解不了其中的细节.
更多细节参考文档
Features
- 超强的性能, 在本地测试极限性能的场景下, 能超过ffuf与feroxbruster的性能50%以上. 实际情况受到网络的影响, 感受没有这么明确. 但在多目标下可以感受到明显的区别.
- 基于掩码的字典生成
- 基于规则的字典生成
- 动态智能过滤, 自定义过滤策略
- 全量gogo的指纹识别, 全量的fingerprinthub,wappalyzer指纹
- 自定义信息提取, 内置敏感信息提取规则
- 自定义输出格式与内容
- *nix的命令行设计, 轻松与其他工具联动
- 多角度的自动被ban,被waf判断
- 断点续传
QuickStart
基本使用
从字典中读取目录进行爆破
spray -u http://example.com -d wordlist1.txt -d wordlist2.txt
通过掩码生成字典进行爆破
spray -u http://example.com -w "/aaa/bbb{?l#4}/ccc"
通过规则生成字典爆破
规则文件格式参考hashcat的字典生成规则
spray -u http://example.com -r rule.txt -d 1.txt
批量爆破多个目标
spray -l url.txt -r rule.txt -d 1.txt
断点续传
spray --resume stat.json
高级用法
check-only 模式
类似ehole/httpx这类对单页面信息收集的模式. 会有针对性的性能优化. 默认使用templates指纹库. 可以使用--finger
打开第三方指纹库的匹配
spray -l url.txt --check-only
启用拓展指纹识别
会进行主动探测常见的指纹目录, 并额外启用fingerprinthub与wappalyzer拓展指纹库
spray -u http://example.com --finger
启用爬虫
spray -u http://example.com --crawl
扫描备份文件与常见通用文件
spray -u http://example.com --bak --common
启用所有插件
spray -u http://example.com -a
被动url收集
参见: https://github.com/chainreactors/urlfounder
Wiki
详细用法请见wiki
https://chainreactors.github.io/wiki/spray/
Make
git clone --recurse-submodules https://github.com/chainreactors/spray
cd spray
go mod tidy
go generate
go build .
Similar or related works
- ffuf 一款优秀的http fuzz工具, 与spray的功能有一定重合但并不完全相同
- feroxbuster 在编写spray之前我最常使用的目录爆破工具, 但因为批量扫描与过滤配置不便的原因选择自行编写
- dirsearch 较早的目录爆破工具, 参考了部分字典生成与配色
- httpx http信息收集功能, 参考了通过脚本语言编写任意过滤条件的功能
- gobuster 一款统一是go编写的爆破工具, 但不仅限于目录爆破
TODO
- [x] 模糊对比
- [x] 断点续传
- [x] 简易爬虫
- [x] 支持http2
- [ ] auto-tune, 自动调整并发数量
- [x] 可自定义的递归配置
- [x] 参考feroxbuster的
--collect-backups
, 自动爆破有效目录的备份 - [x] 支持socks/http代理, 不建议使用, 优先级较低. 代理的keep-alive会带来严重的性能下降
- [ ] 云函数化, chainreactors工具链的通用分布式解决方案.
Thanks
- fuzzuli 提供了一个备份文件字典生成思路
- fingerprinthub 作为指纹库的补充
- wappalyzer 作为指纹库补充
- dirsearch 提供了默认字典
评论31次
还是xi惯用exe的比较便捷感觉
哈哈 太多一下代扫描器了,不知道用哪个好了都
哪位师傅发表下测试使用报告?
感谢分享
spray -u http://example.com -a 这个是最懒人的使用方法吗
差不多,也可以再配合一下自己的小字典或者通过掩码和规则生成一下
有没有老哥来发表下使用感言?
spray -u http://example.com -a 这个是最懒人的使用方法吗
看着解释感觉蛮强大的,工具库已更新~
这个会先识别指纹,然后扫描指纹的默认路径?
好的 谢谢师傅
字典是不是越大越好?
https://chainreactors.github.io/wiki/spray/start/#_3 可以看下字典生成的逻辑
需要个好字典啊
字典生成可以看这里 https://chainreactors.github.io/wiki/spray/start/#_3
有没有用过的
需要个好字典啊
字典是不是越大越好?
更新了一下,更多细节和优势参考文档 https://chainreactors.github.io/wiki/spray/start
比如什么过滤呢?404,403这种吗?但是这种直接丢的话 会丢掉很多隐藏的口子
不是根据状态码过滤的, 有个挺复杂的过滤算法, 甚至能识别无效404和有效404
真的还是假的 这怎么判断啊 这种不是一般看第一级的目录名 然后靠直觉猜嘛 再拟人的ai也做到呀
看这里 https://chainreactors.github.io/wiki/spray/detail/#_2
Fuff用xi惯了~
比如什么过滤呢?404,403这种吗?但是这种直接丢的话 会丢掉很多隐藏的口子
不是根据状态码过滤的, 有个挺复杂的过滤算法, 甚至能识别无效404和有效404
真的还是假的 这怎么判断啊 这种不是一般看第一级的目录名 然后靠直觉猜嘛 再拟人的ai也做到呀
比如什么过滤呢?404,403这种吗?但是这种直接丢的话 会丢掉很多隐藏的口子
不是根据状态码过滤的, 有个挺复杂的过滤算法, 甚至能识别无效404和有效404