十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ffuf 实战指南:从目录扫描到 Web 内容发现的高效模糊测试

ffuf 实战指南:从目录扫描到 Web 内容发现的高效模糊测试 说到Kali里的内容发现我目前最常用的工具就是ffuf。第一次见这名字我觉得挺怪Fuzz Faster U Fool——官方解释是Fuzz快到让你怀疑人生语气很狂但用下来它确实配得上。ffuf 是一款用 Go 编写的 Web 模糊测试工具也就是很多人挂在嘴边的爆破指令里负责爆破的那一环专门用来做目录枚举、文件发现、参数探测、子域名枚举这些事。它解决什么问题一句话当你只知道目标站点的入口 URL想知道后台在哪、备份文件在哪、还有哪些隐藏接口时ffuf 就是最快帮你把这些问题扫出答案的工具。这篇文章适合两类人一是刚接触 Kali、想搞懂目录爆破指令怎么用的新手二是一直在用 dirsearch 或 gobuster、但觉得速度和灵活性差口气的进阶用户。我最初接触 ffuf 是在一次授权测试里目标站目录特别深dirsearch 跑到一半被卡住换 ffuf 之后扫描速度直接上了一个量级从那以后它就进了我的常驻工具箱。下面我会按理解原理 - 搞懂参数 - 实际场景 - 排查问题这条线来写尽量把每一步为什么这么做都说清楚而不是丢一堆命令让你照抄了事。1. ffuf 是什么为什么它值得你认真学1.1 一个被名字耽误的 Web 模糊测试神器很多人第一次看到 ffuf 都以为它是某个加密工具或者破解工具其实它的全称是 Fuzz Faster U Fool核心就一个词Fuzz。模糊测试Fuzzing最早是软件测试里的概念指的是向程序输入大量随机或半随机的数据观察它会不会出错、会不会暴露异常行为。ffuf 把这一套思路搬到了 Web 应用测试上但它的输入不是纯随机垃圾数据而是字典 占位符。你可以把 ffuf 理解成一台自动投喂机你给它一个字典文件、一个 URL 模板它就不停地把字典里的内容替换到 URL 模板里然后发送 HTTP 请求再把响应结果按照状态码、响应大小、关键字等条件筛选出来。这就是中文社区常说的爆破指令的运作逻辑。和纯粹暴力破解密码不同ffuf 的爆破对象是路径、参数、域名这些结构化的信息所以更准确的说法是内容发现。我在实际使用中觉得ffuf 最值得学的点不是它能跑多快而是它的灵活性。它默认就支持多字典交叉组合、请求头自定义、POST 数据注入、递归扫描、自动结果过滤这些功能在原生命令行工具里很少能一次给齐。也就是说你学会 ffuf 之后很多以前需要组合多个工具才能完成的任务现在一条命令就能搞定。1.2 它和目录扫描有什么区别先解决名词混乱在 Kali 相关的中文教程里爆破目录扫描目录枚举内容发现这几个词经常混着用新手很容易被绕晕。我按自己的理解帮你理一下。目录扫描通常指用字典请求网站域名/字典词看哪些路径能返回正常响应。这是最基础的操作gobuster 的 dir 模式、dirsearch 干的就是这件事。内容发现范围更广除了目录还包括文件、子域名、虚拟主机、参数名、API 接口等一切隐藏资源。爆破/模糊测试这是一个方法论不局限于 Web。在 Web 安全的语境下就是用字典批量发请求观察响应差异。ffuf 其实是把暴力遍历和灵活匹配结合得最好的工具。它不是简单地把字典拼到 URL 后面而是允许你在 URL 的任意位置放一个占位符 FUZZ。你可以把 FUZZ 放在域名位置扫子域名放在路径位置扫目录放在参数值位置测参数放在 Cookie 位置测会话甚至可以同时放多个 FUZZ 做组合测试。理解了这一点你就能明白为什么它不是普通目录扫描器能替代的。1.3 ffuf vs gobuster vs dirsearch怎么选我在实战里三个工具都用过见仁见智但对比之后你会发现它们各有侧重。下面这个表是我自己的使用感受整理出来的给大家做个参考。工具语言主要用途速度感受灵活性最适合的场景ffufGo目录、参数、子域名、虚拟主机等全面模糊测试很快并发控制细极高双字典模式很实用需要精细控制匹配规则、多场景复用的测试gobusterGo目录、DNS 子域名、虚拟主机快中参数相对少快速粗扫一条命令跑完dirsearchPython目录和文件扫描中等取决于线程中支持递归和排除扩展名默认规则友好适合新手我的建议是如果你只想要一个点到为止的结果gobuster 就够如果习惯了 dirsearch 的输出格式继续用也没问题但如果你从事授权测试的频率不低或者在 CTF 里经常需要在短时间内把目标 Web 应用的隐藏接口摸清楚那我强烈建议把 ffuf 作为主工具。Go 编译的静态二进制文件决定了它在高并发下的表现比 Python 工具更稳而且 ffuf 没有一堆依赖要装丢到任意 Linux 机器上就能跑。2. 从 0 开始Kali 里的安装与基础参数2.1 三条命令完成安装以及验证Kali 默认源里已经带了 ffuf所以最省事的方式是直接 apt 安装。不过有一点要提醒如果你刚装完 Kali第一步最好先更新一下软件源列表不然 apt 可能找不到最新版本甚至因为源的问题导致安装失败。sudo apt update sudo apt install ffuf -y装完之后验证一下版本ffuf -V能输出版本号就说明环境没问题。如果你用的不是 Kali或者想在 Docker 里快速体验也可以用官方 GitHub 的 release 包wget https://github.com/ffuf/ffuf/releases/latest/download/ffuf_2.1.0_linux_amd64.tar.gz tar -xzf ffuf_2.1.0_linux_amd64.tar.gz sudo mv ffuf /usr/local/bin/关于 Kali 系统本身我多说一句。很多新手喜欢直接在 root 用户下操作这没问题但 ffuf 扫描生成的临时文件、输出文件建议统一放在一个工作目录里比如~/ffuf-work方便过滤结果的时候做二次整理。如果你发现 Kali 的中文字体显示有问题、或者桌面环境卡顿这些都不会影响 ffuf 的命令行使用不用过分纠结图形界面。2.2 十个高频参数先记这些就够了ffuf 的参数非常多全部背下来没有必要但下面这 10 个参数是你跑通第一次扫描就必须掌握的。参数作用示例-w指定字典文件可用:关键字自定义占位符-w dir.txt:FUZZ-u请求的 URL 模板关键位置用 FUZZ 占位-u http://target/FUZZ-mc匹配状态码默认是 200,204,301,302,307,401,403-mc 200,301-fc过滤状态码-fc 404-fs过滤响应大小字节排干扰神器-fs 12345-fw过滤响应单词数-fw 128-t并发线程数-t 80-rate每秒最大请求数限制速度防止被限制-rate 200-recursion对发现的目录继续递归扫描-recursion-o输出结果到文件建议配-of指定格式-o result.json -of json这里重点讲一下-w参数里的自定义关键字。默认情况下ffuf 把字典内容替换到 URL 中所有出现FUZZ的位置但如果你的任务比较复杂比如要同时遍历用户名和密码字典、并且把它们组合到同一个请求里就需要自定义关键字ffuf -w users.txt:USER -w pass.txt:PASS -u http://target/login -X POST -d usernameUSERpasswordPASS -fc 401两个字典分别绑定USER和PASSURL 和 POST 数据里对应位置的占位符就都会被替换。这是 ffuf 比很多目录扫描器高级的地方也是它值得花时间学的核心原因之一。2.3 一条标准命令长什么样输出怎么读刚开始不要追求花哨先跑通一条最基础的命令ffuf -w /usr/share/wordlists/dirb/common.txt:FUZZ -u http://192.168.1.100/FUZZ -mc 200,204,301,302,307,401,403 -t 50这条命令的含义是用 dirb 自带的 common 字典请求目标站点下的每一个路径只要响应状态码落在常见有效范围内就显示出来。跑完之后你会看到类似下面的输出[Status: 200, Size: 11321, Words: 3435, Lines: 211, Duration: 62ms] * FUZZ: index.php每一行对应一个有效结果Status是 HTTP 状态码Size是响应体大小Words是单词数Lines是行数。这些指标不只是好看后面做过滤全靠它们。我建议把第一次扫描的目标设为自己的本地靶场或者 DVWA 这类环境不要直接对公网站点动手。Kali 下搭建 DVWA 靶场用 Docker 非常方便一条docker run就能起来。先把规则和输出看明白再谈实战。3. 实操环节用 ffuf 完成真实场景下的内容发现3.1 场景一目录发现——用最小的配置跑通第一次这是 ffuf 最常见的用法。假设你在授权测试中接手了一个内网测试目标已经确认了 Web 站点根路径现在要快速摸清楚它有哪些隐藏目录。先看一下 Kali 自带字典有哪些ls -lh /usr/share/wordlists/dirb/common.txt大概几千条适合快速验证big.txt更大更全适合对速度要求不高但对覆盖度有要求的场景还有dirbuster目录下的directory-list-2.3-medium.txt也是老牌字典我经常用。第一步建议先用common.txt跑一遍找找感觉而不是直接上大字典。原因很简单如果目标站的 404 页面固定返回一个特定大小你需要先用小字典快速摸清这个噪音基线后面大字典扫描时才不会被淹没在无关结果里。一个带过滤的完整示例ffuf -w /usr/share/wordlists/dirb/common.txt:FUZZ -u http://192.168.1.100/FUZZ -t 80 -ac -fs 1234这里我用-ac让 ffuf 自动校准它会发一个不存在的路径请求检测目标的 404 响应特征然后自动过滤-fs 1234是我手动指定过滤掉大小为 1234 字节的响应。为什么还要手动指定因为在一些奇奇怪怪的 Web 服务器上-ac校准的规则不一定完美手动加一层过滤相当于双保险。实操心得扫目录时看到301千万别直接忽略它往往意味着一个目录存在且有重定向比如/admin/重定向到登录页。你可以把状态码匹配范围放宽到200,204,301,302,307,401,403然后人工去看Location头。3.2 场景二带上 Cookie 和 Header 的认证态探测实际测试中很多目标站在未登录状态下会统一返回 302 跳转这时候你直接扫目录只会看到一堆重定向根本分不清哪些是真实路径哪些是认证拦截。正确做法是先登录目标应用从浏览器开发工具里复制 Cookie然后把它带进 ffuf 的请求里。ffuf -w /usr/share/wordlists/dirb/big.txt:FUZZ -u http://192.168.1.100/dashboard/FUZZ -H Cookie: PHPSESSID8f4a2b9c3d1e5f6a7b8c9d0e1f2a3b4c -H User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) -mc 200,204,301,302,403 -t 50这里有两个容易踩坑的点第一Cookie 里如果包含特殊字符一定要用双引号把整个值包起来否则 shell 会把分号解释成命令分隔符。第二有些应用对 User-Agent 有校验不认识的头会被直接拦截所以最好在浏览器里把自己的 User-Agent 原样复制过来。我习惯把常用的 User-Agent 和 Cookie 写进一个 environment 变量或者脚本模板里省得每次手动敲。加了 Cookie 之后你会发现原本一堆 302 的结果消失真实的目录结构开始浮现。登录态扫描的价值在于很多后台管理页面的目录在登录前后表现完全不同只有登录后才能看到有效响应。3.3 场景三POST 请求下的参数 Fuzzffuf 不仅可以扫路径还可以对参数名和参数值做模糊测试。这个场景在测试登录接口、搜索接口、API 接口时非常有用。举个例子你发现目标站有个登录接口POST 参数是用户名和密码但不确定还存在哪些隐藏参数。这个时候可以这样测试参数名ffuf -w /usr/share/wordlists/dirb/common.txt:FUZZ -u http://192.168.1.100/api/login -X POST -d FUZZ1 -H Content-Type: application/x-www-form-urlencoded -fc 400 -fs 0思路是把字典里的词作为参数名提交值为 1如果某个参数名被应用识别响应大概率会从参数错误变成参数值格式错误状态码或响应体大小就会发生变化。-fc 400过滤掉明显是参数缺失导致的 400 错误-fs 0过滤掉空响应。POST 数据里同样可以用自定义关键字做多字段组合。比如你想测用户名枚举可以固定密码遍历用户名ffuf -w users.txt:FUZZ -u http://192.168.1.100/api/login -X POST -d usernameFUZZpasswordadmin123 -H Content-Type: application/x-www-form-urlencoded -fw 56这里-fw 56的作用是把正常用户名不存在的响应过滤掉剩下响应体大小不一样的往往就是用户名存在的提示。注意这种测试在真实环境中一定要有明确的授权不然就是越界行为合规风险极高。3.4 场景四从域名到子域名和虚拟主机的枚举ffuf 不光可以扫路径还可以用来枚举子域名。原理依然是占位符替换只不过这次 FUZZ 放在域名位置ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://FUZZ.example.com/ -mc 200,204,301,302,403 -t 100这个命令会尝试www.example.com、mail.example.com、dev.example.com等一系列子域名能正常返回的状态码就会被列出来。做子域名枚举时有一个常见问题很多域名有泛解析随便访问一个不存在的子域名也会返回 200 或重定向到一个默认页面导致大量假阳性。解决办法是-ac自动校准或者先手动请求一个随机子域名记录它的响应大小然后用-fs过滤掉。虚拟主机Virtual Host枚举是子域名的变种适用于同一个 IP 上托管了多个域名的情况。这时 FUZZ 放在Host头里ffuf -w vhosts.txt:FUZZ -u http://192.168.1.100/ -H Host: FUZZ.example.com -fs 9856这个技巧在攻防演练里尤其常用因为很多时候从外部扫到的 IP 只有一个但上面绑了好几个应用直接扫 IP 只能看到默认站点用 Host 头枚举才能把后面的虚拟主机逼出来。3.5 场景五递归扫描与扩展名匹配目录扫描的痛点之一是你发现了一个深层目录比如/admin/backup/但字典里没有backup这个词那你可能需要扫描/admin/backup/下的内容。手工一层层扫很麻烦fuff 的递归扫描就是干这个的。最简递归写法ffuf -w /usr/share/wordlists/dirb/common.txt:FUZZ -u http://192.168.1.100/FUZZ -recursion -recursion-depth 2 -mc 200,204,301,302,403 -t 60-recursion打开递归-recursion-depth 2表示发现目录后最多往下一层再递归。这里有个细节我想提醒一下递归扫描会把请求量放大好几倍字典越大越明显。我个人的经验是第一遍用普通模式找出所有目录第二遍针对那些看起来有东西的目录手动开递归不要无脑全局递归否则很容易扫出一大堆.git/index.php这种低价值结果还浪费时间。扩展名匹配也是高频需求。很多站点存在.bak、.old、.swp、.php~这样的编辑器备份文件但字典里只有文件名没有扩展名。ffuf 可以直接加-effuf -w php_common.txt:FUZZ -u http://192.168.1.100/FUZZ -e .php,.bak,.old,.txt,.zip,.sql -mc 200这个组合非常适合找源码备份和配置文件泄露。config.php.bak、db.sql这些文件一旦存在基本就是高危信号。作测试时如果发现这类文件不要直接下载完就了事还应该在授权范围内确认这些文件是否包含数据库连接信息等敏感内容。4. 常见问题与排查技巧实录4.1 常见报错和解决办法速查表ffuf 用多了总会遇到一些奇奇怪怪的报错。下面这张表是我平时遇到最多的问题和对应的解决思路。现象可能原因解决办法unable to open wordlist file字典路径写错或者权限不够先用ls -l确认文件存在再检查当前用户是否有读取权限too many open files线程数太高系统文件描述符不够降低-t线程数或者用ulimit -n临时调高限制扫了半天 0 results过滤器过严或者目标统一返回相同响应去掉-fs/-fw再试或者改用-mc all观察所有响应Invalid method-X后面方法写错了检查大小写POST 就写POST不要写post大量结果全部是 200目标站可能把所有路径统一重写了用-fs过滤掉默认响应大小或者用-ac自动校准子域名扫描全是 200域名做了泛解析手动访问一个随机子域名记录响应大小用-fs过滤或者用-ac提示filter error过滤器参数格式不对检查是不是把-fs 1234写成了-fs 1234,5678但没加引号逗号分隔没问题但空格分隔的值需要加引号请求速度很慢目标服务器响应慢或网络延迟高适当加-t但如果目标有 WAF建议反过来用-rate限制速度4.2 为什么扫出来的结果不靠谱聊聊过滤器的使用我见过太多新手扫完 ffuf 之后把结果一股脑全当成漏洞其实里面混杂了大量假阳性。ffuf 的默认行为是显示所有状态码在匹配范围内的响应但这个匹配只是状态码匹配不代表内容真的有用。举个例子某个站点的 404 页面返回状态码 200那么不管你请求什么不存在的路径结果都会显示 200看起来全是有效目录。这时候就要让-fs出场了。先跑一个随机路径/thisdoesnotexist12345记录响应大小再在正式命令里把它过滤掉。很多情况下还需要同时过滤多个指标比如同样的响应大小但不同单词数可以用-fw辅助。还有一个很容易被忽略的坑CDN 或 WAF 的拦截页面。当你请求频率太高WAF 会返回一个请求太频繁页面状态码可能是 200响应大小也基本固定。这个页面不在你的正常目标范围内如果它混在结果里会严重干扰判断。应对方法很简单一旦感觉结果开始批量出现同一个 Size立刻停下来用-fs把那个大小过滤掉再继续跑。4.3 性能调优与避免被 WAF 限制ffuf 的速度快是把双刃剑。无限制的高并发确实能在几十秒内扫完一个字典但也容易被目标的安全设备识别为恶意流量导致 IP 被临时封禁。我的建议是分几个档次本地靶场、测试环境-t 100起步甚至跑到 200 都没问题求的是速度。内网授权测试-t 50 ~ 80同时加-rate 200避免把内网设备打崩。公网目标授权测试-t 20 ~ 50加-rate 50 ~ 100再配上随机延迟-p 0.05-0.2在隐蔽性和效率之间取个平衡。-rate参数很多人会忽略但它真的能救命。它限制的是每秒请求总数不是单个请求的并发数所以即使你把-t设得很高-rate也能把总流量控制在安全区间内。另外如果目标有严格 WAF建议在 Header 里伪造一个正常的浏览器指纹比如User-Agent、Accept、Accept-Language减少被规则引擎拦截的概率。这不算什么高明技巧但在实战里确实有效。还有一个大家问得比较多的点输出文件格式。ffuf 默认只在终端显示结果但扫描结果多了之后根本看不过来我习惯加一条-o参数把结果存成 JSON再用后面的小脚本提取出状态码和大小ffuf -w dict.txt:FUZZ -u http://target/FUZZ -mc 200,301,403 -o result.json -of json拿到 result.json 之后可以用jq快速筛选出你想看的数据cat result.json | jq .results[] | {status: .status, size: .length, url: .input.FUZZ}这一步不复杂但能帮你从几百条结果里快速定位到真正需要人工验证的路径省下的时间远比输入命令的时间多。4.4 一个我常用的完整工作流示例最后把我平时做授权站点测试时最常用的 ffuf 工作流分享出来你可以照着搭一套自己的模板。第一步先做基础信息收集和授权确认明确目标范围。第二步用小字典快速摸一遍基本情况ffuf -w /usr/share/wordlists/dirb/common.txt:FUZZ -u https://target.com/FUZZ -t 30 -rate 100 -ac -e .php,.bak,.txt -o recon_common.json -of json第三步根据第一步结果对有价值的目录单独开递归扫描ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt:FUZZ -u https://target.com/admin/FUZZ -t 20 -rate 50 -recursion -recursion-depth 1 -fs 1234 -o recon_admin.json -of json第四步如果发现登录接口再用 POST 参数 Fuzz 做一次接口摸底ffuf -w /usr/share/wordlists/dirb/big.txt:FUZZ -u https://target.com/api/login -X POST -d FUZZ1 -H Content-Type: application/x-www-form-urlencoded -fc 400 -fs 0 -t 30 -rate 100这套流程跑下来一个站点的大部分可见和隐藏路径基本都浮出水面了剩下的就是人力排查和验证。跑完记得把结果归档因为后面写报告的时候要用到。我在实际使用中还有一个体会ffuf 跑出来的结果永远只是线索不是结论。路径找到了你得自己去看页面内容、测试接口请求、理解应用逻辑否则扫再快也只是在制造数据垃圾。工具的价值在于把机械化的工作压缩到最短时间省下来的精力应该花在真正需要判断力的地方。
返回列表