反序列化漏洞-PHP

原理

序列化

序列化(Serialization):将对象的状态信息转换为可以存储或传输的形式的过程,一般将对象转换为字节流。序列化时,对象的当前状态被写入到临时或持久性存储区(文件、内存、数据库等)。

反序列化

反序列化(Deserialization):从序列化的表示形式中提取数据,即把有序字节流恢复为对象的过程

反序列化攻击

攻击者控制了序列化后的数据,将有害数据传递到应用程序代码中,发动针对应用程序的攻击。

演示

序列化

  • serialize () 函数用于序列化对象或数组,并返回一个字符串。

序列化

可以看到name变量被我们序列化后变成s:6:”Drton1″   这个s表示字符的意思,6就是字符长度,最后是字符内容,序列化后的形式用来传输。

反序列化

  • unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

反序列化

可以看到我们进行还原,又变成我们之前规定的值。

我理解这就像个加密解密,serialize () 函数加密后,unserialize () 函数再进行解密。

技术

无类时的反序列化

类这个应该都知道,面向对象编程语言里面的概念。没有类时候,那就是面向过程编程

如果序列化时候不是对一个对象序列化,而是对一些变量什么序列化,就想上面那样,那也并不复杂,就跟上面那个一样。但是一旦牵扯到类,就有一些魔术方法会被触发,而这些方法也是导致漏洞的最重要的原因。

有类时的反序列化

魔术方法:

__construct()	//创建对象时触发
__destruct() 	//对象被销毁时触发
__call() 			//在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() 			//用于从不可访问的属性读取数据
__set() 			//用于将数据写入不可访问的属性
__isset() 		//在不可访问的属性上调用 isset()或 empty()触发
__unset() 		//在不可访问的属性上使用 unset()时触发
__invoke() 		//当脚本尝试将对象调用为函数时触发
__sleep()         //如果类中存在_sleep()函数 那么该类被serialize ()前会触发
__wakeup()     //如果类中存在_wakeup()函数 那么该类被unserialize ()前会触发

有类的反序列化

结合上面资料 解释一下右边运行结果:

  • 创建ABC类时 触发_construct()函数  输出了 调用构造函数
  • 在进行unserialize()发现类中有_wakeup()函数 于是进行触发  输出调用了苏醒函数
  • 此时$a被销毁 触发_destruct()函数 输出 调用了折构函数
  • 此时刚刚被反序列化的$a_unser 也被销毁 又触发_destruct()函数 输出调用了折构函数

利用

无类序列化CTF赛题-wp

点login咋没反应 – Bugku CTF

打开环境 ,发现点击登录并无反应。

ctf-1-0

F12审查元素,发现admin.css里面又提示,url加入?17803

ctf-1-1

照做,进入赛题,是一道无类的反序列化题。

ctf-1-2

这里可以看到他的逻辑 几个if进行判断,而我们要的flag 在都二个elseif当中,发现他会比较通过Cookie传参过来的BUGKU参数反序列化后与KEY进行比较,如果相等就显示flag。那么我们思路就很清晰,我们发现他的KEY是”ctf.bugku.com” ,我们只用传入这个内容的序列化内容即可。

ctf-1-3

于是对这串文字进行序列化。

ctf-1-4

然后通过Cookie传参,成功拿到flag,这里要注意我们要去掉url中?17803,因为不去掉的话就符合第一个if的条件了,就不会执行第二个elseif,也就拿不到flag了。

有类反序列化CTF赛题-wp

2020年网鼎杯青龙组-web-AreUserialz

打开赛题:这是一个有类的反序列化赛题

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

仔细审查一下代码思路如下: GET 接收一个参数str   然后会对str进行反序列化

                                                  _destruct()中会对op进行判断如果是2 赋值为1 

                                            但是我们想读取flag.php 肯定想办法触发read函数  触发read函数条件是op=2

                                    于是思路就来了 我们可以传进来一个序列化后的Filehandler类的对象,进来后被反序列化还原成对象,然后程序销毁触发_destruct()函数,此时又要想办法让op=2,但是如果我们直接赋值op=”2″

那么一定会触发if里面条件让op变成1,此时观察到该 比较符是=== ,这个就是又比较类型,又比较内容,我们可以采用op=” 2″绕过,这里2前面多了一个空格,然后我们对该内容进行序列化。

ctf-2-0

ctf-2-1

最后以Get方式传进来,这里因为content内容并不影响逻辑,所以随便赋值,传进来后,F12审查源码发现flag。

ctf-2-2

危害

我们上面那些_destruct()函数里并没有什么危险函数,如eval等,如果有这样的函数,那么黑客是不是可以构造任意命令语句来通过反序列化让其执行。如果是sql语句拼接,那么是不是就是sql注入,所以反序列化漏洞的危害形式非常广。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论