深入淺出記憶體馬(一)
在Web安全領域,Webshell一直是一個非常重要且熱門的話題。在目前傳統安全領域,Webshell根據功能的不同分為三種類型,分别是:一句話木馬,小馬,大馬。而根據現在防火牆技術的更新疊代,随後出現了加密的木馬技術,比如:加密一句話。而我們今天要說的是一種新的無檔案的Webshell類型:記憶體馬。
傳統Webshell連接配接方式,都是先通過某種漏洞将惡意的腳本木馬檔案上傳,然後通過中國菜刀,或者蟻劍,冰蠍等Webshell管理軟體進行連結。

這種方式目前仍然流行,但是由于近幾年防火牆,IDS,IPS,流量分析等各種安全裝置的普及和更新,這種連接配接方式非常容易被裝置捕獲攔截,而且由于檔案是明文存放在伺服器端,是以又很容易被防毒軟體所清除。在今天看來這種傳統連接配接方式顯然已經過時,于是乎,進化了一系列的加密一句話木馬,但是這種方式還是不能繞過有類似檔案監控的防毒軟體,于是乎進化了新一代的Webshell---》記憶體馬
記憶體馬是無檔案Webshell,什麼是無檔案webshell呢?簡單來說,就是伺服器上不會存在需要連結的webshell腳本檔案。那有的同學可能會問了?這種方式為什麼能連結呢?記憶體馬的原理就像是MVC架構,即通過路由通路控制器,我通過自身的了解,概述的說一下, 記憶體馬的原理就是在web元件或者應用程式中,注冊一層通路路由,通路者通過這層路由,來執行我們控制器中的代碼
目前分為兩種:
Servlet-API型
通過指令執行等方式動态注冊一個新的listener、filter或者servlet,進而實作指令執行等功能。特定架構、容器的記憶體馬原理與此類似,如spring的controller記憶體馬,tomcat的valve記憶體馬
filter型
servlet型
位元組碼增強型
通過java的instrumentation動态修改已有代碼,進而實作指令執行等功能。
spring類
攔截器
Controller型
我們以Java Web舉例,在Java Web中有三大元件分别是Servlet, Filter,Listener
Servlet 是運作在 Web 伺服器或應用伺服器上的程式,它是作為來自 HTTP 用戶端的請求和 HTTP 伺服器上的資料庫或應用程式之間的中間層。它負責處理使用者的請求,并根據請求生成相應的傳回資訊提供給使用者。
Servlet程式是由WEB伺服器調用,web伺服器收到用戶端的Servlet通路請求後:
Web伺服器首先檢查是否已經裝載并建立了該Servlet的執行個體對象。如果是,則直接執行第4步,否則,執行第2步。
裝載并建立該Servlet的一個執行個體對象。
調用Servlet執行個體對象的init()方法。
建立一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然後調用Servlet的service()方法并将請求和響應對象作為參數傳遞進去。
WEB應用程式被停止或重新啟動之前,Servlet引擎将解除安裝Servlet,并在解除安裝之前調用Servlet的destroy()方法。
Filter譯為過濾器。過濾器實際上就是對web資源進行攔截,做一些處理後再交給下一個過濾器或servlet處理,通常都是用來攔截request進行處理的,也可以對傳回的response進行攔截處理。
web伺服器根據Filter在web.xml檔案中的注冊順序,決定先調用哪個Filter,當第一個Filter的doFilter方法被調用時,web伺服器會建立一個代表Filter鍊的FilterChain對象傳遞給該方法。在doFilter方法中,開發人員如果調用了FilterChain對象的doFilter方法,則web伺服器會檢查FilterChain對象中是否還有filter,如果有,則調用第2個filter,如果沒有,則調用目标資源。
生命周期
監聽器用于監聽Web應用中某些對象的建立、銷毀、增加,修改,删除等動作的發生,然後作出相應的響應處理。當監聽範圍的對象的狀态發生變化的時候,伺服器自動調用監聽器對象中的方法。常用于統計網站線上人數、系統加載時進行資訊初始化、統計網站的通路量等等。
主要由三部分構成:
事件源:被監聽的對象
監聽器:監聽的對象,事件源的變化會觸發監聽器的響應行為
響應行為:監聽器監聽到事件源的狀态變化時所執行的動作
在初始化時,需要将事件源和監聽器進行綁定,也就是注冊監聽器。
可以使用監聽器監聽用戶端的請求、服務端的操作等。通過監聽器,可以自動出發一些動作,比如監聽線上的使用者數量,統計網站通路量、網站通路監控等。
在 Tomcat 中,每個 Host 下可以有多個 Context (Context 是 Host 的子容器), 每個 Context 都代表一個具體的Web應用,都有一個唯一的路徑就相當于下圖中的 /shop /manager 這種,在一個 Context 下可以有着多個 Wrapper
Wrapper 主要負責管理 Servlet ,包括的 Servlet 的裝載、初始化、執行以及資源回收
通過上面的介紹,我們已經大緻了解記憶體馬的背景知識,現在我們來講解Tomcat Filter類型的記憶體馬,看看這種流程是什麼樣子的?
建立filter
Web.xml配置
就是我們建立一個servlet和一個filter 通路路由都是為<code>/hello</code> 。看下結果:
控制台輸出
我們簡單調試一下
對應Web.xml中的配置資訊,這種方式就是為靜态的添加filter的方式,filter實作分為靜态和動态,靜态就是上述中,普通配置在web.xml或者通過@注釋配置在類中的。
關于整個Filter的調用鍊 可以參考:https://mp.weixin.qq.com/s/YhiOHWnqXVqvLNH7XSxC9w, 這個不是我們主要講述的重點。
Filter調用鍊,可以引用寬位元組安全總結的一張圖來說明:
我們調試一下filterChain.doFilter() 方法,啟動服務,然後通路<code>/hello</code>即可調試:
繼續跟進,可以看到<code>doFilter()</code> 的具體處理過程是在<code>internalDoFilter()</code>
然後最後調用<code>service()</code>方法去調用這個filter裡面的内容
概述地說, <code>FilterChain.doFilter()</code> 方法将調用下一個 Filter.doFilter() 方法;最後一個 <code>Filter.doFilter()</code> 方法中調用的<code>FilterChain.doFilter()</code> 方法将調用目标 <code>Servlet.service()</code> 方法。
上面的描述總結下來就是如何在tomcat中動态的注入一條配置項和代碼,拿filter類型舉例子,那麼我們如何建立一個Filter類型的記憶體馬呢?
首先建立一個惡意Filter
利用 FilterDef 對 Filter 進行一個封裝
将 FilterDef 添加到 FilterDefs 和 FilterConfig
建立 FilterMap ,将我們的 Filter 和 urlpattern 相對應,存放到 filterMaps中(由于 Filter 生效會有一個先後順序,是以我們一般都是放在最前面,讓我們的 Filter 最先觸發)
每次請求createFilterChain都會依據此動态生成一個過濾鍊,而StandardContext又會一直保留到Tomcat生命周期結束,是以我們的記憶體馬就可以一直駐留下去,直到Tomcat重新開機。
好的 那我們首先來編寫一個filter的惡意類
運作效果:
可以看到這個就是在tomcat中沒有任何shell檔案,但是在過濾器中執行了我們的代碼。
那麼真實情況下,我們不可能直接修改項目中Filter的源碼,因為就算修改了,想要生效也需要重新開機。是以我們需要動态的插入filter,那我們該如何操作呢?
最終代碼如下:
通路這個頁面
最後直接通路任意Servlet路由都可以執行指令
即使删除我們的注入檔案<code>filterdemo1.jsp</code>也是一樣可以執行,這樣就可以達到無檔案的Webshell管理方式了。