新型 tomcat websocket 内存马检测与防护思路探究
2023-4-23 00:3:15 Author: LemonSec(查看原文) 阅读量:30 收藏

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

websocket 内存马原理

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

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

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

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

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

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

检测思路

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

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

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

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

其中的 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")));
}
%>

效果如下:

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

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

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

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

总结

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

参考链接

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

原文:https://www.freebuf.com/articles/web/339361.html转自:网络安全者
侵权请私聊公众号删文

 热文推荐  

欢迎关注LemonSec
觉得不错点个“赞”、“在看“

文章来源: http://mp.weixin.qq.com/s?__biz=MzUyMTA0MjQ4NA==&mid=2247545688&idx=2&sn=16783cfe34fdb921a4ec119c88bb09a4&chksm=f9e35c03ce94d5156e4a70f7d708970de0ff0b3baf72b80f21bd853316169034a67397be853c#rd
如有侵权请联系:admin#unsafe.sh