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