freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

使用 Yakit 打破 Java 序列化协议语言隔离
2021-12-31 16:04:53
所属地 海外

一句话背景知识

众所周知,在使用 Java 编写漏洞利用或检测时,ysoserial 或类似工具会构造一个特定的执行命令的对象,然后进行序列化,作为用户只把序列化(Marshal)后的二进制对象作为 Payload,打到特定位置或注册为远程对象,通过 RMI 或者远程服务 readObject 后直接 RCE。

虽然这是一个人人都知道的过程。

威胁

当然,“赛博回忆录-反制系列” 针对这个问题做了详细的文章,Java 实现的漏洞利用实际上是一把 “双刃剑”,在使用各种链来构造特定反序列化流的同时,自己也是一个“靶子”。

其实早在反制系列出现之前,笔者在长亭工作时,子航师傅就提过 Java RMI 的反制,可以做到放一个 1099 RMI 蜜罐在公网,谁来打就打回去反向 RCE。这个原理也非常容易理解。

如何不被“反制”?

大家做漏洞扫描这类安全开发的时候,非常头痛的事情在于,偏爱 Python 或 Golang,不考虑用 Java 实现。

就直接导致很多 Java 漏洞的检测变得非常扭曲。

如果用了 Java 又需要思考如何不被反制,用户需要严格控制不要加载任何来源于攻击者的类或者流。

现状:

市面上关于有 Java 相关的漏洞扫描现在主流分两类:

  1. 依赖 Java 环境,并且 ysoserial.jar 作为扫描器依赖打包,以 Popen / system / subprocess / Exec 调用 java -jar ysoserial.jar 来生成特定 Payload 来进行漏洞检测或攻击。
  2. 另一类选择硬编码利用链的 Payload,然后根据执行命令的 Payload 长度构造合适的 “块”,替换原 Payload 位置,从而构造出一个可用的 Payload。大家常见的 xray 就是通过 “硬编码” 来实现利用链的。

众所周知,针对一些 Groovy 链和常见的 CC1 链都是可以直接找到对应的命令的位置,直接替换即可。实际在第二种实现中,有着非常大的限制:TemplatesImpl

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 模版是很多链执行命令的关键。

尝试过进行一些分析的读者其实非常清楚,我们在有 TemplatesImpl 的链(例如 CC2[CommonCollections2] / CC3 / CC4)中,无法直接 “搜到” 执行的命令的关键字。其实本质上是因为,有一些命令和代码被编译成了 “Java 字节码”,然后又被序列化成了 “TC_BLOCKDATA”,表象就是,每个字节都加了 Padding,我们发现无法 “搜” 到对应 string 了。当然,我们也可以人为去做 “Padding”,然后把 Payload 自己去 Padding 后塞入链中特定位置,也可以构造出一个 “可用” 的 Payload。

作为对比,第一种实现写的代码更少,调用别人的东西而已,无非多启动几个进程;“被反制风险” 当然不言而喻,如果启用 RMI 去攻击,那么被反制可以说是“咎由自取”了。


透过现象看本质

本质上 Java 序列化协议 和 Json 从解决问题的角度来说,没有任何区别:都是为了让数据可以脱离 “程序” 单独存在,进行传输或持久化。只是载体不一样而已。

我们可以很容易理解 Json,其实 Java 序列化协议一样,protobuf 也一样,Bson,Gson,xml 都有这个目的,并且可以说是主要目的。

被反制并不是说只有 Java 反序列化过程会出现问题,PHP 也一样,fastjson 甚至是在反序列化 Json 的过程中,加载了不该加载的东西。

然而要兼容反序列化协议其实并不难,甚至我们可以脑洞一下,我们能把 Java 序列化流中的对象都解析出来,然后经过一些格式检查存储成更利于大家观察的 Json,并且,大家可以修改了 Json 之后,再按照 Java 序列化的协议组合回去。

https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html
https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/protocol.html

Talk is Cheap

其实笔者并不愿意花大量的笔墨来介绍 Java 序列化协议,这些内容其实如果大家稍有研究的话,属于基础知识。我们可以直接来观察一个基础例子:


从一片落叶开始:TC_STRING

我们从最简单的案例开始:我们从字符串对象的序列化开始

1640920080_61ce7410acc6dc57c2135.jpg!small?1640920081028


当然,虽然这个工具看起来非常简单,但是绝对也不仅仅是生成 / 还原一下 HEX。

rO0ABXQAFnlha2xhbmcuaW8taXMtYXdlc29tZSE=

当我们把上述的内容变为十六进制的时候,我们熟悉的 ACED 出现了。

aced000574001679616b6c616e672e696f2d69732d617765736f6d6521

在我们小工具中,我们选择 “Codec => Java => 反序列化 Java 对象流(Hex)”

1640934728_61cead487254ee2dba88a.jpg!small?1640934728835


可以发现我们把左边的序列化的流转换成了一段 JSON

[
  {
    "type": 116,
    "type_verbose": "TC_STRING",
    "is_long": false,
    "size": 22,
    "raw": "eWFrbGFuZy5pby1pcy1hd2Vzb21lIQ==",
    "value": "yaklang.io-is-awesome!",
    "handle": 0
  }
]

同样的,我们把序列化后的内容放在左栏,选择 “Java => Java 对象流序列化(JSON=>HEX)” 即可还原我们的 TC_STRING 变成 ACED 开头的 Java 对象流。

1640934823_61ceada76341f28e3d75c.jpg!small?1640934823729


当然,虽然这个工具看起来非常简单,但是绝对也不仅仅是生成 / 还原一下 HEX。

SerialDumper 的 yaklang.io 版本、

我们 Java 序列化协议的实现过程中,增加了和 SerialDumper 一样的功能。

1640934854_61ceadc6091d0e6b41083.jpg!small?1640934854378

熟悉 Java 反序列化的同学也可能都对 SerialDumper 非常熟悉,通常,我们能直接查看一个 ACED 二进制流的工具并不多

SerialDumper 是 Java 反序列化漏洞大热的时候 toptensoftware 开源的一款序列化分析工具。

复杂案例(一):“可读化”CC1 利用链

当然,如果仅仅只能序列化一个 TC_STRING 其实是很鸡肋的。我们尝试一些更复杂的序列化流。

笔者使用

java -jar ysoserial.jar CommenCollections1 "YAKITEXT" > cc1.ser && yak hex -f cc1.ser

当然 yak hex 命令是 yak 引擎自带的小工具,可以把一个文件以十六进制的形式打印出来。不安装 yak 也有很多种办法可以做到。

1640935455_61ceb01f1c7b72a91be43.jpg!small?1640935456412

1640935464_61ceb0286184d3c78950f.jpg!small?1640935465848

1640935493_61ceb045983544f52a587.png!small?1640935495676

1640935678_61ceb0fe1f984d1dd7da2.png!small?1640935681029

1640935700_61ceb114c4e1ab2e744ea.png!small?1640935703156

1640935743_61ceb13f4895a997f5799.png!small?1640935743866

1640935771_61ceb15b257c6987c2db2.png!small?1640935773863


复杂案例(二):CC1 利用链与 JSON 互可逆

当然,我们发现,仿 SerialDumper 的实现在大多数时候,虽然可读性增强了,但是并不可逆,我们针对这种情况,实现了 ACED 反序列化流与 JSON 的互转。

虽然在 “从一片落叶开始” 中,我们已经发现了这个特性,但是还不够复杂,实战 ysoserial 的案例的展示更有那味儿。

1640936053_61ceb2751768bfe93abaa.png!small?1640936054909

1640936078_61ceb28e1bb16ff9c6755.png!small?1640936080639

1640936159_61ceb2df12acd57bc31df.png!small?1640936161505

1640936137_61ceb2c9c2eeff18ef2e1.png!small?1640936139791

1640936400_61ceb3d06aa9865b3dc37.png!small?1640936402907

1640936426_61ceb3eaf1c04a8b54a0e.png!small?1640936427798

1640936455_61ceb4073199c47808a6d.png!small?1640936457378


额外说明:虽然大多数大家看到的反序列化后的对象都是 TC_XXX 开头的对象,但是偶尔会出现 X_CLASSDATA 这类 ‘X’ 开头的对象名称,这些并不是 Java 中的,而是 yaklang.io 为了方便让其对象更容易可逆互转人为进行了结构分割。


结语与意外

“最后几块拼图” 其实说的是作为一个常年和漏洞扫描算法与扫描装置斗争的代码崽,尝试花一点时间来做“最后一英里”的事情。其实这个思路和操作并不是独一无二的,世界上并没有那么多 “独一无二” 的东西可以给大家来搞。

在完成这个模块的时候,我和 @phith0n P 牛提起这个事儿,他:“卧槽?我也写了一个这玩意”。
嗯...
果然在没有任何预兆的情况下和大家撞车了。

当然,对 P 师傅来说,这个项目还不够深入,比如,Java 字节码本质上也可以变成这样的形式,这一块因为各种原因,还没来得及实现完毕,也算是遗憾;在后续的项目中,我们团队也会进行 Java 字节码的生成的工作。

但是对于 yaklang.io 来说,这个项目并不是结束,我们基于这个项目可以做非常优秀的扩展

  1. 更安全,平台无关的 ysoserial payload generator 的实现
  2. 更安全的 RMI Exploit

回到项目刚开始和大家讲的,我们要做 “安全能力基座”,拼图当然要拼完。

当然,Java 序列化流分析也只是一部分,yak 语言也将会开放 java 各种序列化流处理和分析的接口,方便大家随时使用与集成。

Version Note:

  1. Yakit 版本 >= Yakit 1.0.11-sp6
  2. yak 核心引擎 >= 1.0.11-sp9

大家在安装最新版本的 Yakit 和 yak 核心引擎的之后,就可以使用本文录屏和截屏中的 Java 序列化流分析工具(Codec => Java)。

Reference

SerialDumper (hxxps://github[dot]com/toptensoftware/serialdump)
Java序列化协议 https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html

END

Yakit下载地址:https://github.com/yaklang/yakit

# java反序列化 # 编程语言 # yakit
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录