一篇文章带你了解反序列化漏洞

摘要: 反序列化漏洞

0x01.反序列化漏洞介绍

序列化在内部没有漏洞,漏洞产生是应该程序在处理对象、魔术函数以及序列化相关的问题导致的当传给unserialize()的参数可控时,那么用户就可以注入payload,进行反序列化的时候就可能触发对象中的一些魔术方法。

什么是序列化(serialize)? 

对象的状态信息转换为可以存储或传输的形式的过程在序列化期间,对象将当前的状态写入到临时或持久性的存储区 【将状态信息保存为字符串】。

什么是反序列化(unserialize)? 

将字符串转换为状态信息 序列化 <—>反序列化。

PHP中的几个特殊的魔术方法。

    1.__construct():当对象创建(new)时会自动调用,但在unserialize()时是不会自动调用的(构造函数) 

    2.__destruct():当对象操作执行完毕后自动执行__destruct()函数的代码。

    3.__wakeup():unserialize()时自动调用。

还有好多,关于其他的魔术方法可以百度百度。

__wakeup() //使用unserialize时触发 
__sleep() //使用serialize时触发 
__destruct() //对象被销毁时触发 
__call() //在对象上下文中调用不可访问的方法时触发 
__callStatic() //在静态上下文中调用不可访问的方法时触发 
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性 
__isset() //在不可访问的属性上调用isset()或empty()触发 
__unset() //在不可访问的属性上使用unset()时触发 
__toString() //把类当作字符串使用时触发 
__invoke() //当脚本尝试将对象调用为函数时触发

1

0x02.通过demo理解反序列化漏洞

如果不懂,实在不知道,可以狭义的理解。

    序列化是编码。

    反序列化是解码。

下面的话我仔细解释:

<?php
class test{
    public $name = "f1r3K0";
    public $age = "18";
}
$class = new test();
$class_ser = serialize($class);
print_r($class_ser);

这里就用 __destruct演示,后面的实验我会用 __wakeup()来演示。

上面这段代码为序列化,可以理解成编码。

image.png

image.png

接下来就是解码(反序列化)

<?php
class test{
    public $name = "f1r3K0";
    public $age = "18";
}
$class = new test();
$class_ser = serialize($class);
print_r($class_ser);
$class_unser = unserialize($class_ser);
print_r($class_unser);

image.png

提醒一下,当使用unserialize()恢复对象时,将调用__weakup()成员函数。

0x03. 通过某CTF题目继续入了解反序列化漏洞

接下来就开始讲一下某CTF题目,对于反序列化,我一直模棱两可,之前是一直以为是优先级的问题,但是还是不好确定,就先把这个疑问放到一边了。

image.png

这边可以看出这个类用了两个方法。

1.__destruct: 对象操作执行完毕后自动执行该函数内的代码;

2.__wakeup: 遇到 unserialize 时触发。

image.png

这边的 __wakeup 是事件型的,如果没遇到 unserialize 就永远不会触发了,所以我们得先搞清楚先执行哪个方法,再执行哪个方法。

image.png

通过这段代码,可以看出 __wakeup()是优先执行的,优先级高于 __destruct()

那么再看看上面的ctf题目就懂了,因为遇到了unserialize 得先执行 __wakeup里面的内容,才能跑到我们想要的 __destruct()里面,所以得绕过这个 __wakeup

其实就是遍历一下非静态的,咱写一份代码就懂了,手工测试(这也是我最常用的方法)。

image.png

1

看下输出结果,其实就是把 warn的值变为空,那么就懂了这个 __wakeup中的代码是干嘛的了。

1

就是把 warn的值进行过滤,把它变成空,所以我们不能让 __wakeup执行

__wakeup是当反序列化成功时,才会调用,那我们让它失败呢?其实只要让它失败,就不会调用这个魔术方法了。

1

通过修改一下,让这个源码生成一个exp,当然,你也可以自己构造。

1

里面的值是不可以修改的,但是可以修改的属性(变量)数大于实际的个数时,就可以绕过 __wakeup

O:7:"convent":2:{s:4:"warn";s:10:"No hacker.";}

也就是把1改为其他数字就可以了,也可以改成10。然后把 No hacker改为 phpinfo();但是要注意修改 前面 s的值,因为 phpinfo();也是占了十位,所以不用去改。

O:7:"convent":2:{s:4:"warn";s:10:"phpinfo();";}

成功构造payload了,然后再post传参里面传入。

1

总结

本篇文章也就是简单的了解下什么是 php反序列化,本篇文章虽然不长,但是讲了反序列化是什么,怎么形成反序列化漏洞。然后多个魔术方法情况下是看哪个先执行。

    比如 __wakeup是个事件型的,遇到unserialize就会优先调用执行,但是__construct的执行顺序还是优先__weakup

原文地址:https://www.freebuf.com/articles/web/241998.html

上一篇:内网渗透之应用层隧道技术(上...
下一篇:CVE-2020-9484 ...