版本信息
Tomcat测试版本:7.0.79
漏洞影响全部的 Tomcat 版本:Apache Tomcat 7.0.0 – 7.0.79 (windows环境)
漏洞分析
在tomcat官网下载一个Tomcat7的源码压缩包,打开来慢慢看看里面的.xml文件
与java代码
。
关键配置
配置文件路径
apache-tomcat-7.0.10-src\conf\web.xml
DefaultServlet
类处理除了JSP文件以外的静态资源
<!-- The default servlet for all web applications, that serves static -->
<!-- resources. It processes all requests that are not mapped to other -->
<!-- servlets with servlet mappings (defined either here or in your own -->
<!-- web.xml file). This servlet supports the following initialization -->
<!-- parameters (default values are in square brackets): -->
readonly
默认为true
,在(CVE-2017-12615)的情况下为false
。
<!-- readonly Is this context "read only", so HTTP -->
<!-- commands like PUT and DELETE are -->
<!-- rejected? [true] -->
servlet-name:default
对应的是servlet-class:DefaultServlet
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
JspServlet
类负责JSP文件的汇编与运行
<!-- The JSP page compiler and execution servlet, which is the mechanism -->
<!-- used by Tomcat to support JSP pages. Traditionally, this servlet -->
<!-- is mapped to the URL pattern "*.jsp". This servlet supports the -->
<!-- following initialization parameters (default values are in square -->
<!-- brackets): -->
servlet-name:jsp对应的是servlet-class:JspServlet
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
servlet-mapping主要是截获请求的:
-
- 如果
url-pattern
定义的是路径,那么以后所有对这个路径下资源的请求都会由servlet-name
中定义的servlet
处理; - 如果你的
url-pattern
定义的是资源格式例如*.jsp
等,那么对于所有符合这种格式的资源的请求都由指定的servlet
处理。
- 如果
这里说明了/
类型的资源都由servlet-name:default
处理,*.jsp
与*.jspx
类型的资源都由servlet-name:jsp
处理
<!-- ================ Built In Servlet Mappings ========================= -->
<!-- The servlet mappings for the built in servlets defined above. Note -->
<!-- that, by default, the CGI and SSI servlets are *not* mapped. You -->
<!-- must uncomment these mappings (or add them to your application's own -->
<!-- web.xml deployment descriptor) to enable these services -->
<!-- The mapping for the default servlet -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
代码分析
DefaultServlet.java
文件路径
apache-tomcat-7.0.10-src\\java\\org.apache\\catalina\\servlets\\DefaultServlet.java
受影响的doPut
函数
/**
* Process a PUT request for the specified resource.
*
* @param req The servlet request we are processing
* @param resp The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
String path = getRelativePath(req);
boolean exists = true;
try {
resources.lookup(path);
} catch (NamingException e) {
exists = false;
}
boolean result = true;
// Temp. content file used to support partial PUT
File contentFile = null;
Range range = parseContentRange(req, resp);
InputStream resourceInputStream = null;
// Append data specified in ranges to existing content for this
// resource - create a temp. file on the local filesystem to
// perform this operation
// Assume just one range is specified for now
if (range != null) {
contentFile = executePartialPut(req, range, path);
resourceInputStream = new FileInputStream(contentFile);
} else {
resourceInputStream = req.getInputStream();
}
try {
Resource newResource = new Resource(resourceInputStream);
// FIXME: Add attributes
if (exists) {
resources.rebind(path, newResource);
} else {
resources.bind(path, newResource);
}
} catch(NamingException e) {
result = false;
}
if (result) {
if (exists) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.setStatus(HttpServletResponse.SC_CREATED);
}
} else {
resp.sendError(HttpServletResponse.SC_CONFLICT);
}
}
动态调试
进入doPut
函数,上传的文件名为12w3.jsp/
,可以看到readOnly==false
因为12w3.jsp/不存在服务器中,所以调用bind函数进行写入。进入resources.bind函数
进入dirContext.bind函数
进入bind函数
传入的name参数为/12w3.jsp/,在File函数中会将name中的/去除,进入File函数进行查看
child==/12w3.jsp/,由fs.normalize函数处理,进入fs.normalize函数
normalize(path)函数中调用normalize(path, len, off)函数对/进行处理,进入normalize(path, len, off)函数
normalize(path, len, off)函数对path处理完后,返回\12w3.jsp
从File
函数中出来,把name==/12w3.jsp/
传进rebind函数,进入rebind
函数
在rebind
函数中调用File
函数获得完整路径F:\\Tomcat\\apache-tomcat-7.0.79\\webapps\\ROOT\\12w3.jsp
将文件内容写入F:\\Tomcat\\apache-tomcat-7.0.79\\webapps\\ROOT\\12w3.jsp
文件
上传完成。
漏洞利用
访问Tomcat主页,抓包
右击,选择send to repeater
修改红框中的内容:
- 将
GET
请求改为PUT
- 添加文件名
backdoor.jsp/
(注意后面要添加/
) - 添加文件内容
点击send
发送。查看response
,文件创建成功。
查看Tomcat根目录,多了一个backdoor.jsp
,上传成功。
参考文章
配置Tomcat7:https://www.freebuf.com/articles/others-articles/258885.html
IDEA远程调试Tomcat:https://www.freebuf.com/sectool/258891.html
利用PUT方法的多种方法:https://wh0ale.github.io/2018/12/23/2018-12-23-利用PUT方法的多种方法/
servlet-mapping干什么用的:https://zhidao.baidu.com/question/538577773.html
seebug:https://paper.seebug.org/399/
来源:freebuf.com 2020-12-26 20:08:15 by: 小汽油
请登录后发表评论
注册