压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

S2-057漏洞原作者自述:如何利用自動(dòng)化工具發(fā)現(xiàn)5個(gè)RCE

2018年4月,我向Apache Struts和Struts安全團(tuán)隊(duì)中報(bào)告了一個(gè)新的遠(yuǎn)程執(zhí)行代碼漏洞——CVE-2018-11776(S2-057),在做了某些配置的服務(wù)器上運(yùn)行Struts,可以通過(guò)訪問(wèn)精心構(gòu)造的URL來(lái)觸發(fā)漏洞。

這一發(fā)現(xiàn)是我對(duì)Apache Struts的持續(xù)安全性研究的一部分。在這篇文章中,我將介紹我發(fā)現(xiàn)漏洞的過(guò)程以及如何利用以前的漏洞信息來(lái)獲取Struts內(nèi)部工作的原理,創(chuàng)建封裝Struts特定概念的QL查詢。運(yùn)行這些查詢會(huì)高亮顯示有問(wèn)題代碼的結(jié)果。這些工程都托管在GitHub上,后面我們也會(huì)向此存儲(chǔ)庫(kù)添加更多查詢語(yǔ)句和庫(kù),以幫助Struts和其他項(xiàng)目的安全性研究。

映射攻擊面

許多安全漏洞都涉及了從不受信任的源(例如,用戶輸入)流向某個(gè)特定位置(sink)的數(shù)據(jù),并且數(shù)據(jù)采用了不安全的處理方式——例如,SQL查詢,反序列化,還有一些其他解釋型語(yǔ)言等等,QL可以輕松搜索此類漏洞。你只需要描述各種source和sink,然后讓DataFlow庫(kù)完成這些事情。對(duì)于特定項(xiàng)目,開始調(diào)查此類問(wèn)題的一種好方法是查看舊版本軟件的已知漏洞。 這可以深入了解你想要查找的source和sink點(diǎn)。

這次漏洞發(fā)現(xiàn)過(guò)程中,我首先查看了RCE漏洞S2-032(CVE-2016-3081),S2-033(CVE-2016-3687)和S2-037(CVE-2016-4438)。 與Struts中的許多其他RCE一樣,這些RCE涉及不受信任的輸入被轉(zhuǎn)為OGNL表達(dá)式,允許攻擊者在服務(wù)器上運(yùn)行任意代碼。 這三個(gè)漏洞特別有意思,它們不僅讓我們對(duì)Struts的內(nèi)部工作機(jī)制有了一些了解,而且這三個(gè)漏洞實(shí)際上是一樣的,還修復(fù)了三回!

這三個(gè)問(wèn)題都是遠(yuǎn)程輸入通過(guò)變量methodName作為方法的參數(shù)傳遞的造成的
OgnlUtil::getValue().
![](https://p4.ssl.qhimg.com/t01ba64d4377a0d041f.png)

這里proxy有ActionProxy的類型,它是一個(gè)接口。 注意它的定義,除了方法getMethod()(在上面的代碼中用于賦值的變量methodName)之外,還有各種方法,如getActionName()和getNamespace()。 這些方法看起來(lái)像是會(huì)從URL返回信息,所以我就假設(shè)所有這些方法都可能返回不受信任的輸入。 (后面的文章中,我將深入研究我對(duì)這些輸入來(lái)自何處的調(diào)查。)

現(xiàn)在使用QL開始對(duì)這些不受信任的源進(jìn)行建模:

識(shí)別OGNL的 sink點(diǎn)

現(xiàn)在我們已經(jīng)識(shí)別并描述了一些不受信任的來(lái)源,下一步是為sink點(diǎn)做同樣的事情。 如前所述,許多Struts RCE涉及將遠(yuǎn)程輸入解析為OGNL表達(dá)式。 Struts中有許多函數(shù)最終將它們的參數(shù)作為OGNL表達(dá)式; 對(duì)于我們?cè)诒疚闹虚_始的三個(gè)漏洞,使用了OgnlUtil :: getValue(),但是在漏洞S2-045(CVE-2017-5638)中,使用了TextParseUtil :: translateVariables()。 我們可以尋找用于執(zhí)行OGNL表達(dá)式的常用函數(shù),我感覺(jué)OgnlUtil :: compileAndExecute()和OgnlUtl :: compileAndExecuteMethod()看起來(lái)更有戲。

我的描述:

第一次嘗試

現(xiàn)在我們已經(jīng)在QL中定義了source和sink,我們可以在污點(diǎn)跟蹤查詢中使用這些定義。 通過(guò)定義DataFlow配置來(lái)使用DataFlow庫(kù):

這里是我使用之前定義的isActionProxySource和isOgnlSink。

注意一下,我這里重載了isAdditionalFlowStep,這樣它可以允許我包含污染數(shù)據(jù)被傳播的額外步驟。 比如允許我將特定于項(xiàng)目的信息合并到流配置中。 例如,如果我有通過(guò)某個(gè)網(wǎng)絡(luò)層進(jìn)行通信的組件,我可以在QL中描述那些各種網(wǎng)絡(luò)端的代碼是什么樣的,允許DataFlow庫(kù)跟蹤被污染的數(shù)據(jù)。

對(duì)于此特定查詢,我添加了兩個(gè)額外的流程步驟供DataFlow庫(kù)使用。 第一個(gè):

它包括跟蹤標(biāo)準(zhǔn)Java庫(kù)調(diào)用,字符串操作等的標(biāo)準(zhǔn)QL TaintTracking庫(kù)步驟。第二個(gè)添加是一個(gè)近似值,允許我通過(guò)字段訪問(wèn)跟蹤污點(diǎn)數(shù)據(jù):

也就是說(shuō)如果將字段賦了某個(gè)受污染的值,那么只要兩個(gè)表達(dá)式都由相同類型的方法調(diào)用,對(duì)該字段的訪問(wèn)也將被視為污染。看下面的例子:

從上面看出,bar()中this.field的訪問(wèn)可能并不總是受到污染。 例如,如果在bar()之前未調(diào)用foo()。 因此,我們不會(huì)在默認(rèn)的DataFlow :: Configuration中包含這個(gè)步驟,因?yàn)闊o(wú)法保證數(shù)據(jù)始終以這種方式流動(dòng),但是,對(duì)于挖漏洞,我覺(jué)得加上這個(gè)很有用。在后面的帖子中,我將分享一些類似于這個(gè)的其他流程步驟,這些步驟對(duì)于找bug很有幫助,但由于類似的原因,默認(rèn)情況下是不包含這些步驟的。

初始結(jié)果和細(xì)化查詢

我在最新版本的源代碼上跑了一下QL,發(fā)現(xiàn)因S2-032,S2-033和S2-037仍然被標(biāo)記了。 這些漏洞明明已經(jīng)被修復(fù)了,為什么還是會(huì)報(bào)問(wèn)題呢?

經(jīng)過(guò)分析,我們覺(jué)得應(yīng)該是雖然最初通過(guò)過(guò)濾輸入來(lái)修復(fù)漏洞,但是在S2-037之后,Struts團(tuán)隊(duì)決定通過(guò)調(diào)用OgnlUtil :: getMalue()替換對(duì)OgnlUtil :: getMalue()的調(diào)用來(lái)修復(fù)它。

callMethod()封裝了compileAndExecuteMethod():

compileAndExecuteMethod()在執(zhí)行之前對(duì)表達(dá)式執(zhí)行額外檢查:

這意味著我們實(shí)際上可以從我們的sink點(diǎn)中刪除compileAndExecuteMethod()。

在重新運(yùn)行查詢后,高亮顯示對(duì)getMethod()作為sink的調(diào)用的結(jié)果消失了。 但是,仍然有一些結(jié)果高亮顯示了DefaultActionInvocation.java中的代碼,這些代碼被認(rèn)為是固定的,例如對(duì)getActionName()的調(diào)用,并且數(shù)據(jù)路徑從此處到compileAndExecute()并不是很明顯。

路徑探索和進(jìn)一步查詢細(xì)化

為了搞清楚為什么這個(gè)結(jié)果被標(biāo)記,需要能夠看到DataFlow庫(kù)用來(lái)產(chǎn)生這個(gè)結(jié)果的每個(gè)步驟。 QL允許編寫特殊的路徑問(wèn)題查詢,這些查詢可生成可逐節(jié)點(diǎn)探索的可變長(zhǎng)度路徑,DataFlow庫(kù)允許編寫輸出此數(shù)據(jù)的查詢。

在撰寫這篇博客的時(shí)候,LGTM本身沒(méi)有關(guān)于路徑問(wèn)題查詢的路徑探索UI,因此用了另一個(gè)Semmle應(yīng)用程序:QL for Eclipse。這是一個(gè)Eclipse插件,剛好可以滿足我們這里的需求,允許完成污點(diǎn)跟蹤中的各個(gè)步驟。它不僅可以在LGTM.com上對(duì)開源項(xiàng)目進(jìn)行離線分析,還可以為提供更強(qiáng)大的開發(fā)環(huán)境。可以在semmle-security-java目錄下的Semmle / SecurityQueries Git存儲(chǔ)庫(kù)中找到以下查詢。按照README.md文件中的說(shuō)明在Eclipse插件中運(yùn)行。下文將貼出部分運(yùn)行的截圖。

首先,在initial.ql中運(yùn)行查詢。在QL for Eclipse中,從DefaultActionInvocation.java中選擇結(jié)果后,您可以在Path Explorer窗口中看到從源到接收器的詳細(xì)路徑。

在上圖中可以看出,經(jīng)過(guò)幾個(gè)步驟后,調(diào)用getActionName()返回的值會(huì)流入到pkg.getActionConfigs()返回的對(duì)象的get()方法的參數(shù)中:

點(diǎn)擊下一步,key到了ValueStackShadowMap :: get()方法:

事實(shí)證明,因?yàn)閜kg.getActionConfigs()返回一個(gè)Map,而ValueStackShadowMap實(shí)現(xiàn)了Map接口,所以理論上pkg.getActionConfigs()返回的值可能是ValueStackShadowMap的一個(gè)實(shí)例。 因此,QL DataFlow庫(kù)顯示了從變量chainedTo到類ValueStackShadowMap中的get()實(shí)現(xiàn)的潛在流程。 實(shí)際上,ValueStackShadowMap類屬于jasperreports插件,該類的實(shí)例僅在幾個(gè)地方創(chuàng)建。因此我覺(jué)得問(wèn)題應(yīng)該不在ValueStackShadowMap :: get(),我通過(guò)在DataFlow :: Configuration中添加一個(gè)barrier來(lái)排除這種結(jié)果:

這里的意思是如果污染數(shù)據(jù)流入ValueStackShadowMap的get()或containsKey()方法,那么就不要繼續(xù)跟蹤它。 (我在這里添加了containsKey()方法,因?yàn)樗灿型瑯拥膯?wèn)題。)

又為ActionMapping :: toString()添加了barrier之后(因?yàn)樵谌我鈱?duì)象上調(diào)用toString()時(shí)出問(wèn)題),重新運(yùn)行查詢,只留下了部分結(jié)果。 當(dāng)然你也可以嘗試使用Eclipse插件來(lái)顯示污點(diǎn)路徑。

發(fā)現(xiàn)漏洞

只有10對(duì)source和sink,很容易通過(guò)手工檢查這些是否是真正的問(wèn)題。 通過(guò)一些路徑,看出有些路徑是無(wú)效的,所以我又在查詢中添加了一些barrier來(lái)過(guò)濾掉這些路徑。 最后的結(jié)果比較有意思。
以ServletActionRedirectResult.java中的源代碼為例:


在第一步中,調(diào)用getNamespace()的source通過(guò)變量名稱空間流入ActionMapping構(gòu)造函數(shù)的參數(shù)中:

繼續(xù)跟這些步驟,看到getUriFromActionMapping()返回一個(gè)URL字符串,該字符串使用構(gòu)造的ActionMapping中的命名空間。 然后通過(guò)變量tmpLocation流入setLocation()的參數(shù):
然后setLocation()在超類StrutsResultSupport中設(shè)置location:

然后代碼在ServletActionResult上調(diào)用execute():

將location字段傳遞給對(duì)conditionalParse():

conditionalParse()然后將location傳遞給translateVariables(),它將param轉(zhuǎn)化為引擎蓋下的OGNL表達(dá)式:

所以看起來(lái)當(dāng)在ServletActionRedirectResult中沒(méi)有設(shè)置namespace參數(shù)時(shí),代碼從ActionProxy獲取命名空間,然后將其作為OGNL表達(dá)式。 為了驗(yàn)證這個(gè)想法,我通過(guò)以下方法替換了showcase應(yīng)用程序中的一個(gè)配置文件(例如struts-actionchaining.xml)中的struts標(biāo)記:

然后我在本地運(yùn)行showcase應(yīng)用程序,訪問(wèn)了一個(gè)旨在觸發(fā)此漏洞的URL并執(zhí)行shell命令以在我的計(jì)算機(jī)上打開計(jì)算器應(yīng)用程序。

彈出計(jì)算器了(中間還花了一些時(shí)間繞過(guò)OGNL沙箱)。現(xiàn)在我暫時(shí)不提供進(jìn)一步的細(xì)節(jié),后面會(huì)發(fā)出來(lái)。

不單單這一處,來(lái)自ActionChainResult,PostbackResult和ServletUrlRenderer的不可信來(lái)源都能彈出計(jì)算器! PortletActionRedirectResult中的那個(gè)可能也可以,但我沒(méi)有測(cè)試。 四個(gè)RCE足以證明問(wèn)題的嚴(yán)重性。

結(jié)論

在這篇文章中,我已經(jīng)展示了通過(guò)使用已知(過(guò)去)的漏洞來(lái)幫助構(gòu)建應(yīng)用程序的污點(diǎn)模型,然后由 QL DataFlow庫(kù)找新的漏洞。特別是通過(guò)研究Struts中之前的三個(gè)RCE,最終找到了四個(gè)(也可能是五個(gè))!

鑒于S2-032,S2-033和S2-037都是在短時(shí)間內(nèi)被發(fā)現(xiàn)和修復(fù)的,安全研究人員清楚地研究了S2-032用以尋找類似問(wèn)題并發(fā)現(xiàn)S2-033和S2-037。這里就有問(wèn)題了:我發(fā)現(xiàn)的漏洞(S2-057)也來(lái)自類似的污染源,為什么安全研究人員和供應(yīng)商之前沒(méi)發(fā)現(xiàn)?在我看來(lái),這是因?yàn)镾2-032,S2-033和S2-037之間的相似性在某種意義上是局部的,因?yàn)樗鼈兌汲霈F(xiàn)在源代碼中的相似位置(全部在Rest插件中)。 S2-057和S2-032之間的相似性處于更加語(yǔ)義的層面。它們由受污染的源鏈接,而不是源代碼的位置,因此任何能夠成功找到這樣的變體的軟件或工具都需要能夠在整個(gè)代碼庫(kù)中執(zhí)行這種語(yǔ)義分析,就像我現(xiàn)在可演示的QL。

如果你認(rèn)為我的這些發(fā)現(xiàn)只是運(yùn)氣好,因?yàn)槲壹僭O(shè)ActionProxy中的命名空間字段已經(jīng)被污染了,那么請(qǐng)繼續(xù)關(guān)注下一篇文章,我會(huì)展示更多的細(xì)節(jié)問(wèn)題,并從傳入的HttpRequestServlet本身開始,從“第一原則”開始進(jìn)行一些污點(diǎn)跟蹤。我還將從我的“漏洞狩獵工具箱”中分享一些工具,以及一些改進(jìn)查詢的一般提示。在這樣做的過(guò)程中,QL還捕獲了漏洞S2-045!

原文地址:https://lgtm.com/blog/apache_struts_CVE-2018-11776

上一篇:中美研究人員:DNS流量可被劫持并操縱

下一篇:360威脅情報(bào):GlobeImposter勒索病毒攻擊事件分析