Java 反序列化漏洞_利用原理

0x00 前言

对 Java Deserialization 进行一些复习,感觉这个漏洞还是不能全面理解,java渣渣的痛啊,今次主要阅读以下“NickstaDB”的文章并归纳一些观点,这个文章主要概括了如何在渗透测试中利用这个漏洞

0x01 序列化与反序列化

序列化就是把java运行时的变量或者对象转换为一种特定的序列格式,可以用于储存和传输。反序列化就是这个过程的逆向,把序列化后的数据恢复为java运行时的变量和对象。序列化的格式可以基于文本,例如json,xml或者是二进制格式。Nick的文章只专注于java内建的序列化格式,其他格式的序列化漏洞自行查询了^_^

0x02 面向属性编程(property-oriented programming)

这里的意思大概就是通过控制对象属性从而影响程序行为,这里原文作者提到了一个概念:”POP gadget”,我的理解应该是java调用链,反序列攻击中攻击者不会发送涉及对象或者代码给服务器执行,而是仅仅发送一些服务器而知的类属性,从而更改受这些属性决定的代码片段。大部分的反序列攻击都会用到‘readObject‘函数,因为可以保证代码在反序列化中会被执行

0x03 反序列化攻击

文章列出了反序列化攻击的两个条件:

  1. 入口点:一个允许攻击者发送定制化对象给目标进行反序列的入口点
  2. 一个或者多个允许攻击者通过反序列来更改的代码片段:POP Gadgets

入口点的判断

  • 检查代码中的‘java.io.ObjectInputStream’ 对象和具体的‘readObject’ 方法,判断攻击者是否可以修改它们的输入数据
  • 通过本地储存或者网上流量判断,头四个字节:魔术数字+版本号:AC ED 00 05 。然后后面的一个字节 range 是 0x70 to 0x7E,总的来说类似 0xAC ED 00 05 77 ,但要注意,这4个字节只会在序列化流开始的阶段出现一次,也就是说那些保持连接的序列化数据流是难以捉到这个数据头的
  • 当观察不到头4个字节的时候,可以借助另外一个特征,就是在十六进制的流中观察是否出现类名,例如L开头,结尾是分号’;’,slash作为分隔符,(e.g. ‘Ljava/rmi/dgc/VMID;’)

入口点的利用,payload插入点

  • 最简单的例子是判断4字节后面的对象类型,如果第5个字节是一个具体的类型,则‘readObject’ 方法会直接读取第5个字节,这里就是payload的插入点,如何判断第5个字节是什么类型?Nick给出了一份表格参考,如果第5个字节是下面的类型,则插入点payload插入点就在第4个字节后面,第5个字节前面
0x70 – TC_NULL
0x71 – TC_REFERENCE
0x72 – TC_CLASSDESC
0x73 – TC_OBJECT
0x74 – TC_STRING
0x75 – TC_ARRAY
0x76 – TC_CLASS
0x7B – TC_EXCEPTION
0x7C – TC_LONGSTRING
0x7D – TC_PROXYCLASSDESC
0x7E – TC_ENUM
  • 其余的情况,第5个字节则会是 TC_BLOCKDATA element (0x77) or a TC_BLOCKDATALONG element (0x7A).这两个代表后面的是数据块,攻击者要寻找数据块中支持上述类型的字节,例如:

ACED00057708af743f8c1d120cb974000441424344

  1. 首先分析头5个字节:ACED000577,头4个字节外加一个0x77,代表后面跟着一个数据模块,不是直接一个对象
  2. 74000441424344:0x74 – TC_STRING,找到一个STRING对象了

为了简化这个流程,Nick给出了一个简单的小工具:SerializationDumper

https://github.com/NickstaDB/SerializationDumper

  • 对象在序列化流中是会马上得到实例化的,不用等到整个序列化流都接收完成后才实例化,所以我们插入payload是不用考虑其余的码流的,攻击者的payload会在其他数据流到达和解释前得到实例化和执行。

POP Gadgets

这里Nick的文章直接提议使用“ysoserial”来生成相应的payload,这样比较容易搞吧,还给出了针对java Runtime的命令执行缺点以及解决办法的工具,下面的链接就是分别对应的两个工具:

ysoserial deserialization payload generator (https://github.com/frohoff/ysoserial/)

Runtime.exec() payload encoder (http://jackson.thuraisamy.me/runtime-exec-payloads.html)

自己搭建环境和使用Nick的自动化工具

文章最后Nick给出了一个测试环境:‘DeserLab‘ 和一个自动化的测试工具 ‘SerialBrute’ , 博客回复中有人做了跟进实验,参考以下链接:

http://randomlinuxtech.blogspot.com/2017/08/java-deserialization-howto.html

总结

读了Nick的文章后加深了对java反序列的理解,当然其他语言例如PHP都会存在这类漏洞,但原理应该是相通的。至于一些具体漏洞的调用链研究就以后再继续吧

参考链接:

https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/

https://github.com/NickstaDB/SerialBrute/

https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet

SerializationDumper (https://github.com/NickstaDB/SerializationDumper)

SerialBrute (https://github.com/NickstaDB/SerialBrute/)

DeserLab (https://github.com/NickstaDB/DeserLab)