一、什么是序列化与反序列化?序列化:把内存中的对象转换成可存储或传输的格式(字节流、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反序列化6.1 结构要理解攻击,先得看得懂序列化后的字符串。当你对一个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第三个属性(受保护):s:6:" * sex";3:"boy";表面看是" * sex",长度似乎只有4但实际上长度却是6:实际存储:\x00(1字节)+*(1字节)+\x00(1字节)+sex(3字节)属性名中带有*号,它就是受保护的属性。6.2 危险的魔术方法unserialize()执行的过程中,如果类中定义了特定方法,PHP会自动调用它们,这就成了攻击的“入口”:__wakeup():反序列化时最先自动调用,常作用作对象资源初始化。__destruct():对象被销毁时自动调用(如:脚本结束时),常被用来做“收尾”工作。__toString():对象被当做字符串使用时触发(如:echo $obj)。__call():调用对象中不存在或不可访问的方法时触发。__get()/__set():读取/赋值对象中不存在或不可访问的属性时触发。6.3 利用方式与POP链构造6.3.1 初级利用直接利用危险魔术方法。比如,控制__destruct()里的文件删除路径,实现任意文件删除。6.3.2 高级利用(POP链)通过魔术方法作为起点,调用其他类的方法,像链条一样一环扣一环,最终执行高危操作。6.3.3 自动化工具https://github.com/ambionics/phpggc6.3.4 特殊绕过__wakeup()绕过(CVE-2016-7124):当序列化字符串中表示属性个数的值大于实际个数时,可绕过__wakeup()的执行。Phar反序列化:利用phar://伪协议,在file_exists()等文件操作函数中触发元数据的反序列化,属于“无unserialize()”的利用。6.4 Jboss反序列化如何检测:下载工具检测 java -jar DeserializeExploit.jar6.4.1 Jboss 5.x/6.x反序列化漏洞(CVE-2017-12149)原理:Jboss的HttpInvoker组件中的ReadOnlyAccessFilter过滤器进行任何安全检查的情况下将凯子客户端的数据流进行反序列化。访问地址:http://192.168.1.1:8080/http://192.168.1.1:8080/invoker/readonly返回500说明漏洞存在利用:下载利用工具反弹shell:github自己找6.4.2 Jboss 4.x JBossMQ JMS反序列化漏洞(CVE-2017-7504)原理:问题根源在于类ObjectinputStream在反序列化时,没有对生成的对象类型做限制利用:下载利用工具反弹shell:github自己找6.4.2 Jboss 远程部署漏洞原理:后端未对用户可控参数做严格过滤危害:导致任意命令执行,入侵者可利用此漏洞直接获取webshell。6.5 Weblogic反序列化版本:10.3.6.0、12.1.3.0、12.2.1.2、12.2.1.3CVE-2018-2628原理:此漏洞产生于Weblogic的T3服务。当开放Weblogic控制台端口(默认7001)时,T3服务会默认开启。攻击者可以利用T3协议发送恶意序列化数据。非反序列化漏洞—弱口令:弱口令漏洞可以百度该中间件的默认用户名密码比如:weblogic弱口令:用户名密码都是weblogicJava反序列化漏洞操作(CVE-2018-2628)、任意文件上传漏洞操作(CVE-2018-2894)、XML Decoder反序列化操作漏洞(CVE-2017-10271)、SSRF漏洞(需要安装Weblogic时选择UDDI组件)、反序列化漏洞(CVE-2019-2725)、未授权访问。6.6 Apache反序列化6.6.1 Shiro-550 存在java反序列化攻击特征:在返回包里的Set-Cookie中存在rememberMe=deleteMe字段漏洞影响:Apache Shiro <=1.2.4 版本都存在威胁漏洞原理:漏洞利用的是cookie里的rememberMe参数,这个参数的值是AES加密再Base64之后设置在cookie中的。在服务端对rememberMe的cookie值的操作应该是先base64解码,然后再AES解密,再反序列化。问题的关键在于,AES加密的密钥就在源代码里,AES是对称加密,所以加密密钥就是解密密钥。攻击者只要得到AES加密的密钥,就可以构造一个恶意对象,对其进行序列化、AES加密、Base64编码。然后将其最为cookie的rememberMe字段发送,Shiro将其进行解密并反序列化,最终造成了反序列化漏洞。防范方法:升级修改文件中硬编码的密钥临时防范建议:在安全设备尝试拦截爆破流量,及时组织攻击者进行攻击尝试。升级对应JDK版本到8u191/7u201/6u211/11.0.1以上WAF拦截Cookie中长度过大的rememberMe值WAF拦截访问过于频繁的IP,因为该漏洞需要爆破Cookie6.7 安全防范安全配置好php相关参数:php.ini配置文件里有个disable_functions = 配置,这个禁止某些php函数,服务器便是用这个来禁止php的执行命令函数的。升级中间件严格控制传入变量,严谨使用魔法函数。
一、什么是序列化与反序列化?
漏洞就出在“反序列化不可信数据”这一步。程序还在还原对象的时候,可能会自动触发某些危险操作,攻击者利用这点来构造恶意数据。
1.1 反序列化简介
二、反序列化漏洞产生的原理
sreialize()和unserialize()在PHP内部实现上是没有漏洞的,之所以会产生反序列漏洞是因为应用程序,在处理对象、魔术函数以及序列化相关问题时导致的。
三、不同语言的典型情况
很多语言在反序列化时会自动调用对象的一些生命周期方法
例:
攻击者无法随意执行代码,但可以利用程序本身或第三方库中现有的类,像搭积木一样拼出一条调用链(Gadget Chain),最终实现任意命令执行。因为数据完全由攻击者控制,连类名,字段值都可以被篡改。
四、危害
五、怎样防御
总结:永远不要信任来自客户端的序列化对象,如果业务必须使用,一定要加上签名和白名单校验。
六、PHP反序列化
6.1 结构
要理解攻击,先得看得懂序列化后的字符串。当你对一个Person类实例进行序列化,你会得到类似下面的结构。
6.2 危险的魔术方法
unserialize()执行的过程中,如果类中定义了特定方法,PHP会自动调用它们,这就成了攻击的“入口”:
6.3 利用方式与POP链构造
6.3.1 初级利用
直接利用危险魔术方法。比如,控制__destruct()里的文件删除路径,实现任意文件删除。
6.3.2 高级利用(POP链)
通过魔术方法作为起点,调用其他类的方法,像链条一样一环扣一环,最终执行高危操作。
6.3.3 自动化工具
6.3.4 特殊绕过
6.4 Jboss反序列化
6.4.1 Jboss 5.x/6.x反序列化漏洞(CVE-2017-12149)
原理:Jboss的HttpInvoker组件中的ReadOnlyAccessFilter过滤器进行任何安全检查的情况下将凯子客户端的数据流进行反序列化。
访问地址:
返回500说明漏洞存在
利用:下载利用工具反弹shell:github自己找
6.4.2 Jboss 4.x JBossMQ JMS反序列化漏洞(CVE-2017-7504)
原理:问题根源在于类ObjectinputStream在反序列化时,没有对生成的对象类型做限制
利用:下载利用工具反弹shell:github自己找
6.4.2 Jboss 远程部署漏洞
原理:后端未对用户可控参数做严格过滤
危害:导致任意命令执行,入侵者可利用此漏洞直接获取webshell。
6.5 Weblogic反序列化
版本:10.3.6.0、12.1.3.0、12.2.1.2、12.2.1.3
CVE-2018-2628
非反序列化漏洞—弱口令:弱口令漏洞可以百度该中间件的默认用户名密码比如:weblogic弱口令:用户名密码都是weblogic
Java反序列化漏洞操作(CVE-2018-2628)、任意文件上传漏洞操作(CVE-2018-2894)、XML Decoder反序列化操作漏洞(CVE-2017-10271)、SSRF漏洞(需要安装Weblogic时选择UDDI组件)、反序列化漏洞(CVE-2019-2725)、未授权访问。
6.6 Apache反序列化
6.6.1 Shiro-550 存在java反序列化
攻击特征:在返回包里的Set-Cookie中存在rememberMe=deleteMe字段
漏洞影响:Apache Shiro <=1.2.4 版本都存在威胁
漏洞原理:
防范方法:
6.7 安全防范