空想网安の乌托邦
首页小说读书项目归档照片墙音乐说说杂谈关于
封面

HTB Academy:使用 Ffuf 攻击 Web 应用

写作时间:2026-09-20 22:54:37
# 网安
# HTB Academy

模块:Attacking Web Applications with Ffuf(13 小节)
核心工具:​ffuf​
目标:发现未公开的目录、页面、扩展名、子域、虚拟主机、参数和参数值。
边界:只对明确授权的域名、主机和 Web 应用进行模糊测试。

​

 

‍Attacking Web Applications with Ffuf 模块封面

​

0. 本章工作流

确认目标可访问
  → 选取合适字典
  → 目录模糊测试
  → 识别技术栈和文件扩展名
  → 页面模糊测试
  → 递归发现深层路径
  → DNS / 子域 / vhost 枚举
  → 校准并过滤噪声
  → GET / POST 参数名枚举
  → 参数值枚举
  → 手工验证所有有效结果

前置知识

  • Linux 命令行。
  • HTTP 请求、响应和状态码。
  • URL、Host Header、GET/POST 参数。
  • DNS、子域与虚拟主机的基本区别。

1. Introduction

手工浏览只能看到页面主动公开的链接,而未链接的后台目录、旧文件、备份、开发接口和隐藏参数往往不会出现在前端。​ffuf​ 将字典中的候选值替换到请求中的指定位置,并通过响应状态码、大小、字数、行数和耗时帮助识别有效结果。

本章主要覆盖:

  • 目录模糊测试。
  • 文件及扩展名模糊测试。
  • 隐藏子域和虚拟主机。
  • GET/POST 参数名。
  • 参数值。

​200​ 通常表示资源成功返回,但不能只依赖状态码;重定向、鉴权页和自定义 404 也可能返回不同或相同的状态码。


2. Web Fuzzing

2.1 首次使用与环境检查

课程环境通常已经安装 ffuf:

ffuf -h
ffuf -V

若系统仓库提供:

sudo apt install ffuf

本章常用 SecLists 字典:

ls /opt/useful/seclists/Discovery/Web-Content/
ls /usr/share/seclists/Discovery/Web-Content/

不同环境中 SecLists 路径可能不同,应先确认实际文件位置。

2.2 基本语法

ffuf -w <WORDLIST> -u 'http://<TARGET>/FUZZ'

​FUZZ​ 是占位符。ffuf 逐行读取字典,把每个候选词替换到 ​FUZZ​ 所在位置。

2.3 常见参数

参数 作用 ​-w​ 指定字典,可给字典设置关键字 ​-u​ 目标 URL ​-H​ 增加请求 Header ​-X​ 指定 HTTP 方法 ​-d​ 请求体数据 ​-b​ Cookie ​-t​ 并发线程数 ​-rate​ 每秒请求上限 ​-timeout​ 请求超时 ​-r​ 跟随重定向 ​-v​ 显示完整 URL 等详细信息 ​-s​ 静默输出 ​-ac​ 自动校准过滤规则 ​-o​ / ​-of​ 输出文件及格式

首次测试应使用合理线程,并先请求一个不存在的随机路径,观察目标对 404 的真实处理方式。


3. Directory Fuzzing

3.1 基本目录枚举

ffuf -w /opt/useful/seclists/Discovery/Web-Content/directory-list-2.3-small.txt \
  -u 'http://<TARGET>/FUZZ'

典型结果:

admin      [Status: 301, Size: ..., Words: ..., Lines: ...]
uploads    [Status: 301, Size: ..., Words: ..., Lines: ...]

目录经常返回 ​301/302​ 跳转到带 ​/​ 的路径;不要只显示 ​200​。

3.2 带认证、Cookie 或自定义 Header

ffuf -w directories.txt -u 'http://<TARGET>/FUZZ' \
  -H 'Authorization: Bearer <TOKEN>' \
  -b 'session=<COOKIE>'

需要特定 Host:

ffuf -w directories.txt -u 'http://<IP>/FUZZ' \
  -H 'Host: app.example.com'

3.3 判断结果

  • ​200​:资源返回,但仍需确认不是统一错误页。
  • ​301/302/307/308​:可能是目录标准化、登录跳转或另一页面。
  • ​401​:资源存在,但需要身份验证。
  • ​403​:资源可能存在,但当前身份无权访问。
  • ​404​:通常不存在,也可能是应用故意伪装。
  • ​500​:输入触发服务端错误,应谨慎复核。

4. Page Fuzzing

目录存在后,需要识别该应用使用的文件扩展名,再枚举页面。

4.1 扩展名模糊测试

ffuf -w /opt/useful/seclists/Discovery/Web-Content/web-extensions.txt \
  -u 'http://<TARGET>/indexFUZZ'

如果结果显示 ​.php​ 有效,继续:

ffuf -w /opt/useful/seclists/Discovery/Web-Content/directory-list-2.3-small.txt \
  -u 'http://<TARGET>/FUZZ.php'

4.2 多扩展名

ffuf -w pages.txt:PAGE -w extensions.txt:EXT \
  -u 'http://<TARGET>/PAGE.EXT'

给字典命名后,URL 中使用对应关键字,而不是固定 ​FUZZ​。

4.3 常见目标

.php .asp .aspx .jsp .html .txt .xml .json
.bak .old .orig .zip .tar.gz

字典应与技术栈匹配。若服务器明显使用 PHP,盲目枚举大量 Java 或 ASP.NET 扩展只会增加噪声。


5. Recursive Fuzzing

单层目录枚举可能发现 ​/admin​,但更深层的 ​/admin/panel​ 仍不可见。ffuf 可对发现的目录继续递归。

ffuf -w directories.txt -u 'http://<TARGET>/FUZZ' \
  -recursion -recursion-depth 2

结合扩展名:

ffuf -w directories.txt -u 'http://<TARGET>/FUZZ' \
  -recursion -recursion-depth 2 -e .php,.html

5.1 参数意义

  • ​-recursion​:对匹配到的目录继续 fuzz。
  • ​-recursion-depth​:限制最大深度,避免无限扩大请求量。
  • ​-e​:在候选后追加扩展名。

5.2 风险控制

递归会显著增加请求量。先使用小字典和较浅深度,确认过滤规则准确,再扩大范围。


6. DNS Records

子域和虚拟主机不是同一概念:

  • DNS 子域:DNS 中存在记录,通常解析为 IP。
  • 虚拟主机:Web 服务器依据 HTTP ​Host​ Header 选择站点,可能没有公开 DNS 记录。

开始枚举前先确定根域及 DNS 解析:

dig example.com
nslookup example.com
host example.com

如果实验目标只提供 IP,需要把域名写入 ​/etc/hosts​:

<TARGET_IP> example.com

修改后验证:

curl -I http://example.com/

DNS 解析失败时,子域 fuzz 的网络行为和 vhost fuzz 的 Host Header 行为会不同,应分别处理。


7. Sub-domain Fuzzing

子域枚举把 ​FUZZ​ 放在域名标签中:

ffuf -w /opt/useful/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -u 'http://FUZZ.example.com/'

7.1 前置条件

  • 根域名可被 DNS 解析。
  • DNS 能返回候选子域的地址。
  • 环境不存在把任意子域都解析到同一地址的通配符记录,或已经建立对应过滤。

7.2 通配符 DNS

先查询随机子域:

dig random-name-that-should-not-exist.example.com

若仍返回 IP,说明存在 wildcard DNS。此时需要根据响应内容、IP 或其他特征过滤,不能把所有结果视为有效子域。


8. Vhost Fuzzing

Vhost 枚举把 ​FUZZ​ 放入 Host Header,并直接访问已知服务器 IP:

ffuf -w /opt/useful/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -u 'http://<TARGET_IP>/' \
  -H 'Host: FUZZ.example.com'

8.1 为什么要用 IP

候选 vhost 可能没有公开 DNS 记录。直接连接 IP,再修改 ​Host​,由 Web 服务器决定返回哪个站点。

8.2 验证结果

找到 ​admin.example.com​ 后加入 ​/etc/hosts​:

<TARGET_IP> admin.example.com

随后浏览器或 curl 验证:

curl -I http://admin.example.com/

vhost fuzz 常遇到所有 Host 都返回默认站点,因此通常需要按响应大小过滤。


9. Filtering Results

过滤是本章核心。匹配参数决定“保留什么”,过滤参数决定“排除什么”。

9.1 Match 参数

参数 含义 ​-mc​ 匹配状态码 ​-ms​ 匹配响应大小 ​-mw​ 匹配单词数 ​-ml​ 匹配行数 ​-mr​ 匹配正则表达式 ​-mt​ 匹配响应时间

9.2 Filter 参数

参数 含义 ​-fc​ 过滤状态码 ​-fs​ 过滤响应大小 ​-fw​ 过滤单词数 ​-fl​ 过滤行数 ​-fr​ 过滤正则表达式 ​-ft​ 过滤响应时间

9.3 典型用法

过滤统一错误页大小:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' -fs 900

只显示指定状态码:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' -mc 200,204,301,302,307,401,403

自动校准:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' -ac

9.4 正确校准步骤

  1. 请求随机、肯定不存在的路径或 Host。
  2. 记录状态码、Size、Words、Lines 和响应关键字。
  3. 选择最稳定的特征过滤。
  4. 对保留下来的结果逐一手工请求。

仅按状态码过滤通常不够,因为许多应用为所有请求返回 ​200​ 自定义错误页。


10. Parameter Fuzzing - GET

目标是发现页面接受但前端未公开的 GET 参数名。

10.1 参数名枚举

ffuf -w /opt/useful/seclists/Discovery/Web-Content/burp-parameter-names.txt \
  -u 'http://<TARGET>/page.php?FUZZ=test' \
  -fs <BASELINE_SIZE>

​FUZZ​ 位于参数名位置,固定测试值用于观察不同参数是否改变响应。

10.2 带已有参数

ffuf -w parameters.txt \
  -u 'http://<TARGET>/page.php?id=1&FUZZ=test'

10.3 结果验证

发现参数后使用 curl 或浏览器手工请求:

curl 'http://<TARGET>/page.php?debug=test'

响应大小不同可能只是错误提示;必须确认参数确实影响业务、输出或服务器行为。


11. Parameter Fuzzing - POST

POST 参数位于请求体中,需要同时指定方法、数据和 Content-Type。

11.1 表单编码

ffuf -w parameters.txt \
  -u 'http://<TARGET>/page.php' \
  -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'FUZZ=test' \
  -fs <BASELINE_SIZE>

11.2 JSON 请求

ffuf -w parameters.txt \
  -u 'http://<TARGET>/api/endpoint' \
  -X POST \
  -H 'Content-Type: application/json' \
  -d '{"FUZZ":"test"}'

11.3 会话与 CSRF

ffuf -w parameters.txt -u 'http://<TARGET>/page.php' -X POST \
  -b 'PHPSESSID=<SESSION>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'csrf=<TOKEN>&FUZZ=test'

若 CSRF Token 每次请求都会变化,静态 ffuf 请求可能全部失败,需要先理解应用会话机制或使用其他自动化方式维护 Token。


12. Value Fuzzing

参数名已知后,把 ​FUZZ​ 放在参数值位置。

12.1 GET 值枚举

ffuf -w values.txt \
  -u 'http://<TARGET>/page.php?id=FUZZ' \
  -fs <NOT_FOUND_SIZE>

数字范围:

seq 1 1000 > ids.txt
ffuf -w ids.txt -u 'http://<TARGET>/page.php?id=FUZZ'

也可通过命令输入:

ffuf -w <(seq 1 1000) -u 'http://<TARGET>/page.php?id=FUZZ'

12.2 POST 值枚举

ffuf -w values.txt -u 'http://<TARGET>/page.php' -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'id=FUZZ' \
  -fs <BASELINE_SIZE>

12.3 判断有效值

  • Size/Words/Lines 与无效基线不同。
  • 状态码或重定向位置改变。
  • 响应中出现实体名称、数据字段或成功信息。
  • 响应时间有稳定差异。

枚举对象 ID 时必须注意越权风险。发现其他对象可访问后,先最小化验证,不应批量下载不属于测试目标的数据。


13. Skills Assessment - Web Fuzzing

13.1 推荐解题顺序

  1. 用 curl 检查目标、状态码和默认响应。
  2. 目录 fuzz,记录 ​200/3xx/401/403​。
  3. 针对有效目录识别扩展名与页面。
  4. 开启浅层递归寻找深层资源。
  5. 确认域名后分别执行子域与 vhost fuzz。
  6. 对统一错误页建立 ​-fs/-fw/-fl/-fr​ 过滤。
  7. 在目标页面 fuzz GET 参数名。
  8. 根据表单或请求格式 fuzz POST 参数名。
  9. 对有效参数 fuzz 值。
  10. 用 curl/浏览器逐条验证并整理攻击链。

13.2 综合命令模板

目录:

ffuf -w <DIR_WORDLIST> -u 'http://<HOST>/FUZZ' -ac

页面与扩展名:

ffuf -w <PAGE_WORDLIST> -u 'http://<HOST>/<PATH>/FUZZ.php' -ac

Vhost:

ffuf -w <SUBDOMAIN_WORDLIST> -u 'http://<IP>/' \
  -H 'Host: FUZZ.<DOMAIN>' -fs <DEFAULT_SIZE>

GET 参数:

ffuf -w <PARAM_WORDLIST> \
  -u 'http://<HOST>/<PAGE>?FUZZ=test' -fs <BASELINE_SIZE>

POST 参数:

ffuf -w <PARAM_WORDLIST> -u 'http://<HOST>/<PAGE>' -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'FUZZ=test' -fs <BASELINE_SIZE>

值:

ffuf -w <VALUE_WORDLIST> \
  -u 'http://<HOST>/<PAGE>?<PARAM>=FUZZ' -fs <INVALID_SIZE>

附录 A:FUZZ 放置位置速查

测试目标 示例 目录 ​<http://host/FUZZ/​> 页面名 ​<http://host/FUZZ.php​> 扩展名 ​<http://host/indexFUZZ​> 子域 ​<http://FUZZ.example.com/​> Vhost ​-H 'Host: FUZZ.example.com'​ GET 参数名 ​?FUZZ=test​ GET 参数值 ​?id=FUZZ​ POST 参数名 ​-d 'FUZZ=test'​ POST 参数值 ​-d 'id=FUZZ'​ Cookie 值 ​-H 'Cookie: role=FUZZ'​ Header 值 ​-H 'X-Forwarded-For: FUZZ'​

附录 B:输出与复现

保存 JSON 结果:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' \
  -o results.json -of json

保存 HTML 报告:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' \
  -o results.html -of html

通过 Web 代理观察请求:

ffuf -w words.txt -u 'http://<TARGET>/FUZZ' \
  -x http://127.0.0.1:8080

代理模式适合调试小字典,不适合把高并发、大规模 fuzz 全部塞入 Burp/ZAP。

附录 C:常见失败原因

现象 原因与处理 所有候选都显示有效 目标使用统一错误页;建立 ​-fs/-fw/-fl/-fr​ 过滤 没有任何结果 URL、Host、DNS、协议或字典路径错误;检查基准请求 vhost 全部相同 返回默认站点;过滤默认响应大小 子域 fuzz 失败但 vhost 成功 候选无公开 DNS,但 Host Header 存在虚拟站点 POST 全部失败 缺少 Content-Type、Cookie、CSRF Token 或必要固定字段 页面返回 403 资源可能存在;不要直接当作不存在 301 结果被忽略 目录常跳转到带斜杠路径;保留 3xx 并手工验证 请求过多或超时 降低 ​-t​、设置 ​-rate​、缩小字典和递归深度 结果随时间波动 动态页面导致 Size 不稳定;改用 Words、Lines 或正则过滤 只找到目录未找到页面 继续做扩展名、页面和递归 fuzz

附录 D:测试记录模板

目标 URL / IP:
授权范围:
字典与来源:
FUZZ 位置:
基准错误响应:Status / Size / Words / Lines
匹配参数:
过滤参数:
线程与速率:
发现结果:
手工验证命令:
验证后的真实资源/参数:
敏感数据与权限影响:

总结

ffuf 的关键不是“跑一个大字典”,而是把 ​FUZZ​ 放在正确的请求位置,并用稳定的响应特征过滤噪声。实际工作中应遵循:先建立基线,再选择字典;先做浅层发现,再递归深入;自动化找到候选,手工请求完成验证。

avatar

Zybaxy918039

书本,学术,网安之间反复横跳的业余爱好者,目前在自学计算机网络和AI相关知识

RECOMMENDED

HTB Academy:使用 Nmap 进行网络枚举

2026-09-19 22:17:09

HTB Academy:信息收集-网络版(Web Reconnaissance)学习笔记

2026-09-19 22:22:34

HTB Academy:Footprinting(足迹收集)

2026-09-20 12:23:20

Table of Contents