反序列化漏洞黑盒很难发现,即使发现了也好难利用。不过危害很大。
序列化使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
序列化结果
string(5) "i:34;" //number
string(13) "s:6:"uusama";" //str
string(4) "b:1;" //bool
string(2) "N;" //null
string(30) "a:2:{s:1:"a";i:1;s:1:"b";i:2;}" //array('a' => 1, 'b' => 2);
string(52) "O:2:"CC":2:{s:4:"data";s:2:"uu";s:8:" CC pass";b:1;}" //new CC('uu', true);
几个相关的魔术方法:
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发 该方法挑选一些特定的变量名称进行下一步序列化,而不是使用类中所有变量进行序列化
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发,返回值需要为字符串
__invoke() //当脚本尝试将对象调用为函数时触发
PHP预定义序列化接口Serializable
https://stitcher.io/blog/new-in-php-74
反序列化漏洞举例:
<?php
class A{
var $test = "demo";
function __destruct(){
echo $this->test;
}
}
$a = $_GET['test'];
$a_unser = unserialize($a);
?>
变量$a从url中test参数获取到内容,并且在反序列化的时候通过__destruct()直接将传入的数据不经过任何处理,echo出来,这里就存在反射型xss漏洞了。
当脚本结束运行时,所有的对象都会销毁,就会自动调用__destruct方法。要关注__wakeup和__destruct,追踪是否存在可利用的函数。
高危函数:
exec()
passthru()
popen()
system()
file_put_contents()
file_get_contents()
unlink()
。。。
PHP的 unserialize() 函数只能反序列化在当前程序上下文中已经被定义过的类.在传统的PHP中你需要通过使用一大串的include() 或者 require()来包含所需的类定义文件。于是后来出现了 autoloading 技术,他可以自动导入需要使用的类,再也不需要程序员不断地复制粘贴 那些include代码了。这种技术同时也方便了我们的漏洞利用.因为在我们找到一个反序列化点的时候我们所能使用的类就多了,那么实现漏洞利用的可能性也就更加高。
还有一个东西要提一下,那就是Composer,这是一个php的包管理工具,同时他还能自动导入所以依赖库中定义的类。这样一来 unserialize() 函数也就能使用所有依赖库中的类了,攻击面又增大不少。
1.Composer配置的依赖库存储在vendor目录下
2.如果要使用Composer的自动类加载机制,只需要在php文件的开头加上
require __DIR__ . '/vendor/autoload.php';
参考:
https://www.cnblogs.com/youyoui/p/8610068.html
https://blog.youkuaiyun.com/qq_33020901/article/details/80743728
RFC for a Secure Unserialization Mechanism in PHP
https://wiki.php.net/rfc/custom_object_serialization