专栏首页尚国PHP反序列化漏洞

PHP反序列化漏洞

serialize:序列化

unserialize: 反序列化

简单解释:

serialize 把一个对象转成字符串形式, 可以用于保存

unserialize 把serialize序列化后的字符串变成一个对象

我们来看一个实例:

<?php
 class F{
    public $filename='a.txt';
}

$a = new F();
echo $a->filename.'<br />';
echo serialize($a);

上面例子是创建一个类, 并输出 filename的值 , 最后输出序列化字符串:

关于这一串:

O:1:"F":1:{s:8:"filename";s:5:"a.txt";}

简单解释:

O: 对像, 1 对象名长度, 就是这里的 'F'

s: 字符串

8: 字符串长度, 后面的filename为字符串定义时的名字

详细解释可以百度找资料看, 因为这个不是本文重点。

这里你可以看到, 我代码里的类定义为: class F, 这个序列化就是 F, 我定义变量名字是filename, 它这里也是 filename, 我们可以修改看看:

可以看到序列化后的变量名字变成 filenameF 了。

看下面代码:

<?php
 class F{
    public $filenameF='bcda.txt';
}

$a = new F();
echo $a->filenameF.'<br />';
echo serialize($a);

这是另一个代码:

<?php
 class F{
    public $filename='a.txt';
}

$a = new F();
echo $a->filename.'<br />';
echo serialize($a);

这两个代码定义的类一样, 只是属性不一样。

当我们用如下代码反序列时:

<?php
 class F{
    public $filename='a.txt';
    function __destruct(){
        echo '--------------><br />';
    }
}

$a = new F();
echo $a->filename.'<br />';
echo serialize($a);
$b = unserialize('O:1:"F":1:{s:9:"filenameF";s:8:"bcda.txt";}');
echo '<br />'.$b->filename;
echo '<br />'.$b->filenameF;

可以看到析构函数输出了两次, 说明这两个应是同一个类, 只是 $b 多出了一个属性 filenameF, filename可直常输出, filenameF也可正常输出。

在PHP中, 类被创建或消失后, 都会自动的执行某些函数, 如:

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(), and __autoload()

或自动执行某些方法, 如:

Exception::__toString
ErrorException::__toString
DateTime::__wakeup
ReflectionException::__toString
ReflectionFunctionAbstract::__toString
ReflectionFunction::__toString
ReflectionParameter::__toString
ReflectionMethod::__toString
ReflectionClass::__toString
ReflectionObject::__toString
ReflectionProperty::__toString
ReflectionExtension::__toString
LogicException::__toString
BadFunctionCallException::__toString
BadMethodCallException::__toString
DomainException::__toString
InvalidArgumentException::__toString
LengthException::__toString
OutOfRangeException::__toString
RuntimeException::__toString

我们就可以利用这种自动执行某些函数或方法的特性,执行我们相要的操作。

我们创建如下代码:

<?php
 class F{
    public $filename='d:\\phpstudy\\www\\a.txt';
    #$filename为public
    function __destruct(){
        $data = readfile($this->filename);
        echo $data;
    }
}

$a = new F();
echo $a->filename.'<br />';

运行时如下所示:

因为 __destruct 析构函数在一个类对象消失时, 会自动执行。 所以上面的代码当运行结束时, 类对象 $a 消失后, 代码会自动执行 __destruct() 函数。

假如我们创建一个如下的测试代码:

<?php
 class F{
    public $filename='d:\\phpstudy\\www\\a.txt';
    #$filename为public
    function __destruct(){
        $data = readfile($this->filename);
        echo $data.'<br />';
    }
}

$a = new F();
echo $a->filename.'<br />';
$b = unserialize($_GET[a]);

这代码中我们用unserialize反序列一个字符串变成一个类对象, 也就是说这个代码中, 会有两个类对象, 一个是$a, 一个是用户可控的$b ($b 中的filename可控, 因为class F中的 filename为public)。

当代码运行结束时, 会运行两个析构函数。 第一次运行的析构函数中, filename为$a中默认的 'd:\\phpstudy\\www\\a.txt', 第二个因为是从$_GET[a]获得字符串, 所以我们可以控制第二个对象中的filename。

从而使得 __destruct 函数可以读取到我们想要读的文件。

下面这个代码中的类跟上面代码的类一样, 不同的地方是我们修改了filename的值, 并生成序列化字符串:

<?php
 class F{
    public $filename='a.txt';
}

$a = new F();
$a->filename = 'd:\\phpstudy\\www\\2.txt';
echo serialize($a);

生成的序列化字符串为:

O:1:"F":1:{s:8:"filename";s:21:"d:\phpstudy\www\2.txt";}

再创建一个 2.txt 文件用于测试, 内容为:

password

现在,我们已改变了原来的 filename值,并生成了序列化字符串, 再把它发送到测试代码中去:

http://localhost/11.php?a=O:1:%22F%22:1:{s:8:%22filename%22;s:21:%22d:\phpstudy\www\2.txt%22;}

测试代码除了有对象 $a 外, 还反序列化创建了一个对象 $b, 而这个$b中的属性filename被我们修改了。

最后运行两次 __destruct析构函数时, 一次读取了 a.txt, 另一次读取了 2.txt。

最后总结一下:

<?php
include "xxx.php";#此文件中有类定义, 有魔术函数或方法, 且输入参数能被控制
class Classname{
    #存在有害魔术函数或方法,且输入参数能被控制
}


do something...
do something...
do something...

#存在反序列化函数
unserialize('用户输入有害参数未过滤')
do something...
do something...
do something...

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Windows SMBv3 CVE-2020-0796漏洞

    今天,Microsoft不小心泄露了有关安全更新的信息。 蠕虫的 Microsoft服务器消息块(SMB)协议中的漏洞。

    伍尚国
  • avast:中兴手机预装恶意软件 嵌入固件底层

    著名安全机构 avast 发布报告称,旗下安全威胁实验室发现,中兴、爱可视、MyPhone 等厂商的多款安卓手机居然预装了恶意广告软件。该恶意软件被命名为“ C...

    伍尚国
  • 深入剖析最新IE0day漏洞

    在2018年4月下旬,我们使用沙箱发现了IE0day漏洞;自从在野外发现上一个样本(CVE-2016-0189)已经有两年多了。从许多方面来看,这个特别的漏洞及...

    伍尚国
  • 新手001|CentOS7下源码安装MySQL5.7.6+

    MySQL 安装方式分为: 源码安装,相应系统发行包安装(如 rpm, yum, apt-get 等)。生产中比较推荐使用二进制安装。 这里给大家推荐一篇...

    wubx
  • Uninstall all those broken versions of MySQL and re-install it with Brew on Mac Mavericks

    To remove an instance of MySQL from your macOS or OSX installation you need to d...

    九州暮云
  • 【翻译】200行代码讲透RUST FUTURES (2)

    在我们深入研究 Futures in Rust 的细节之前,让我们快速了解一下处理并发编程的各种方法,以及每种方法的优缺点。

    MikeLoveRust
  • mysql-8.0.11-winx64 安装配置: mysqld --initialize --console MYSQL:ERROR 1045 (28000): Access denied ...

    mysql-8.0.11-winx64 安装配置: mysqld --initialize --console MYSQL:ERROR 1045 (28000...

    一个会写诗的程序员
  • mysql相关脚本 原

    (adsbygoogle = window.adsbygoogle || []).push({});

    阿dai学长
  • 第16章、复制

    观察到服务器版本略有差异,应用在生产环境时最好将MySQL的版本保持一致。最不济也要保证前两位(5.7)版本保持一致,不要出现主(5.7)从(5.1)这种跨版本...

    幺鹿
  • ARKit和CoreLocation

    演示代码 ARKit和CoreLocation:第一部分 ARKit和CoreLocation:第二部分 ARKit和CoreLocation:第三部分

    iOSDevLog

扫码关注云+社区

领取腾讯云代金券