(本文作者是orange,以其第一人稱敘述。)
這是我在Black Hat USA 2018和DEFCON 26上的案例研究,PPT可在這里下載:
? Breaking Parser Logic! Take Your Path Normalization Off and Pop 0days Out
這兩年我一直在關(guān)注網(wǎng)絡(luò)安全中的“不一致”的問題。什么叫做“不一致”的問題呢? 打個(gè)比方,就像我去年在Black Hat展示的GitHub的由SSRF導(dǎo)致RCE案例中出現(xiàn)的, URL解析器和URL獲取器之間的不一致導(dǎo)致整個(gè)SSRF繞過!
這里還推薦一篇文章@ 0x09AL,Bypassing Web-Application Firewalls by abusing SSL/TLS ,從中足以看出“不一致”問題的可怕。
所以今年,我開始關(guān)注路徑解析器和路徑規(guī)范化中的“不一致”的問題!
編寫一款設(shè)計(jì)良好的解析器很難。因?yàn)椴煌膶?shí)體都有著不同的標(biāo)準(zhǔn)和實(shí)施方式。一般為了在不影響業(yè)務(wù)邏輯的情況下來修復(fù)錯誤,都會增加一個(gè)過濾器而不是直接給漏洞打補(bǔ)丁。那如果過濾器和被調(diào)用方法之間存在任何不一致,就可以輕松繞過安全機(jī)制!
在閱讀文檔說明的時(shí)候,我注意到一個(gè)叫URL Path Parameter的功能。 一些研究人員早就指出過這個(gè)功能可能會導(dǎo)致安全問題,但是是說它仍然取決于編程是否有問題! 畫個(gè)思維導(dǎo)圖,然后我發(fā)現(xiàn)這個(gè)功能可以完美地應(yīng)用在多層體系結(jié)構(gòu)上,而且是默認(rèn)情況下就很容易受到攻擊。如果你使用反向代理,并且是Java作為后端服務(wù),那么就危險(xiǎn)了!
早先在2015年第一次發(fā)現(xiàn)這個(gè)攻擊面是在一次紅隊(duì)測試中。我覺得這個(gè)問題很牛x,想看看有多少人知道,然后就在WCTF 2016中出了一道相關(guān)的題目。
不過后來事實(shí)證明,沒人知道這個(gè)問題,因?yàn)闆]有參賽隊(duì)伍做出這個(gè)題。
今年我打算分享這個(gè)問題。為了說服審查委員會,我要更多的案例證明它有效!然而在尋找案列的過程中發(fā)現(xiàn)這個(gè)攻擊面不僅可以泄漏信息,還可以繞過ACL(例如優(yōu)步的OneLogin bypass),并在幾個(gè)賞金計(jì)劃中導(dǎo)致RCE。 這篇文章介紹的就是其中之一!
(PPT里有以上的案例說明)
↓多層架構(gòu)的不一致性!
首先,感謝亞馬遜的漏洞披露計(jì)劃。與亞馬遜安全團(tuán)隊(duì)合作感覺特別好(當(dāng)然Nuxeo團(tuán)隊(duì)也是)。
整個(gè)故事始于一個(gè)域名collaborate-corp.amazon.com,它貌似是一個(gè)內(nèi)部協(xié)作系統(tǒng)。 從網(wǎng)頁下面的copyright來看,這個(gè)系統(tǒng)是用一個(gè)開源項(xiàng)目Nuxeo構(gòu)建的。 它是一個(gè)非常龐大的Java項(xiàng)目,起初我就想提高一下Java審計(jì)技能。所以就從它開始了。
我的個(gè)人習(xí)慣是拿到j(luò)ava源碼之后先去看pom.xml,看看有沒有引用一些過時(shí)的包什么的。在java漏洞里面很多問題都是OWASP Top 10 – A9上列的已知易受攻擊的組件,比如Struts2,F(xiàn)astJSON,XStream或具有反序列化問題的組件等等。
Nuxeo的包大部分都是最新的。不過還是有一個(gè)“老朋友”——Seam Framework。 Seam是JBoss開發(fā)的Web應(yīng)用程序框架,幾年前它是一個(gè)相當(dāng)流行的Web框架,到現(xiàn)在仍有許多基于Seam的應(yīng)用程序:P
1. 路徑規(guī)范化錯誤導(dǎo)致ACL繞過
通過WEB-INF / web.xml查看訪問控制時(shí),我發(fā)現(xiàn)Nuxeo使用自定義的身份驗(yàn)證過濾器NuxeoAuthenticationFilter并映射/ *。 從過濾器來看大多數(shù)頁面都需要身份驗(yàn)證,但是有一個(gè)白名單,例如login.jsp。這些都是在bypassAuth方法中實(shí)現(xiàn)的。
從上面可以看出來,bypassAuth檢索當(dāng)前請求的頁面,與unAuthenticatedURLPrefix進(jìn)行比較。 但bypassAuth如何檢索當(dāng)前請求的頁面? Nuxeo編寫了一個(gè)從HttpServletRequest.RequestURI中提取請求頁面的方法,第一個(gè)問題出現(xiàn)在這里!
為了處理URL路徑參數(shù),Nuxeo以分號截?cái)嗨形搽S部分。 但是URL路徑參數(shù)是多種多樣的。 每個(gè)Web服務(wù)器都有自己的實(shí)現(xiàn)。 Nuxeo的方式在WildFly,JBoss和WebLogic等容器中可能是安全的。 但它在Tomcat下就不行了! 因此getRequestedPage方法和Servlet容器之間的區(qū)別會導(dǎo)致安全問題!
根據(jù)截?cái)喾绞剑覀兛梢詡卧煲粋€(gè)與ACL中的白名單匹配但是到達(dá)Servlet中未授權(quán)區(qū)域的請求!
我們選擇login.jsp作為前綴! ACL繞過可能如下所示:
如圖所示,繞過了重定向進(jìn)行身份驗(yàn)證,不過大多數(shù)頁面還是返回500錯誤。這是因?yàn)閟ervlet邏輯無法獲得有效的用戶原則,因此它會拋出Java NullPointerException。 但這并不影響進(jìn)一步操作。
附: 雖然有一個(gè)更快捷的方式來實(shí)現(xiàn)這個(gè)目的,不過還是值得寫下第一次嘗試!
2. 代碼重用功能導(dǎo)致部分EL調(diào)用
我之前也說到,Seam框架中有許多安全隱患。所以下一步我要做的就是回到第一個(gè)問題中去訪問未經(jīng)認(rèn)證的Seam servlet!
這個(gè)部分我將逐一詳細(xì)解釋這些“功能”.
為了控制瀏覽器應(yīng)該重定向的位置,Seam引入了一系列HTTP參數(shù),并且在這些HTTP參數(shù)中也存在問題… actionOutcome就是其中之一。 2013年,@meder發(fā)現(xiàn)了一個(gè)遠(yuǎn)程代碼執(zhí)行漏洞。見CVE-2010-1871:JBoss Seam Framework remote code execution for details!但今天,我們將討論另一個(gè) – actionMethod!
actionMethod是一個(gè)特殊的參數(shù),可以從查詢字符串中調(diào)用特定的JBoss EL(Expression Language)。這看起來相當(dāng)危險(xiǎn),但在調(diào)用之前有一些先決條件。詳細(xì)的實(shí)現(xiàn)可以在方法callAction中找到。為了調(diào)用EL,必須滿足以下前提條件:
1.actionMethod的值必須是一對,例如:FILENAME:EL_CODE
2.FILENAME部分必須是context-root下的真實(shí)文件
3.文件FILENAME必須包含內(nèi)容“#{EL_CODE}”(雙引號是必需的)
例如:
context-root下有一個(gè)名為login.xhtml的文件:
可以通過URL調(diào)用EL user.username
3. 雙重評估導(dǎo)致EL注入
之前的功能看起來沒啥毛病,你無法控制context-root下的任何文件,因此無法在遠(yuǎn)程服務(wù)器上調(diào)用任意EL。 然而,還有一個(gè)更瘋狂的功能:
如果返回一個(gè)字符串,并且該字符串看起來像一個(gè)EL就糟糕了, Seam框架將再次調(diào)用!
請看更細(xì)節(jié)的調(diào)用堆棧信息
1.CallAction(Pages.java)
2.handleOutcome(Pages.java)
3.handleNavigation(SeamNavigationHandler.java)
4.interpolateAndRedirect(FacesManager.java)
5.interpolate(Interpolator.java)
6.interpolateExpressions(Interpolator.java)
7.createValueExpression(Expressions.java)
有了這個(gè)功能,如果我們可以控制返回值,我們可以執(zhí)行任意EL!
這與二進(jìn)制利用中的ROP(Return-Oriented Programming)非常相似。 所以我們需要找到一個(gè)合適的工具!
這里我用的是 widgets/suggest_add_new_directory_entry_iframe.xhtml
為什么選用這個(gè)呢?這是因?yàn)閞equest.getParameter返回一個(gè)我們可以從查詢字符串控制的字符串! 雖然整個(gè)標(biāo)記是分配變量,但我們可以濫用語義!
現(xiàn)在將第二階段payload放在directoryNameForPopup中。 對于第一個(gè)bug,我們可以將它們鏈接在一起以執(zhí)行任意EL而無需任何身份驗(yàn)證! PoC:
雖然我們現(xiàn)在可以執(zhí)行任意EL,但仍然無法反彈shell。 為什么?繼續(xù)看。
4. EL黑名單繞過導(dǎo)致RCE
Seam也知道EL的問題。 從Seam 2.2.2.Final開始,用一個(gè)EL黑名單來阻止危險(xiǎn)的調(diào)用! 不幸的是,Nuxeo使用最新版本的Seam(2.3.1.Final),因此必須找到繞過黑名單的方法。 黑名單可以在resources/org/jboss/seam/blacklist.properties中找到。
研究一下發(fā)現(xiàn)黑名單只是一個(gè)簡單的字符串匹配,我們都知道黑名單一般都是下下策。 我剛看到這個(gè),就想起了Struts2 S2-020。這兩個(gè)有相似之處。 使用類似數(shù)組的運(yùn)算符來處理黑名單模式:
把
“”.getClass().forName(“java.lang.Runtime”)
改成
“”[“class”].forName(“java.lang.Runtime”)
最后,在JBoss EL中編寫shellcode。 我們使用Java反射API來獲取java.lang.Runtime對象,并列出所有方法。 getRuntime()返回Runtime實(shí)例,exec(String)執(zhí)行我們的命令!
最后總結(jié)一下所有所有步驟并將它們連在一起利用:
1.路徑規(guī)范化錯誤導(dǎo)致ACL繞過
2.繞過白名單訪問未經(jīng)授權(quán)的Seam servlet
3.使用Seam功能actionMethod調(diào)用文件中的小工具suggest_add_new_directory_entry_iframe.xhtml
4.在HTTP參數(shù)directoryNameForPopup中準(zhǔn)備第二階段payload
5.使用類似數(shù)組的運(yùn)算符繞過EL黑名單
6.使用Java反射API編寫shellcode
7.坐等shell
這是整個(gè)漏洞利用:
通過執(zhí)行perl腳本,成功反彈shell:
修復(fù)分為三塊:
1. JPBoos
最麻煩的是Seam框架。 我已于2016年9月向security@jboss.org報(bào)告了這些問題。但他們的回復(fù)是:
由于EOL這些問題似乎沒有官方補(bǔ)丁。 但是,許多Seam應(yīng)用程序仍然被廣為使用。 所以如果你使用Seam。 建議你用Nuxeo的方案來緩解這個(gè)問題。
2. Amazon
亞馬遜安全團(tuán)隊(duì)隔離了服務(wù)器,與報(bào)告者討論了如何解決,并列出了他們采取的方案! 與他們合作是一個(gè)很好的經(jīng)歷:)
3. Nuxeo
在亞馬遜發(fā)出通知后,Nuxeo迅速發(fā)布了8.10版的補(bǔ)丁。 補(bǔ)丁重寫了方法callAction()! 如果需要Seam的補(bǔ)丁,可以在這里下載!
時(shí)間線
2018年3月10日01:13 GMT + 8通過aws-security@amazon.com向亞馬遜安全團(tuán)隊(duì)報(bào)告
2018年3月10日01:38 GMT + 8收到回復(fù)他們正在調(diào)查
2018年3月10日03:12 GMT + 8要求我參加安全團(tuán)隊(duì)的電話會議
2018年3月10日05:30 GMT + 8與亞馬遜召開電話會議,了解他們?yōu)榇寺┒床扇〉拇胧?/p>
2018年3月10日16:05 GMT + 8詢問是否可以公開披露
2018年3月15日04:58 GMT + 8 Nuxeo發(fā)布了新版本8.10,修補(bǔ)了RCE漏洞
2018年3月15日23:00 GMT+8 與亞馬遜召開電話會議,了解情況并討論公開細(xì)節(jié)
2018年4月 5日05:40 GMT + 8獲得亞馬遜獎金