Tomcat CVE-2023-41080 分析与复现
0x00 前言 最近在看tomcat CVE-2023-41080,想起来这个cve还没有人怎么调过,我来浅浅研究下 0x01 复现 稳定触发需要先行访问登录页面,第一步不要登陆 http://target/ 再重开窗口访问构造的POC http://target//www.baidu.com 最后再在第一步的tomcat的表单登录页面提交登录,提交账号和密码之后浏览器会跳转到baidu的
0x00 前言
最近在看tomcat CVE-2023-41080,想起来这个cve还没有人怎么调过,我来浅浅研究下
0x01 复现
- 稳定触发需要先行访问登录页面,第一步不要登陆
http://target/

- 再重开窗口访问构造的POC
http://target//www.baidu.com - 最后再在第一步的tomcat的表单登录页面提交登录,提交账号和密码之后浏览器会跳转到baidu的网址

注:是目前比较稳定触发的是firefox和老版本的chrome, 新版本的chrome不太稳定。
0x02 补丁分析
版本对比分析可得知,过滤在formauthenticator.java中增加了路径校验,也就是在路径长度大于2的情况下,如果第二个字符是斜杠号/,则删除该斜杠号。比如说,如果访问的路径是http://target//test,未打补丁之前是字符串是//test在经过补丁代码后就变成了/test
https://github.com/apache/tomcat/compare/9.0.79...9.0.80

结合官方公开的漏洞信息表明,该漏洞是跳转漏洞,在经过测试后发现,可以通过可以通过控制访问路径来控制跳转目标,比如正常的控制服务器的返回包中的location字段,浏览器在接受到返回包之后会跳转到test路径
HTTP/1.1 303
Set-Cookie: JSESSIONID=10784C4217959B843EAB1310C4428C36; Path=/; HttpOnly
Location: /test/
Content-Length: 0
Date: Tue, 12 Mar 2024 06:40:17 GMT
Connection: close
但如果想要跳转到baidu的网站,则需要给location字段赋值
HTTP/1.1 303
Set-Cookie: JSESSIONID=10784C4217959B843EAB1310C4428C36; Path=/; HttpOnly
Location: http://www.baidu.com
Content-Length: 0
Date: Tue, 12 Mar 2024 06:40:17 GMT
Connection: close
问题的核心点在于,官方检测到第二个斜杠后会删除第一个字符串,最终逻辑是只允许一个斜杠号。经过搜索资料后发现,当location的字段内容的前两个字符是两个斜杠的时候,浏览器会自动跳转访问斜杠号后面的域名,如下边的返回包,浏览器自动访问百度
HTTP/1.1 303
Set-Cookie: JSESSIONID=10784C4217959B843EAB1310C4428C36; Path=/; HttpOnly
Location: //www.baidu.com
Content-Length: 0
Date: Tue, 12 Mar 2024 06:40:17 GMT
Connection: close
poc的特征到此已经很明显了,我们只需要控制最后一步用户提交完表单之后,服务器返包location当中存在我们想要跳转的目标网站就行
Location: //target
0x03 测试环境源代码构建分析&数据流跟踪
我这里在Webapp的ROOT目录下放了一个form表单提交的示例,目录结构如下

web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 安全限制配置 -->
<security-constraint>
<display-name>default</display-name>
<!-- 需要限制访问的资源子集 -->
<web-resource-collection>
<web-resource-name>all files</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<!-- 指定可以访问该资源集合的用户角色 -->
<auth-constraint>
<role-name>manager-gui</role-name>
</auth-constraint>
<!-- 用来显示怎样保护在客户端和Web容器之间传递的数据 -->
<!-- NONE 不需要传输保证 -->
<!-- INTEGRAL 服务器和客户端之间的数据必须以某种方式发送,而且在传送中不能改变 -->
<!-- CONFIDENTIAL 传输的数据必须是加密的数据 -->
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- 表单方式验证 -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>manager-gui</role-name>
</security-role>
</web-app>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>DEMO</title>
</head>
<body>
<h1>FORM 表单验证</h1>
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form method="post" action="j_security_check">
<p>
用户名:<input type="text" name="j_username" />
</p>
<p>
密 码:<input type="password" name="j_password" />
</p>
<p>
<button type="submit">登录</button>
</p>
</form>
</body>
</html>
从漏洞补丁点所在的函数savedRequestURL回溯,可以确定,数据流从用户端输入后,必须流向FormAuthenticator.java中,根据文档可知,FormAuthenticator主要负责表单的身份登录校验模块,因此我们还需要配置tomcat-user.xml
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<user username="tomcat" password="aaaaaa"
roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui"/>
</tomcat-users>
从逻辑上来讲,这就是针对跳转登录功能的一个bypass,正常情况下,开发者可以设置跳转到指定目录,但是我们可以通过location的一些奇怪的属性进行绕过直接跳转到别的网站去。
在黑盒视角下,整个利用过程如下,我们需要浏览器开两个标签,第一步先第一个标签是正常访问登录页面,第二步再开一个标签访问第poc url,第三步是在第一步返回的页面的基础上提交用户名密码,再配合前面分析的补丁部分对应的漏洞,即可完成跳转。

在白盒视角下,我们需要在先在存储session的容器中初始化并存储一个sessionid和该sessionid对应的requesturi(即跳转路径)。因此,访问了poc之后,在没有合法sessionid的情况下tomcat会初始化的sessionid,并存储对应的uri,以及返回这个sessionid。而当你提交用户名密码的时候,浏览器会携带你上一步得到的sessionid向tomcat验证表单用户名密码。

如果只看该图的流程,不禁要问,为什么要多一个流程呢,为什么不直接POC url(http://target//www.baidu.com)返回的登陆页面,直接登录呢?但是第一次触发的因为post提交的时候路径最开始有两个斜杠,这会导致直接跳转到favicon.ico。
0x04 一些问题
- 官方公告也讲了,需要根目录触发,很鸡肋,研究这个cve我也当作是加深对tomcat机制的理解了
- tomcat启起来的时候第一次直接
http://target//www.baidu.com提交用户名密码也可以跳转,但第二次就不行了,后续再仔细看看 - chrome最新版本貌似不太行,我用的firefox最新版本124.0.2和chrome老一点的版本可以
0x05 Reference
https://www.hxstrive.com/subject/tomcat/1636.htm
0x06 最后
还有些问题没解决,以及对tomcat理解不深,若有错误请师傅们指出,轻喷