內存🐎的檢測與排查
文章目錄
- 內存🐎的檢測與排查
- 查殺Java Web filter型內存馬
- 0x01 內存馬簡歷史
- 0x02 查殺思路
- 0x03 內存馬的識別
- 0x04 內存馬的查殺
查殺Java Web filter型內存馬
0x01 內存馬簡歷史
其實內存馬由來已久,早在17年n1nty師傅的《Tomcat源碼調試筆記-看不見的shell》中已初見端倪,但一直不溫不火。后經過rebeyong師傅使用agent技術加持后,拓展了內存馬的使用場景,然終停留在奇技淫巧上。在各類hw洗禮之后,文件shell明顯氣數已盡。內存馬以救命稻草的身份重回大眾視野。特別是今年在shiro的回顯研究之后,引發了無數安全研究員對內存webshell的研究,其中涌現出了LandGrey師傅構造的Spring controller內存馬。至此內存馬開枝散葉發展出了三大類型:
- servlet-api類
-
- filter型
-
- servlet型
- spring類
-
- 攔截器
-
- controller型
- Java Instrumentation類
-
- agent型
0x02 查殺思路
利用Java Agent技術遍歷所有已經加載到內存中的class。先判斷是否是內存馬,是則進入內存查殺。
0x03 內存馬的識別
1.filter名字很特別【弱特征】
內存馬的Filter名一般比較特別,有shell
或者隨機數等關鍵字。這個特征稍弱,因為這取決于內存馬的構造者的習慣,構造完全可以設置一個看起來很正常的名字。
2.filter優先級是第一位【弱特征】
為了確保內存馬在各種環境下都可以訪問,往往需要把filter匹配優先級調至最高,這在shiro反序列化中是剛需。但其他場景下就非必須,只能做一個可疑點。
對于一個web工程的filter過濾器,一般有兩種方式放入項目中:
1、在web.xml里面配置
之前我們控制多個filter的執行順序是通過web.xml中控制filter的位置來控制的,放在上面的會比放在下面的先執行,如下“用戶登錄檢查過濾器”會比“接口日志過濾器”先執行。
<!-- 用戶登錄檢測過濾器 -->
<filter><filter-name>UserLoginFilter</filter-name><filter-class>net.tfgzs.demo.filter.UserLoginFilter</filter-class>
</filter>
<filter-mapping><filter-name>UserLoginFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
<!--接口日志過濾器-->
<filter><filter-name>ApiLog</filter-name><filter-class>net.tfgzs.demo.filter.ApiLog</filter-class>
</filter>
<filter-mapping><filter-name>ApiLog</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
2、@WebFilter注解
注解里面沒有提供可以控制執行順序的參數,通過實踐發現如果想要控制filer的執行順序可以 通過控制filter的文件名的首字母來 來控制。
比如:
UserLoginFilter.java 和 ApiLog.java 這兩個文件里面分別是“用戶登錄檢查過濾器”和“接口日志過濾器”,因為這兩個文件的 首字母A排U之前 ,導致每次執行的時候都是先執行“接口日志過濾器”再執行“用戶登錄檢查過濾器”。
3.對比web.xml中沒有filter配置【強特征】
內存馬的Filter是動態注冊的,所以在web.xml中肯定沒有配置,這也是個可以的特征。但servlet 3.0引入了@WebFilter
標簽方便開發這動態注冊Filter。這種情況也存在沒有在web.xml中顯式聲明,這個特征可以作為較強的特征。
4.特殊classloader加載【弱特征】
我們都知道Filter也是class,也是必定有特定的classloader加載。一般來說,正常的Filter都是由中間件的WebappClassLoader加載的。反序列化漏洞喜歡利用TemplatesImpl和bcel執行任意代碼。所以這些class往往就是以下這兩個:
-
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$TransletClassLoader
-
com.sun.org.apache.bcel.internal.util.ClassLoader
這個特征是一個特別可疑的點了。當然了,有的內存馬還是比較狡猾的,它會注入class到當前線程中,然后實例化注入內存馬。這個時候內存馬就有可能不是上面兩個classloader。
5.對應的classloader路徑下沒有class文件【強特征】
所謂內存馬就是代碼駐留內存中,本地無對應的class文件。所以我們只要檢測Filter對應的ClassLoader目錄下是否存在class文件。
private static boolean classFileIsExists(Class clazz){if(clazz == null){return false;}String className = clazz.getName();String classNamePath = className.replace(".", "/") + ".class";URL is = clazz.getClassLoader().getResource(classNamePath);if(is == null){return false;}else{return true;}
}
6.Filter的doFilter方法中有惡意代碼【強特征】
我們可以把內存中所有的Filter的class dump出來,使用fernflower
等反編譯工具分析看看,是否存在惡意代碼,比如調用了如下可疑的方法:
-
java.lang.Runtime.getRuntime
-
defineClass
-
invoke
-
…
不難分析,內存馬的命門在于5
和6
。簡單說就是Filter型內存馬首先是一個Filter類,同時它在硬盤上沒有對應的class文件。若dump出的class還有惡意代碼,那是內存馬無疑。
0x04 內存馬的查殺
java-memshell-scanner
通過jsp腳本掃描并查殺各類中間件內存馬,比Java agent要溫和一些。
未注入內存馬之前:
注入內存馬后:
點擊kill,殺掉內存馬
再次訪問已經無法執行命令
tomcat有一個work目錄,里面存放了頁面的緩存,訪問的jsp都會編譯(從 work里進入Catalina后的如localhost站點文件夾下的項目,我們可以看到那些jsp頁面會被編譯成應該是servlet文件,下次再來 訪問時,就直接運行servlet類就可以向客戶端反應響應頁面了,所以有的博客說第一次訪問時會比較慢,是因為新發布上去的頁面在第一個人訪問時,會先 編譯成servlet文件,所以慢了,一旦編譯好,那么除非jsp頁面修改,不然下次訪問直接運行servlet就可以響應用戶,所以快),編譯后的文件都會存儲在work目錄下。而tomcat顯示的目錄,都會從這個緩存里找編譯后的jsp對應的class文件。所以當清空了work目錄后,該過程將會從新來過。