前言
参考:
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