版本范围:
9.0.0.M1 <= tomcat <= 9.0.98
10.1.0-M1 <= tomcat <= 10.1.34
11.0.0-M1 <= tomcat <= 11.0.2
需要满足一下条件:
1.
conf/context.xml添加,设置session会话永久存储到本地文件,默认是存在内存中。
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore"/>
</Manager>
2.
conf/web.xml,默认是true走不到我们的代码
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
3.
最关键的点,就是存在一个可以反序列化的库如cc(commons-collections-3.2.1.jar),这里通过lib或者pom.xml导入都可以。
漏洞原因:
采用了历史漏洞的组合,后面也会讲
CVE-2017-12615 Tomcat PUT ⽂件上传
CVE-2020-9484:Tomcat Session 反序列化漏洞
CVE-2024-50379 :Tomcat PUT 条件竞争⽂件上传
首先我们去看PUT请求那也就是Tomcat里面的Servlet,DefaultServlet#doPut(图一),其中属性readOnly,
就是web.xml设置的默认是true就不会走到else这里设置之后会先获取请求URL,getRelativePath里面获取Servlet路径(图四),
之后走到getResource方法里做一些基础路径判断,接着就是parseContentRange方法,
这个比较关键因为在图一340行中默认是相等的走不到else里面,所以我们进去看看图二,首先设置数据包头
Content-Range,接着ContentRange.parse图三,里面会获取头的内容我么设置成bytes 0-1000000/1就行了因为图二中还会
获取是不是bytes开头,写小了会写入不全具体可以自己分析一下,下面就是executePartialPut,这里面存在路径判断就是说比如
你想跳目录使用../会转换成...把反斜杠转换成点(图三)。
再上图图三中可以看到374行进行创建文件createNewFile(),就是说要是文件创建成功deleteOnExit(),JVM 退出时自动删除,
奥对了再就是路径new File中tempDir代码
File tempDir = (File)this.getServletContext().getAttribute("javax.servlet.context.tempdir");
指定的,不同操作系统位置不同,下面就是写入操作了,412和413行就直接写入了,到这里写入内容就结束了。
接下来就需要看session进行反序列化了,既然说到反序列化那就要导入组件了,就拿cc6打吧,
FileStore#load方法导致反序列化,首先能走到load是因为我们配置了context.xml,这里看下面图一
改变了context.getManager();所以后面到了load,接着我们看load这个方法(图二),这个file方法就是让文件后面多了一个
session(图三),如.ceshi.session,那么前面这个点就是我们最开始讲的会把反斜杠换成点,要是不清楚说明你没有好好看,
在之后就会走到图二中139行session.readObjectData(ois);。
上面我们得知会走进session.readObjectData(ois);这个猜测看就是进行反序列化的,跟进去看看下面图一,
接着看doReadObject,图二直接原生反序列化了,结束。
这里面有个小坑就是在不做任何编码下发送数据包会因为编码或者其他因素导致反序列化失败,不得不说Yakit可以直接指定文件使用
下面图一,这里会直接写入我们的反序列化内容,在接着触发反序列化,其实也可以不发送数据包都可以,
图二中我们触发反序列化,成功RCE。