序列化 & 反序列化#
序列化:将内存中的对象(数据结构)转换成可存储或传输的格式(比如:字节流、JSON、XML、Protobuf 等)。
反序列化:序列化的逆过程。
不同的编程语言,对序列化与反序列化的叫法可能有所不同,比如 Python 称序列化为 pickling(腌制)、Ruby 称序列化为 marshalling(编组)。尽管在日常交流中,直接说序列化与反序列化并不会引起误解,但是你也得知道有这么一种说法。
序列化会将对象中的所有(有例外,见下)属性(无论是什么访问修饰符)以及其对应的值完整地保留在序列化的结果里面,通过反序列化就可以完整恢复。
几乎每种语言都会采用一种方式来避免某属性被序列化,比如 Java 中,对于那些被 transient 或者 static 修饰的属性就不会被序列化。
不安全的反序列化#
如果对不可信的用户数据执行了反序列化操作,则会恢复一些用户指定的对象(里面的属性以及属性值都是用户指定的)。这还不是最关键的,执行反序列化的时候,程序往往会自动执行一些方法(比如 PHP 中的魔数方法、Java 中的 readObject 等),这可能涉及到对恢复对象的一些操作,从而引发危害。
由此可见,攻击者需要提供一个精心构造的 Payload,使其在被反序列化的时候触发危害操作。这就涉及到利用链的构造,详见下一小节。
值得一提的是,不安全的反序列化的利用往往在反序列化的过程中就完成了,至于最终应用会不会报错或者终止,已经没有什么关系了(有些时候需要考量 OPPSEC)。
如何构造利用链?#
Gadget:应用或者依赖库中的某段代码片段。
Gadget Chain(利用链):将各个 Gadget 串联,组成一条链。
Gadget Chain 的核心特性:以反序列化操作为触发器,能自动地走完链上的所有 Gadget。
So,如何构造利用链?
没有什么特殊的技巧,只需要记住:Gadget 是载体,自动化是精髓,反序列化是触发器。
如何发现不安全的反序列化?#
如果你在 HTTP 报文历史记录中,发现了序列化后的数据的迹象,则你可以推断目标存在某端点能反序列化这些数据。
序列化后的数据往往具备一定的特征,比如 PHP:
O:4:"User":2:{s:4:"name":s:6:"carlos";s:10:"isLoggedIn":b:1;}再比如 Java,序列化后的二进制字节流的开头总是固定的:
AC ED当然,这些序列化后的数据很可能经过各种编码。
Burp Suite Scanner 会对于历史 HTTP 报文中信息会进行被动扫描,如果发现了序列化信息特征,则会在 issues 中报告:

不安全的反序列化利用方式#
主要有下述三种方式:
- 修改序列化后的数据,使得某属性或者属性值发生变化
- 用已知的利用链
- 自己构造利用链(需要有源码访问权限)