文章首發先知:Java安全之Weblogic 2016-0638分析javascript
續上篇文的初探weblogic的T3協議漏洞,再談CVE-2016-0638, CVE-2016-0638是基於 CVE-2015-4852漏洞的一個繞過。html
這裏採用上次的weblogic環境,可是在這裏還須要打一個補丁包,來修復 CVE-2015-4852漏洞後,對該漏洞進行一個繞過。git
CVE-2015-4852的修復補丁爲p21984589_1036_Generic
,因爲在互聯網上並無找到該補丁包,只能經過官網下載,官網下載須要購買對應的服務,因此在這裏找了p20780171_1036_Generic
和p22248372_1036012_Generic
這兩個補丁包,p21984589_1036_Generic
是前面這兩個補丁包的集成。github
由於前面搭建是docker的環境,須要將這兩個補丁包上傳到docker鏡像裏面去,而後進行安裝。web
命令整理:docker
docker cp ../p20780171_1036_Generic weblogic1036jdk7u21:/p20780171_1036_Generic docker cp ../p22248372_1036012_Generic weblogic1036jdk7u21:/p22248372_1036012_Generic docker exec -it weblogic1036jdk7u21 /bin/bash cd /u01/app/oracle/middleware/utils/bsu mkdir cache_dir vi bsu.sh 編輯MEM_ARGS參數爲1024 cp /p20780171_1036_Generic/* cache_dir/ ./bsu.sh -install -patch_download_dir=/u01/app/oracle/middleware/utils/bsu/cache_dir/ -patchlist=EJUW -prod_dir=/u01/app/oracle/middleware/wlserver/ cp /p22248372_1036012_Generic/* cache_dir/ ./bsu.sh -install -patch_download_dir=/u01/app/oracle/middleware/utils/bsu/cache_dir/ -patchlist=ZLNA -prod_dir=/u01/app/oracle/middleware/wlserver/ –verbose
重啓weblogic服務。apache
/u01/app/oracle/Domains/ExampleSilentWTDomain/bin/startWebLogic.sh
這裏看到weblogic 2015-4852的payload打過去,並無像以往同樣,建立一個文件。那麼就說明補丁已經打上了,已經可以修復該漏洞了。這裏是切換了JDK7u21和cc1的利用鏈依舊沒打成功。安全
接下來仍是須要將裏面的依賴包給拷一下。bash
mkdir wlserver1036 mkdir coherence_3.7 docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/modules ./wlserver1036 docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/wlserver/server/lib ./wlserver1036 docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./coherence_3.7/lib
下面來對該補丁進行一個繞過。
補丁做用位置:
weblogic.rjvm.InboundMsgAbbrev.class :: ServerChannelInputStream weblogic.rjvm.MsgAbbrevInputStream.class weblogic.iiop.Utils.class
在分析漏洞前,先來看到一下,上一個漏洞點的補丁是怎麼進行修復的。
在這其實看到該resolveClass
方法的位置,前面加多一個判斷。
前面判斷className是否爲空,ClassName的長度是否爲零,可是重點是ClassFilter.isBlackListed
方法。
這裏先打一個 CVE-2015-4852 exp過來,在該位置打個斷點,跟蹤進該方法,查看怎麼進行防禦。
跟進進來後,先別急着看後面的,由於下面還有一個靜態代碼塊,靜態代碼塊中代碼優先執行,須要先來查看靜態代碼塊內容。
這裏前面有兩個判斷,判斷中都調用了兩個方法,來看看這兩個方法的實現。
一個是判斷是否爲weblogic.rmi.disableblacklist
,一個是判斷是否爲weblogic.rmi.disabledefaultblacklist
,寫法有點奇怪,多是由於是class文件的緣故。
這兩個判斷爲true的話,就會執行來到下一步調用updateBlackList
將後面的一系列黑名單的類傳入到裏面去。
updateBlackList
該方法從名字得知,就是一個黑名單列表添加的一個方法,將黑名單內容添加到一個HashSet
裏面去。查看具體實現。
StringTokenizer 構造方法:爲指定的字符串構造一個字符串tokenizer。
hasMoreTokens方法:返回與 hasMoreTokens
方法相同的值。
nextToken 方法:返回此字符串tokenizer字符串中的下一個令牌。
整體的來理解就是構造一個字符串,而後遍歷裏面的值,而後調用processToken
方法將該值傳遞進去。
再來看到processToken
方法。
裏面判斷若是開頭是+
號,則截取第一位後面的值添加到黑名單的這個HashSet裏面去。若是是-
號則移除,若是開頭不是前面的+
-
號則直接添加到黑名單裏面去。
到這裏靜態代碼塊就已經分析完成了,總的來講其實就是將一些危險的類,添加到了黑名單裏的一個步驟。
黑名單列表爲:
+org.apache.commons.collections.functors, +com.sun.org.apache.xalan.internal.xsltc.trax, +javassist,+org.codehaus.groovy.runtime.ConvertedClosure, +org.codehaus.groovy.runtime.ConversionHandler, +org.codehaus.groovy.runtime.MethodClosure
返回剛剛的ClassFilter.isBlackListed
方法進行跟蹤
最後這裏調用了contains
方法判斷 這個pkgName存不存在黑名單中,存在的話這裏返回true。
返回到resolveClass
方法能夠看到這裏爲true,就會直接拋異常。
若是不存在於黑名單中,會來到else這個分支的代碼塊中調用父類的resolveClass
方法。
而這一個點,只是過濾的一個點,下面來看看過濾的點都有哪些。
再來看下一個點MsgAbbrevInputStream
的位置
這裏也是調用ClassFilter.isBlackListed
方法進行過濾,和前面的是同樣的。以此類推。
在CVE-2016-0638裏面用到了weblogic_cmd工具,github地址。
下面來看看該工具的實現,再談漏洞的繞過方式。
下載該源碼後,導入IDEA中,配置命令參數。
這裏若是報錯找不到sun.tools.asm包的話,須要將Tools.jar包手動添加一下。在這我是使用jdk1.6進行執行的,使用1.8版本會找不到sun.org.mozilla.javascript.internal.DefiningClassLoader
類
在Main的類中打個斷點進行執行。
前面都是代碼都是進行一個配置,這裏斷點選擇落在該方法中。
選擇跟蹤
繼續跟蹤WebLogicOperation.blindExecute
方法。
前面判斷了服務器類型,重點在SerialDataGenerator.serialBlindDatas
方法中,payload由該方法進行生成。跟進查看一下該方法如何生成payload。
在這先選擇跟蹤blindExecutePayloadTransformerChain
方法。
在這裏又看到了熟悉的面孔,CC鏈的部分代碼。
回到剛剛的地方,跟蹤serialData
方法
在這裏就看到了CC鏈後面的一段代碼,這組合成了一條CC1利用鏈。可是在後面調用了BypassPayloadSelector.selectBypass
方法來處理在原生的利用鏈中本該直接進行序列化的對象。
跟進該方法進行查看。
這裏面還會去調用Serializables.serialize
,依舊先跟蹤最裏層的方法。
這傳入一個obj對象和out對象,進行了序列化操做。而後將序列化後的數據寫到out對象中。
執行完成後,返回上一個點,剛纔分析得知返回的是序列化後的數據。因此在處調用streamMessageImpl
方法傳遞的參數也是序列化的數據。
跟蹤查看。
內部是new了一個weblogic.jms.common.StreamMessageImpl
的實例,而後調用setDataBuffer
方法將序列化後的對象和序列化後的長度傳遞進去。
執行完這步後,回到這個地方
後面的這個方法是進行序列化操做的,這裏又對 streamMessageImpl
的實例對象進行了一次序列化。該方法在前面查看過了,這裏就不跟進去看了。
而最後來到了這裏。
然後面這個方法就是構造特定的數據包,使用T3協議發送payload。
那麼若是須要繞過的話,咱們須要找一個類,他的類在內部的readObject
方法建立了本身的InputStream
的對象,可是又不能爲黑名單裏面過濾掉的ServerChannelInputStream
和MsgAbbrevInputStream
裏面的readObject
方法。而後調用該readObject
方法進行反序列化,這時候就能夠達成一個繞過的效果。
在師傅們的挖掘中尋找到了weblogic.jms.common.StreamMessageImpl#readExternal()
,StreamMessageImpl
類中的readExternal
方法能夠接收序列化數據做爲參數,而當StreamMessageImpl
類的readExternal
執行時,會反序列化傳入的參數並調用該參數反序列化後對應類的這個readObject
方法。
繞過原理以下:
將反序列化的對象封裝進了 StreamMessageImpl,而後再對 StreamMessageImpl 進行序列化,生成 payload 字節碼。反序列化時 StreamMessageImpl 不在 WebLogic 黑名單裏,可正常反序列化,在反序列化時 StreamMessageImpl 對象調用 readObject 時對 StreamMessageImpl 封裝的序列化對象再次反序列化,這樣就逃過了黑名單的檢查。
在此先再來思考一個問題,weblogic.jms.common.StreamMessageImpl#readExternal()
該方法是怎麼被調用的呢?在前面分析原生readObject
方法的時候發現,其實readObject
方法的底層還會去調用不少其餘方法。
在Weblogic從流量中的序列化類字節段經過readClassDesc-readNonProxyDesc-resolveClass獲取到普通類序列化數據的類對象後,程序依次嘗試調用類對象中的readObject、readResolve、readExternal等方法。而在這裏readExternal
就會被調用。
那麼下面來調試分析一下該漏洞。
仍是先在weblogic.rjvm.InboundMsgAbbrev#ServerChannelInputStream.resolveClass
地方打個斷點,而後使用weblogic_cmd工具打一個payload過去,先來查看一下傳輸過來的數據。
這裏能夠看到獲取到的ClassName是weblogic.jms.common.StreamMessageImpl
的對象,而不在再是AnnotationInvocationHandler
對象。StreamMessageImpl
不在黑名單中,這裏的判斷不會進行拋異常。
下個斷點直接落在StreamMessageImpl.readExternal
中跟蹤一下。
看到調用棧這裏就應驗了咱們前面所提到的關於StreamMessageImpl.readExternal
調用問題。
這裏的var4爲正常反序列化後的數據,然後面會new一個ObjectInputStream
類傳遞var4參數進去。而後再調用readObject
方法
執行完這一步後,命令就已經執行成功。後面的是對CC鏈執行命令的一個基本認知,在此不作贅述。
https://xz.aliyun.com/t/8443#toc-6 https://www.anquanke.com/post/id/224343#h3-6
其實摸清楚補丁的一個套路事後,再去基於補丁分析後面的漏洞會比較清晰。由於補丁無非就是再從ClassFilter裏面添加黑名單列表,這也是爲何weblogic修修補補又爆洞的緣由,並無從根本緣由去進行修復。