近期,看到網(wǎng)上有安全研究人員發(fā)布了一篇文章,描述了一款在Tomcat的全新內(nèi)存馬,地址為:https://www.iculture.cc/forum-post/19128.html,該內(nèi)存馬基于Websocket協(xié)議,有別于目前已知常見的filter型內(nèi)存馬、servlet型內(nèi)存馬,該類型的網(wǎng)馬從形式上還有功能上都是非常新穎的,且根據(jù)描述,目前常規(guī)的內(nèi)存馬掃描工具(如 Memshell Scanner)無法檢測出該類型的內(nèi)存馬。為此,對該內(nèi)存馬的原理進(jìn)行了分析,并在此提出了一種檢測該內(nèi)存馬的思路,可以幫助安全人員檢測出此種類型內(nèi)存馬,從而降低業(yè)務(wù)系統(tǒng)安全隱患。 | ||
Websocket 內(nèi)存馬原理 | ||
Tomcat服務(wù)器在啟動時會通過 WsSci 中的 WsServerContainer 將 classpath 注解下帶有 @ServerEndpoint 的類加入到 Websocket 服務(wù)中。如: | ||
通過調(diào)試可以看到添加位置如下: | ||
對該段代碼進(jìn)行分析,注冊websocket服務(wù)步驟如下, 首先要初始化一個 WsServerContainer , | ||
通過掃描 classpath 下的帶注解的類并加入一個 iterator 之中, | ||
然后遍歷該列表,針對每個元素,然后創(chuàng)建一個 ServerEndpointConfig,然后通過 addEndpoint 將該類加入到 Websocket服務(wù)中。 | ||
至此,就將一個 ws 節(jié)點加入的服務(wù)中,根據(jù)這個思路,攻擊者也可以利用這種方式在運行時動態(tài)注入 ws 節(jié)點,注入的思路與此一致。 | ||
檢測思路 | ||
既然是內(nèi)存馬,那在內(nèi)存中肯定會有實體,所以只要找到存儲該實體的位置,就能檢測出此類內(nèi)存馬。 下面通過動態(tài)調(diào)試分析該實體的具體存儲位置,前面提到,最終是通過 addEndpoint 函數(shù)將該內(nèi)存馬實體加入到 ws 服務(wù)中,于是跟進(jìn)該函數(shù), | ||
在 addEndpoint 中通過 (WsServerContainer.ExactPathMatch)this.configExactMatchMap.put(path,newMatch) 加入到一個名為 configExactMatchMap 的 Map 之中,進(jìn)一步查看該成員變量定義: | ||
是一個 Map 的類型,通過調(diào)試可知,該 map 的 key 就是對應(yīng) ws 服務(wù)的 url, 后面的 WsServerContainer.ExactPathMatch 則存放了 ws 服務(wù)的實體,該類定義如下: | ||
其中的 config 變量就是之前掃描注解時生成的實體類。 于是,檢測思路就呼之欲出了:找到對應(yīng) context 的 configExactMatchMap, 里面保存了所有注冊的 ws 服務(wù),每個服務(wù)就是該 map 中的一個元素。 一個簡單的 jsp 檢測腳本,訪問該 jsp 就能打印出所有的 ws 服務(wù)。 | ||
<%@ 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 configExactMatchMap = (Map) field.get(wsServerContainer); // 遍歷configExactMatchMap, 打印所有注冊的 websocket 服務(wù) Set keyset = configExactMatchMap.keySet(); Iterator 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 服務(wù) url, 對應(yīng)的 class out.println(String.format("websocket name:%s, websocket class: %s", key, clazz.getName())); } // 如果參數(shù)帶name, 刪除該服務(wù),名字為name參數(shù)值 if(request.getParameter("name")!= null){ configExactMatchMap.remove(request.getParameter("name")); out.println(String.format("delete ws service: %s", request.getParameter("name"))); } %> | ||
效果如下: | ||
如果想要刪除一個 ws 服務(wù),直接將該實體從 map 中移除即可, configExactMatchMap.remove(request.getParameter("name")); | ||
通過該 jsp 就是在后面加入 | ||
再此訪問檢測工具,該服務(wù)已經(jīng)刪掉: | ||
|
||||
Copyright© 重慶秉通精益信息技術(shù)有限公司 | 渝公網(wǎng)安備 50010702502937號 | 渝ICP備2024028021號-1 聲明:本站部分內(nèi)容圖片來源于互聯(lián)網(wǎng),如有侵權(quán)請聯(lián)系管理員刪除,謝謝! |