最近和同学一起做别人的招新题,学到了些新的东西,记下来以免忘记。
打开网页,看到一只猫:
备份网站的习惯,我试了试.bak,发现没有,然后用御剑扫了一下后台,扫出来了www.zip。
下载下来看看:
看到个flag.php,点进去,提交发现是错的flag。
再看看index.php,看到一行关键代码:
猜测是反序列化漏洞。
再看看class.php
<?php
include 'flag.php';
error_reporting(0);
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
我自己写了一串代码,来测试各个魔术函数的执行时间:
<?php
error_reporting(0);
class Test
{
private $c = 789;
private $d = 'def';
public function __construct()
{
echo "construct\n";
$this->c = 123;
}
public function __destruct()
{
echo "destruct\n";
if($this->c == 456)
echo "You did it\n";
}
public function __wakeup()
{
echo "wakeup\n";
}
}
$test = new Test();
echo "create a new object.\n";
echo serialize($test);
echo "serialize the object.\n";
$re = 'O:4:"Test":2:{s:7:" Test c";i:123;s:7:" Test d";s:3:"def";}';
var_dump(unserialize($re));
echo "unserialize the object.\n";
?>
运行结果如下:
可以看到:1,魔术函数的执行顺序为:_construct() --> 创建对象 --> 序列化 --> __wakeup() --> 反序列化 --> __destruct()
2, 通过$this->c
,我们成功将$c
的值改为了123,但再将原来的序列化进行反序列化时,却失败了。
看魔术函数执行的顺序可知,我们需要绕过__wakeup()
,再看了看官方对于该函数的文档以及绕过__wakeup的文章值得注意的是,这题所用的变量也是private变量,所以,要按照文章中的方法编码\00
否则的话就不能成功,上面的小代码就是因为没有将\00
编码导致的反序列化失败。
下面是我的脚本:
其中o1
为成功绕过的payload,o2
为绕过了__wakeup()
的payload,o3
为class.php将__construct()
函数注释之后序列化的结果。
可以看到,我将00
进行了编码,加进了类名和private变量名前面,而且长度也进行了增加,修改了object
的数目,从而绕过了__construct()
函数。然后成功拿到flag。
反序列化可以学的东西还很多,我得继续努力。