新型 tomcat websocket 内存马检测与防护思路探究
2022-7-17 11:2:57 Author: www.freebuf.com(查看原文) 阅读量:32 收藏

最近,看到网上有安全研究人员发布了一篇文章,描述了一款在 tomcat的全新内存马,地址为:https://www.iculture.cc/forum-post/19128.html,该内存马基于 websocket协议,有别于目前已知的见的filter型内存马、servlet 型内存马,该类型的网马从形式上还有功能上都是非常新颖的,且根据该作者描述,目前常规的内存马扫描工具(如memshell scanner)无法检测出该类型的内存马。为此,笔者对该内存马的原理进行了分析,并在此提出了一种检测该内存马的思路,可以帮助安全人员检测出此种类型内存马,从而降低业务系统安全隐患。

websocket 内存马原理

Tomcat 服务器在启动时会通过WsSci中的 WsServerContainer 将 classpath 注解下带有@ServerEndpoint的类加入到 websocket 服务中。如:
image

通过调试可以看到添加位置如下:
image

对该段代码进行分析,注册 websocket 服务步骤如下,
首先要初始化一个WsServerContainer
image

通过扫描 classpath 下的带注解的类并加入一个 iterator 之中,
image

然后遍历该列表,针对每个元素,然后创建一个 ServerEndpointConfig ,然后通过 addEndpoint 将该类加入到websocket服务之中。

image

至此,就将一个ws节点加入的服务中,根据这个思路,攻击者也可以利用这种方式在运行时动态注入ws节点,注入的思路与此一致,该类型内存马作者也给出了代码,此处不再过多叙述。

检测思路

既然是内存马,那在内存中肯定会有实体,所以只要找到存储该实体的位置,就能检测出此类内存马。

下面通过动态调试分析该实体的具体存储位置,前面提到,最终是通过 addEndpoint 函数将该内存马实体加入到ws服务中,于是跟进该函数,

image

在 addEndpoint 中,通过(WsServerContainer.ExactPathMatch)this.configExactMatchMap.put(path, newMatch)加入到一个名为configExactMatchMap的 Map 之中,进一步查看该成员变量定义:

image

是一个Map<String, WsServerContainer.ExactPathMatch>的类型,通过调试可知,该 map 的 key 就是对应 ws 服务的 url, 后面的WsServerContainer.ExactPathMatch则存放了ws服务的实体,该类定义如下:
image

其中的 config 变量就是之前扫描注解时生成的实体类。

于是,检测思路就呼之欲出了: 找到对应 context 的 configExactMatchMap, 里面保存了所有注册的 ws 服务,每个服务就是该map中的一个元素。

笔者写了一个简单的 jsp 检测脚本,访问该 jsp 就能打印出所有的 ws 服务。

<%@ page import="org.apache.tomcat.websocket.server.WsServerContainer" %>
<%@ page import="javax.websocket.server.ServerContainer" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.Set" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="javax.websocket.server.ServerEndpointConfig" %><%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
  // 通过 request 的 context 获取 ServerContainer
  WsServerContainer wsServerContainer = (WsServerContainer) request.getServletContext().getAttribute(ServerContainer.class.getName());

  // 利用反射获取 WsServerContainer 类中的私有变量 configExactMatchMap
  Class<?> obj = Class.forName("org.apache.tomcat.websocket.server.WsServerContainer");
  Field field = obj.getDeclaredField("configExactMatchMap");
  field.setAccessible(true);
  Map<String, Object> configExactMatchMap = (Map<String, Object>) field.get(wsServerContainer);

  // 遍历configExactMatchMap, 打印所有注册的 websocket 服务
  Set<String> keyset = configExactMatchMap.keySet();
  Iterator<String> iterator = keyset.iterator();
  while (iterator.hasNext()){
    String key = iterator.next();
    Object object = wsServerContainer.findMapping(key);
    Class<?> wsMappingResultObj = Class.forName("org.apache.tomcat.websocket.server.WsMappingResult");
    Field configField = wsMappingResultObj.getDeclaredField("config");
    configField.setAccessible(true);
    ServerEndpointConfig config1 = (ServerEndpointConfig)configField.get(object);
    Class<?> clazz = config1.getEndpointClass();

    // 打印 ws 服务 url, 对应的 class
    out.println(String.format("websocket name:%s,  websocket class: %s", key, clazz.getName()));
  }

  // 如果参数带name, 删除该服务,名字为name参数值
  if(request.getParameter("name")!= null){
    configExactMatchMap.remove(request.getParameter("name"));
    out.println(String.format("delete ws service: %s", request.getParameter("name")));
  }
%>

效果如下:

image

如果想要删除一个ws服务,直接将该实体从map中移除即可,

configExactMatchMap.remove(request.getParameter("name"));

通过该jsp就是在后面加入?name=websocket服务名字即可:

image

再此访问检测工具,该服务已经删掉:

image

总结

本文通过分析该新型内存马原理,提出了对应的检测思路,并实现了一个简陋的内存马检测代码和内存马删除代码,希望该方法能够帮助有此需求的同行安全运维人员,也希望能够抛砖引玉,开展更为深入的讨论。

参考链接

https://www.iculture.cc/forum-post/19128.html
https://juejin.cn/post/7095918534210879519


文章来源: https://www.freebuf.com/articles/web/339361.html
如有侵权请联系:admin#unsafe.sh