序列化与反序列化一、什么是序列化与反序列化?序列化:把内存中的对象转换成可存储或传输的格式(字节流、JSON、XML等等)反序列化:把这种格式的数据还原成程序中的对象。漏洞就出在“反序列化不可信数据”这一步。程序还在还原对象的时候,可能会自动触发某些危险操作,攻击者利用这点来构造恶意数据。1.1 反序列化简介就是把一个对象,变成可以传输的字符,目的是为了方便传输。假设:我们写了一个class,这个class里存着一些变量。当这个class被实例化之后,在使用的过程中里面的一些变量的值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个class一直不销毁,等着下一次要用这个class的时候,再次被调用的话会浪费系统。当我们写一个小型的项目可能没什么太大影响,但随着项目的壮大,一些小问题就会被放大产生很多麻烦。这个时候PHP跟我们说,你可以把这个对象序列化,存储成一个字符串,当你要用的时候在放他出来不就好了。这就是说把对象进行序列化存储。在PHP反序列化中,围绕sreialize()和unserialize() 这两个函数讲解。二、反序列化漏洞产生的原理sreialize()和unserialize()在PHP内部实现上是没有漏洞的,之所以会产生反序列漏洞是因为应用程序,在处理对象、魔术函数以及序列化相关问题时导致的。当传给unserialize()的参数可控时那么用户就可以注入精心构造的Payload。当进行反序列化的时候就有可能触发对象中的一些魔术方法,造成意想不到的结果。三、不同语言的典型情况很多语言在反序列化时会自动调用对象的一些生命周期方法例:Java:readObject()、finalize();PHP:__wakeip()、__destruct()、__toString()Python:__reduce__()、__setstate__()攻击者无法随意执行代码,但可以利用程序本身或第三方库中现有的类,像搭积木一样拼出一条调用链(Gadget Chain),最终实现任意命令执行。因为数据完全由攻击者控制,连类名,字段值都可以被篡改。Java:最常见。利用ObjectInputStream反序列化恶意的Serialize()对象,结合Commons Collections、Fastjson等组件完成攻击。PHP:unserialize()处理用户输入时,利用魔术方法构造POP链。Python:pickle模块的loads()明确警告不要反序列化不可信数据,因为其虚拟机可以被直接注入系统命令。.NET:BinaryFormatter、SoapFormatter已经被官方标记为危险,不应用于不可信数据。Node.js:node-serialize等第三方包如果直接反序列化用户传入的数据,也可能导致代码注入。四、危害远程代码执行:拿到服务器权限文件读写:窃取配置、源码或写入WebShell拒绝服务:通过嵌套数组、循环引用等构造“反序列化炸弹”,耗尽CPU和内存五、怎样防御禁止反序列化不可信数据(最根本)。优先使用纯数据格式如JSON,且只用库的纯数据映射模式。必须反序列化时,进行完整性检查:对反序列化数据加数字签名或加密,确保未被篡改。类白名单:严格限制允许反序列化的类(如:Java的ObjectInputFilter,PHP7.3+的allowd_classes选项)更新依赖:及时升级基础库和框架,避免使用已知含Gadget的旧版本隔离:在沙箱或者低权限进程中执行反序列化操作。总结:永远不要信任来自客户端的序列化对象,如果业务必须使用,一定要加上签名和白名单校验。六、PHP反序列化要理解攻击,先得看得懂序列化后的字符串。当你对一个Person类实例进行序列化,你会得到类似下面的结构。PHPclass Person { public $name = "张三"; private $age = 20; producted $sex = "boy" }TEXTO:6:"Person":3:{s:4:"name";s:6:"张三";s:11:" Person age";i:20;s:6:"*sex";s:3:"boy";}对象声明:O:6:"Person":3 表示一个对象(O),类名长度6,类名Person,有3个属性。O :这是一个对象(Object)6:类名Person的长度是6个字节(P-e-r-s-o-n)"Person":类名3:这个对象有3个属性第一个属性(公开):s:4:"name";s:6:"张三";s:4:"name":属性名是字符串,长度4,内容是name。s:6:"张三":属性值是字符串,长度是6,内容是张三。因为张三在UTF-8编码下占6个字节(每个中文字符占3字节)如果写成s:2就会阶段报错。第二个属性(私有):s:11:" Person age";i:20这段是全串最坑、最重要的部分!表面看是:" Person age"(前面一个空格,中间一个空格)。但长度却是11,数一下隐藏字符:实际存储为:\x00+Person+\x00+age拆开数:\x00(1字节)+Person(6字节)+\x00(1字节)+age(3字节)在文本显示用\x00(空字节不可见),通用显示为空格,所以才写成" Person age"。i:20:值是整数20
一、什么是序列化与反序列化?
漏洞就出在“反序列化不可信数据”这一步。程序还在还原对象的时候,可能会自动触发某些危险操作,攻击者利用这点来构造恶意数据。
1.1 反序列化简介
二、反序列化漏洞产生的原理
sreialize()和unserialize()在PHP内部实现上是没有漏洞的,之所以会产生反序列漏洞是因为应用程序,在处理对象、魔术函数以及序列化相关问题时导致的。
三、不同语言的典型情况
很多语言在反序列化时会自动调用对象的一些生命周期方法
例:
攻击者无法随意执行代码,但可以利用程序本身或第三方库中现有的类,像搭积木一样拼出一条调用链(Gadget Chain),最终实现任意命令执行。因为数据完全由攻击者控制,连类名,字段值都可以被篡改。
四、危害
五、怎样防御
总结:永远不要信任来自客户端的序列化对象,如果业务必须使用,一定要加上签名和白名单校验。
六、PHP反序列化
要理解攻击,先得看得懂序列化后的字符串。当你对一个Person类实例进行序列化,你会得到类似下面的结构。