JNDI注入工具改造

SecIN發表於2022-11-17

原始碼連結

(修改前的原始碼,因為feihong師傅的倉庫已經不在了,這裡使用的是Jeromeyoung師傅的原始碼進行改造)https://github.com/Jeromeyoung/JNDIExploit-1

0x00 JNDI注入工具程式碼結構分析

controllers模組:負責LDAP請求的處理

enum模組:負責儲存各種模板型別名稱,如:反序列化的Gadget、記憶體馬的型別

異常模組:負責處理可能丟擲的異常

反序列化模組:各種反序列化鏈的處理

模板模組:命令執行、回顯、DNS、記憶體馬模板

工具類模組:主要是為了方便而編寫的一些工具類

協議服務及啟動模組:負責LDAP、HTTP協議的具體實現

下面先對啟動及協議服務模組進行說明

com.feihong.ldap.Starter類為整個工具的啟動入口,從命令列接收引數傳參到com.feihong.ldap.utils.Config類

Config類中的@Parameter註解為引數的說明及代表的意思,類似於py中的argparse,命令接收到引數,分別賦值給Config類的幾個私有變數。

然後在之後的HTTPServer與LDAPServer中得到應用

關於LDAP服務端的編寫和Demo可以參考以下連結:https://www.freebuf.com/vuls/253545.html,HTTPServer則是正常的Java Demo編寫即可

第一部分註解的應用

在JNDIEXP中,作者為了可以反射一種型別的類,Controller類,這裡的類起到了尋找特定類的作用,而且每個註解類都給定了uri屬性

在LDAPServer.start()之前,會先透過new Reflections(this.getClass().getPackage().getName())的方法獲取到com.feihong.ldap包下面所有LdapMapping的類,之後將其以鍵值對(TreeMap<String, LdapController>)放入到Map中,以便於後續呼叫

比如com.feihong.ldap.controllers.BasicController類,在Map中的儲存格式就是(basic=>Object BasicController)

根據傳送來的LDAP請求去決定呼叫哪個類,具體透過com.feihong.ldap.processSearchResult

根據工具執行的實際效果,如果我們的LDAP請求為ldap://192.168.85.1:1389/Basic/123

那麼DN為Basic/123,首先根據DN中的開頭字串決定是哪個Controller來處理當前的LDAP的請求

第二部分服務端動態呼叫類

在LDAP呼叫LdapController介面實現類之後(以BasicController為例),會先呼叫process方法,以/為標誌分割,獲取到相應的模組名稱,比如ldap://0.0.0.0:1389/Basic/Command/whoami,那麼第一部分Basic用來指定是BasicController,Command指定執行BasicController下的命令執行模組

如果是命令執行模組

透過com.feihong.ldap.utils.Util的getCmdFromBase方法獲取到執行命令的內容,如果是base編碼的,進行base64解碼後返回內容

將其賦值給params,之後再呼叫BasicController的sendResult方法,如果是command模組,初始化該模組,透過asm碼的方法,這裡為了避免出現類名重複的情況,使用隨機字元命令類名

之後命令執行模組呼叫cache方法

將其儲存在map中,之後開始進行LDAP的步驟

首先LDAP設定好

javaClassName:記錄序列化物件的類名,這樣應用程式就可以確定類資訊,而不必首先反序列化

javaClassNames:關於序列化物件的附加類資訊。

javaCodebase:例項化工廠所需的類定義的位置(HTTP地址)

javaFactory:用於儲存物件工廠的完全限定類的可選屬性(即類名)

一張圖說明LDAP請求的過程

wKg0C2I4Qs6AAM4QAABoz1qOh2I020.png

接下來看HTTPServer如何接收HTTP請求並返回

當HTTPServer接收到請求之後,將Cache類中map儲存的類寫入到響應中,這樣避免了class檔案落地的情況。

0x01 去除server console內容

在這個JNDI的注入工具中,會在注入記憶體馬的時候,使用系統輸出語句,在控制檯列印出東西,無關緊要的東西,直接去掉就好。

0x02 冰蠍3.11記憶體馬注入

改造前的filter類,獲取session是透過ServletRequest的方式獲取的

改造之後的filter類,不再使用自寫的classLoader而是直接使用URLClassLoader,同理對其他的元件也進行類似的改造,如:spring的Interceptor,weblogic和jboss的filter

所有回顯使用的是header頭的WWW-Authenticate欄位,而非cmd

0x03 JDK版本匹配及tomcat版本相容解決

利用JDK向下相容的特性,這裡使用JDK6編譯filter class。

tomcat版本相容,根據先知不久之前提出的,tomcat6-9的通用StandardContext獲取方法,獲取到StandardContext,接下來的問題就是解決tomcat版本識別與不同版本間filter注入的問題。

tomcat8以下版本FilterDef、FilterMap都在org.apache.catalina.deploy包裡,tomcat8以上包括8都在org.apache.tomcat.util.descriptor.web裡。

2.識別版本之後,進行不同版本間的filter注入

實現邏輯大概如下:

對各個版本的filter記憶體馬全部轉為位元組碼Base64的編碼格式,透過loadClass的辦法,根據版本注入到記憶體中。(class一律使用JDK1.6編譯)

為了避免相關類載入不到的問題,這裡統一使用反射寫所有的filter注入步驟。

tomcat6789的StandardContext先知上已經給出瞭解決方案:

https://xz.aliyun.com/t/9914

對tomcat特定類進行篩選,來決定FilterDef和FilterMap類載入的使用,最後形成的Demo如下:

getStand的原始碼如下:

經測試,可用於常規的tomcat6、7(某凌)、8、9版本。

當所有的tomcat版本都測試完畢之後,發現這個通用方法對某遠並不適用,原因是致遠這裡的ServerPort會永遠等於-1。

解決方案是使用原版的feihong-jndi將TomcatMemShell2中的filter類替換為自定義的filter類即可。

0x04 spring memShell的改進

在一些版本的測試中,發現原版的JNDIExploit的spring並不適用於所有的spring框架場景,對此做出補充(借鑑自lz2y與microworld師傅的成果)

以ruoyi cms後臺的snake yaml為例,lz2y師傅這裡已經說了具體的原因(https://xz.aliyun.com/t/10651),直接使用師傅的Demo就好,我這裡使用的是Windows的環境,使用比較在Linux和Windows都通用的Demo獲取的WebApplicationContext

使用com.ruoyi.common.utils.spring.SpringUtils在windows ruoyi4.6.0的環境中沒有成功(POC使用的是com.sun.rowset.JdbcRowSetImpl)

使用com.ruoyi.common.utils.spring.SpringUtils在windows ruoyi4.6.0的環境中成功(POC使用的是javax.script.ScriptEngineManager)

剩下的步驟直接注入記憶體馬即可,實現Demo如下:

將其新增到類的引用處,對於spring的框架新增新增類的引用,需要修改的是四個類:

com.feihong.ldap.enumtypes.PayloadType

com.feihong.ldap.utils.Cache

com.feihong.ldap.controllers.BasicController

com.feihong.ldap.controllers.TomcatBypassController

修改Cache類是為了能夠讓惡意類能夠在記憶體中載入,具體的原因已經在0.1中分析完畢,修改BasicController和TomcatBypassController是為了能在LDAP在JDK的高低版本中找到引用。

0x05 jetty memShell的改進

對於jetty記憶體馬的改進,主要是log4j對solr的影響,針對於實戰的場景,參考Qu3een師傅的文章(https://tttang.com/archive/1386/

實現的Demo如下,直接整合到JNDI注入工具中

修改com.feihong.ldap.enumtypes.PayloadType

修改com.feihong.ldap.utils.Cache

修改com.feihong.ldap.controllers.BasicController

0x06 webSphere memShell的改進

暫缺

0x07 增加resin中介軟體下的記憶體馬注入

基於pen4uin師傅的通用研究成果直接整合到JNDI注入工具中,原理不再贅述,參考pen4uin師傅的公眾號即可,直接給出Demo

同樣的,修改com.feihong.ldap.enumtypes.PayloadType

修改com.feihong.ldap.utils.Cache

修改com.feihong.ldap.controllers.BasicController

0x08 增加tomcatValue記憶體馬

在tomcat容器中,有些場景filter記憶體馬並不如valve記憶體馬,所以為了增加相容性,這裡增加valve記憶體馬,實現的Demo大致如下:

同樣的修改配置檔案,增加到BasicController、TomcatBypassController、Cache、Config中。

參考連結

https://landgrey.me/blog/19/

https://github.com/Mr-xn/JNDIExploit-1

https://tttang.com/archive/1386/

https://mp.weixin.qq.com/s/5s9eyRpaP7WhVd2estwtKg

https://github.com/lz2y/yaml-payload-for-ruoyi

https://xz.aliyun.com/t/10651


相關文章