前言
在某次实战中遇到了java原生反序列化入口点,由于这套系统之前知道有CB链,准备用CB2一把梭哈时,遇到了RASP拦截,于是便有了这次戴着镣铐跳舞的故事。
判断检测原理
当使用CB链攻击时,目标报错

使用反序列化炸弹(FindClassByBomb)时,正常反序列化成功,产生超长延时。说明目标RASP的拦截逻辑并非时阻拦反序列化,而是阻拦其所认为“恶意类”的反序列化。那么此处就存在绕过空间。

寻找可用链-Tomcat Reference初试
同事在测试常用链后给出了情报,C3P0链可用,但坏消息是目标不出网,因此无法直接通过出网RCE。
C3P0反序列化链有两种玩法,第一种玩法:出网拉URLClassLoader,实例化远程恶意类去RCE。第二种玩法:通过本地可用的Reference去RCE。首先我们想到了Tomcat的org.apache.naming.factory.BeanFactory类,通过org.apache.naming.factory.BeanFactory调用EL表达式执行代码,这是在jndi注入时如果目标存在Tomcat8+并且jdk高版本时的一种绕过方式,不了解的可以见:https://paper.seebug.org/942/#classreference-factory。
此时构造了第一个反序列化生成脚本
1 | import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase; |
这时候我们遇到了第一个问题,发送exp后报错如下:

首先我们怀疑这不是Tomcat系统,但仔细看了下堆栈,这无疑就是Tomcat

于是我通过FindClassByBomb链探测了org.apache.naming.factory.BeanFactory类,发现该类存在。矛盾的结论迫使我去翻看C3P0的代码
com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized#getObject

com.mchange.v2.naming.ReferenceableUtils#referenceToObject

从这里看没什么毛病,ClassLoader是Thread.currentThread获取的,肯定能获取到中间件中的类。于是我怀疑目标的C3P0的代码是不是不和我们一样,于是我找了一个老版本的C3P0的Jar包,发现其com.mchange.v2.naming.ReferenceableUtils#referenceToObject代码如下

显然老版本用的是系统类加载器,这个加载器是获取不到中间件的类的,所以我们目标应当是这种情况。不过路也不是完全不通,从上面代码看,如果fClassLocation如果不是空,那么会通过一个URLClassLoader去加载类。此时我才开始认真的研究序列化生成的脚本
1 | ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", null); |
首先映射一下序列化内容和referenceToObject方法参数的对应关系:
org.apache.naming.factory.BeanFactory –>fClassName
ResourceRef对象最后一个参数null –> fClassLocation
所以这个URLClassLoader的索引路径我们是可以在序列化过程中指定的,org.apache.naming.factory.BeanFactory类是在catalina.jar中,在黑盒情况下如何索引到目标catalina.jar的位置?
CTF,启动!!!
在linux中,Tomcat的JVM环境下:
1 | /proc/self/cwd --> /xxx/xxx/xxx/apache-tomcat-xxx/webapps |
因此通过下面的序列化代码可以索引到catalina.jar
1 | ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", file:///../../../../../../../../../../../../proc/self/cwd/../lib/catalina.jar); |
此时出现了新的报错,但好像消息是org.apache.naming.factory.BeanFactory已经被索引到了。而我们研究了报错的这段代码后发现,这个报错应当是不影响javax.el.ELProcessor被触发的。

于是再次确认后发现,目标没有javax.el.ELProcessor这个类,也就说明目标很可能是Tomcat7及以下
随后我想到了浅蓝师傅曾经发过一篇文章:https://tttang.com/archive/1405/#toc_nativelibloader,给出了替换javax.el.ELProcessor的一些方式。但实测后发现,例如:Xstream/Groovy等目标环境都没有。到此刻为止路又断了。
FileUpload链+组合拳
在我不断测试后发现,FileUpload1链没有引发目标的RASP拦截,但我也不确定到底有没有利用成功,因此我随便发了个包测试了下

收到报错,说明确实成功了,但文件名看起来无法预测

此时我想到了前段时间网上很火的mysql connect不出网利用,他也用到了commons-fileuploads,根据其理论,每次上传后文件名只会变动UniqueId部分,而这部分是自增的,该理论我搭建环境复线后发现确实如此。因此我只要FileUpload链写一次不存在目录触发报错,获得upload_b85a4be8_6ea8_4917_939e_f1de9bddd780_00000097.tmp
然后我在用FileUpload链写文件,那么此时这个临时文件的名字就为upload_b85a4be8_6ea8_4917_939e_f1de9bddd780_00000098.tmp

截止目前为止,获取到的所有信息如下:
1、C3P0链可以反序列化本地Reference
2、FileUpload链可以用,该链写文件时会在/tmp下生成一个临时文件,此文件名和后缀均不可控,但能通过技巧预测到文件名。
而同时我们上文提到,C3P0在反序列化过程中使用了URLClassLoader加载类并实例化,这个路径和类名是可控的,于是我设计了一种方案:
1、本地生成一个恶意的jar包,代码如下

2、通过FileUpload写入上面这个jar,此时/tmp/目录下会生成一个tmp文件

3、写不存在目录触发报错获得upload_b85a4be8_6ea8_4917_939e_f1de9bddd780_00000097.tmp

4、重复步骤2,此时这个jar在目标上会生成,同时其绝对路径为/tmp/upload_b85a4be8_6ea8_4917_939e_f1de9bddd780_00000098.tmp
5、修改序列化脚本如下,然后再发一次C3P0的反序列化包
ResourceRef resourceRef = new ResourceRef(“javax.el.ELProcessor”, (String)null, “”, “”, true, “com.test”, file:///tmp/upload_b85a4be8_6ea8_4917_939e_f1de9bddd780_00000098.tmp);
调用到newInstance,触发我们的恶意代码,最终完成RCE~
从回包来看,延时5秒,后面把恶意jar中的代码换成内存马注入代码即获取到webshell

后话
后面拿到shell后验证发现,其实FileUpload链在目标利用是有问题的,因为正常的FileUpload链是可以指定目录和文件名写的,而目标却无法写入,只是commons-fileupload这个包恰好会生成临时文件,然后这个点被我们抓到了而已。