-- PHP反序列化漏洞的基本原理,漏洞获取,利用,攻击和防御
【官网】:无
应用场景
序列化和反序列化大量应用在web系统中,其中很多开发者会在序列化和反序列化函数中做一些处理。例如在php中调用反序列化函数unserialize时,如果存在用户可控参数,同时由于反序列化会自动调用一些魔术方法,且恰好魔术方法内存在一些敏感操作例如eVal()函数基础资源
1)目标web请求的服务端存在反序列化调用. 2)反序列化操作中有动态执行函数. 3)动态执行函数会获取用户可控参数
使用须知
请仅用于合法安全测试和修复,勿用于非法用途。
配置步骤
无
常见问题
快速入门
A)反序列化漏洞原理。
a1)什么是序列化与反序列化?
序列化是将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象状态,重新创建该对象。
换一句话说:序列化:把对象转换为字节序列的过程称为对象的序列化。 反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
php的序列化函数:
https://www.runoob.com/php/php-serialize-function.html
php反序列化函数:
https://www.runoob.com/php/php-unserialize-function.html
A2)序列化格式解释.
A2.1)对于没有private字段的情况.
序列化串: O:4:"test":2:{s:2:"id";s:5:"Baize";s:4:"name";s:3:"Sec";}
解释:
O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>}
A2.2)对于有private成员的序列化。
序列化串:O:4:"test":2:{s:8:"testid";s:5:"Baize";s:4:"name";s:3:"Sec";}
O:4:"test":2:{s:8:"%00test%00id";s:5:"Baize";s:4:"name";s:3:"Sec";}
解释:
O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>}
附:其它语言生成php 序列化串的资料。
JavaScript 版本(stable):http://www.devpro.it/code/102.html
Perl 版本(stable):http://hurring.com/code/perl/serialize/
另一个 Perl 版本:http://www.cpan.org/modules/by-module/PHP/JBROWN/php-serialization/
Python 版本(beta):http://hurring.com/code/python/serialize/
Java 版本(pre-alpha):http://hurring.com/code/java/serialize/
Ruby 版本:http://www.aagh.net/files/ruby/php_serialize.rb
Flash/Actionscript 版本:http://sourceforge.net/projects/serializerclass/
C# 版本:http://sourceforge.net/projects/csphpserial/
a3)反序列化漏洞产生的原理。
反序列化漏洞就出在反序列化(把数据转化成对象)的过程中。在这个过程中,应用需要根据数据的内容,去调用特定的魔术方法。而黑客正是利用这个逻辑,在数据中嵌入自定义的代码(比如执行某个系统命令)。应用对数据进行反序列化的时候,会执行这段代码,从而使得黑客能够控制整个应用及服务器。这就是反序列化漏洞攻击的过程。
a3.1)利用 php中的魔术方法。
__construct() 当创建对象时触发,一般用于初始化对象,对变量赋初值
__destruct() 当一个对象被销毁时触发
__sleep() 使用serialize()时自动触发 __wakeup() 使用unserialize()时自动触发 __toString() 当一个类被当成字符串使用时触发 __invoke() 当尝试以调用函数的方式调用一个对象时触发 __call() 在对象上下文中调用不可访问的方法时触发 __callStatic() 在静态上下文中调用不可访问的方法时触发 __get() 用于从不可访问的属性读取数据 __set() 用于将数据写入不可访问的属性 __isset() 在不可访问的属性上调用isset()或empty()触发 __unset() 在不可访问的属性上使用unset()时触发
B)反序列化漏洞的危害.
b1)通过反序列化漏洞,被黑客在内容中嵌入了执行自定义命令的代码,被获得了服务器权限。
Runtime.exec(...)
eVal()
b2) 被黑客构造了一些特殊的(虽然没有执行命令,但嵌套深度很深)导致服务器cpu耗尽(进而停止服务).
C)反序列化漏洞获得途径。
1)源码审计,发现魔术函数,自定义反序列化函数,可利用的pop链,php本身的漏洞。
2)猜测等手段确认对方的系统是基于某些开源框架或系统开发的。
3)漏洞报告。
D)反序列化漏洞的实例。
E)反序列化漏洞的防御。
e1)签名与认证。
如果序列化的内容没有用户可控参数,仅仅是服务端存储和应用,则可以通过签名认证,来避免应用接受黑客的异常输入。
e2)限制序列化与反序列化的类。
增加一层序列化和反序列化接口类。这就相当于允许提供了一个白名单的过滤:只允许某些类可以被反序列化。只要你在反序列化的过程中,避免接受处理任何类型(包括类成员中的接口、泛型等),黑客其实很难控制应用反序列化过程中所使用的类,也就没有办法构造出调用链,自然也就很难利用反序列化漏洞了
e3)RASP检测。
(Runtime Application Self-Protection,实时程序自我保护)。RASP 通过 hook 等方式,在这些关键函数(例如:序列化,反序列化)的调用中,增加一道规则的检测。这个规则会判断应用是否执行了非应用本身的逻辑,能够在不修改代码的情况下对反序列化漏洞攻击实现拦截.