废话不多说,直接复现
1、首先准备环境,受影响版本如下:
11.0.0-M1 <= Apache Tomcat < 11.0.2
10.1.0-M1 <= Apache Tomcat < 10.1.34
9.0.0.M1 <= Apache Tomcat < 9.0.98
我的环境:win10系统+tomcat9.097+jdk1.8
(必须是windows系统,该漏洞利用条件之一;关于jdk版本,个人感觉只要tomcat能运行应该没问题,但是网上说有的版本可能有问题)
2、漏洞利用条件:默认 Servlet 的 readonly 参数被设置为 false(非默认配置),该设置其实就是允许PUT的意思。这里我用的是eclipse搭建的web服务
3、环境准备OK,开搞前先讲一下该漏洞原理,网上好多文章说的云里雾里的,我来给大家说明白:
这是一个条件竞争引起的漏洞,先通过条件竞争(并发数据包)GET到上传的恶意脚本,实现你想搞什么就搞什么,那当然RCE了,所以市面上都称该漏洞为远程代码执行漏洞。
那么怎么个并发,怎么个条件竞争法,谁和谁在竞争,为什么要并发?这个就有点绕了,其实很好理解:
一、如果我们不搞并发,先PUT一个不符合标准的扩展名的.Jsp脚本,再去GET一个符合标准的.jsp脚本,那么是GET不到的,因为这个过程经历了完全的安全检查和路径匹配,tomcat压根不会指到刚才PUT进去的.Jsp,因为你访问的是符合标准的.jsp,尽管windows文件系统不分,但是tomcat会区别。这种情况下一切按顺序进行,不存在任何时间窗口。
二、当我们并发PUT和GET时,情况就不一样了,文件还没落地,随时存在变数。在.Jsp被PUT进去的一瞬间,GET也在同步快速进行,并且GET是合法的,windows文件系统由于不区分大小写,被一瞬间PUT进去的.Jsp文件立马被GET触发编译执行,而另外一个原本优先的层面(或线程)需要进行安全检查和路径匹配,完全的安全检查需要时间(尽管很短暂,但是对于另一个线程来说就是时间窗口),因此编译执行和安全检查之间存在竞争,目的是在tomcat还未完成检查之前就解析执行了。
三、PUT 不停更新文件,另一边 GET 不停读取。安全检查和实际资源访问之间有时间差。在通过安全检查后,Tomcat还会执行一些其他操作(如加载文件或编译JSP)。如果这期间资源状态被攻击者修改,Tomcat可能会直接处理未被检查的新资源,从而绕过安全限制。这种感觉有点像“调包”!
四、PUT不符合标准扩展名的.Jsp文件:为了绕过 JSP Servlet 的后缀匹配规则,使其由默认 Servlet 处理,这样就能落地。
4、开搞!我用的BP并发PUT包,批处理脚本并发GET包。
这里我PUT一个反弹shell的代码进去,用我闲置的云主机接受反弹shell:
批处理脚本:不停地GET d.jsp,返回200立马暂停
云主机准备好监听,Go!
返回200,成功反弹shell到我的云主机:
验证稳定性,执行命令,没问题:
至此,成功复现该漏洞。