【安全漏洞】Emissary 的SSRF漏洞(CVE-2021-32639)发现过程
導(dǎo)語:通過在Emissary項(xiàng)目上運(yùn)行標(biāo)準(zhǔn)的CodeQL查詢集,我發(fā)現(xiàn)了之前報(bào)告的任意文件泄露(CVE-2021-32093)。
通過在Emissary項(xiàng)目上運(yùn)行標(biāo)準(zhǔn)的CodeQL查詢集,我發(fā)現(xiàn)了之前報(bào)告的任意文件泄露(CVE-2021-32093),但也發(fā)現(xiàn)了新的漏洞:
不安全的反序列化漏洞 (CVE-2021-32634);
服務(wù)器端請求偽造漏洞(CVE-2021-32639);
原始代碼注入CVE (CVE-2021-32096)是由社區(qū)貢獻(xiàn)的CodeQL查詢標(biāo)記的;
到目前為止,還可以通過默認(rèn)的CodeQL查詢發(fā)現(xiàn)反映的跨站點(diǎn)腳本漏洞(CVE-2021-32092)。
代碼注入 (CVE-2021-32096)
起初我嘗試在Emissary 5.9.0代碼庫上使用CodeQL腳本注入查詢時(shí),卻沒有得到任何結(jié)果。
在閱讀源代碼獲取漏洞細(xì)節(jié)后,我確信我的查詢正確地建模了javax.script.ScriptEngine.eval()接收,并且該源代碼已經(jīng)由默認(rèn)的CodeQL JAX-RS庫建模。然而,我意識到從不受信任的數(shù)據(jù)到腳本注入接收器的流不是“直接的”流。你可以通過查看代碼流的方式來理解其原因。
用戶數(shù)據(jù)進(jìn)入應(yīng)用程序的 JAX-RS 終端是:
getOrCreateConsole(request) 將調(diào)用 RubyConsole.getConsole() ,它會轉(zhuǎn)到:
此代碼啟動一個(gè)運(yùn)行 RubyConsole.run() 方法的新線程(因?yàn)樗鼘?shí)現(xiàn)了 Java Runnable 接口):
但是,由于此時(shí) stringToEval 為 null,因此該方法幾乎會立即使用 wait() 方法暫停線程。
稍后,在 rubyConsolePost 中,我們可以找到以下代碼:
這里是不受信任數(shù)據(jù)(request.getParameter(CONSOLE_COMMAND_STRING))進(jìn)入應(yīng)用程序并流入RubyConsole.evalAndWait()方法的地方。但是,evalAndWait()方法是:
沒有對RubyConsole.eval()方法的實(shí)際調(diào)用,Ruby腳本在該方法中被計(jì)算,因此如果跟蹤受感染的請求參數(shù),你將在該方法中結(jié)束并到達(dá)受感染的跟蹤的末尾。用戶控制的命令只被分配給stringToEval字段,這似乎就到此為止了。然而,如果你仔細(xì)觀察,你還會看到這個(gè)方法正在調(diào)用notifyAll()方法,這意味著這個(gè)方法將有效地激活被暫停的線程,該線程將依次運(yùn)行以下表達(dá)式:
當(dāng)rubyConsolePost方法被調(diào)用時(shí),RubyConsole.run()會以一個(gè)null stringToEval執(zhí)行,然后進(jìn)入wait狀態(tài)。
當(dāng)調(diào)用 evalAndWait(commandString) 時(shí),stringToEval 獲取用戶控制的腳本,然后恢復(fù) RubyConsole.run() 方法,該方法將評估現(xiàn)在分配的 stringToEval。
因此,沒有靜態(tài)代碼分析工具可以有效跟蹤的直接數(shù)據(jù)流。不過,通過使用CodeQL感染步驟對Javawait/notify模式建模,我應(yīng)該能夠發(fā)現(xiàn)這個(gè)漏洞。
在此代碼模式中,你可以看到兩種不同類型的塊:調(diào)用notify的同步塊和調(diào)用wait的同步塊。當(dāng)同步發(fā)生在同一個(gè)對象上時(shí),我想將notify塊中的寫入與wait塊上相同字段的讀取連接起來。這意味著我需要一個(gè)額外的污點(diǎn)步驟來連接這些原本斷開連接的節(jié)點(diǎn),以便 CodeQL 的污點(diǎn)跟蹤可以橋接這種邏輯斷開連接:
啟用這個(gè)額外的感染步驟后,我成功地報(bào)告了這個(gè)漏洞:
令人驚嘆的是,這個(gè)查詢不是由GitHub CodeQL工程師開發(fā)的,而是由幾個(gè)CodeQL社區(qū)成員貢獻(xiàn)和改進(jìn)的:
https://github.com/github/codeql/pull/2850;
https://github.com/github/codeql/pull/5349;
https://github.com/github/codeql/pull/5802;
這個(gè)社區(qū)貢獻(xiàn)的查詢正在進(jìn)入標(biāo)準(zhǔn)查詢集,并將很快提供給所有運(yùn)行 GitHub 代碼掃描的開源項(xiàng)目。
我還向 CodeQL 存儲庫貢獻(xiàn)了我的notify/wait模式感染步驟,這可能很快就會為所有 CodeQL 用戶啟用同步字段之間的類似數(shù)據(jù)流分析!
任意文件泄露 (CVE-2021-32093)
CodeQL 發(fā)現(xiàn)了默認(rèn)配置下的任意文件泄露,因此我不會評論此漏洞的詳細(xì)信息,因?yàn)樗呀?jīng)在 SonarSource文章中進(jìn)行了描述。
不安全的反序列化 (CVE-2021-32634)
CodeQL 默認(rèn)查詢還報(bào)告了三個(gè)不安全的反序列化操作。
第一個(gè)位于 WorkSpaceClientEnqueueAction REST 終端:
可以通過對 /WorkSpaceClientEnqueue.action 的經(jīng)過身份驗(yàn)證的 POST 請求訪問此終端。正如你在源代碼中所讀到的,表單參數(shù) WorkSpaceAdapterWORK_BUNDLE_OBJ (tpObj) 在第 52 行被解碼和反序列化。
幸運(yùn)的是,這是一個(gè)身份驗(yàn)證后的漏洞,由于SonarSource報(bào)告修復(fù)了跨站請求偽造(CSRF)漏洞,因此無法通過CSRF代表已登錄用戶利用該漏洞。
CodeQL 還報(bào)告了另外兩個(gè)當(dāng)前未在代碼中執(zhí)行的不安全反序列化操作。然而,它們可能會在未來的版本中啟用。
第一個(gè)起源于MoveToAction類,它沒有被Jersey服務(wù)器公開。
MoveToAction:
MoveToAdapter:
PayloadUtil:
第二個(gè)方法來源于WorkSpaceAdapter類的inboundEnque方法。該漏洞需要調(diào)用inboundEnque(),但目前尚未執(zhí)行該調(diào)用。
WorkspaceAdapter:
WorkspaceAdapter:
WorkspaceAdapter:
服務(wù)器端請求偽造 (CVE-2021-32639)
在CodeQL中發(fā)現(xiàn)這個(gè)漏洞得益于另一個(gè)社區(qū)的貢獻(xiàn)。報(bào)告此漏洞的查詢最初是由@lucha-bc和@porcupineyhair貢獻(xiàn)的,并且已經(jīng)被提升為任何CodeQL掃描使用的默認(rèn)規(guī)則集。
該查詢報(bào)告了兩個(gè)服務(wù)器端請求偽造 (SSRF) 漏洞。第一個(gè)影響 RegisterPeerAction REST 終端。例如,以下請求將導(dǎo)致多個(gè)請求發(fā)送到位于 http://attacker:9999 的攻擊者控制的服務(wù)器。
需要注意的重要一點(diǎn)是,一些偽造的請求是發(fā)送到 /emissary/Heartbeat.action 終端的未經(jīng)身份驗(yàn)證的請求:
但是,也有經(jīng)過身份驗(yàn)證的請求發(fā)送到攻擊者控制的服務(wù)器上的 /emissary/RegisterPeer.action 終端:
SSRF 漏洞通常用于訪問內(nèi)部服務(wù)器或掃描內(nèi)部網(wǎng)絡(luò),但在這種情況下,我想到了不同的漏洞利用場景。由于 SSRF 漏洞導(dǎo)致 Emissary 使用的 Apache HTTP 客戶端發(fā)送一個(gè)帶有摘要身份驗(yàn)證標(biāo)頭的經(jīng)過身份驗(yàn)證的請求,因此從理論上講,我可以誘使客戶端切換到基本身份驗(yàn)證,從而泄漏服務(wù)器憑證。
要使用 Apache HTTP 客戶端發(fā)送經(jīng)過身份驗(yàn)證的請求,需要在憑據(jù)提供程序上設(shè)置憑據(jù),然后配置 HTTP 客戶端以使用該憑據(jù)提供程序:
可以看到憑據(jù)是從 Jetty 用戶領(lǐng)域讀取的,用于連接到需要憑據(jù)的任何主機(jī)和任何端口。這些憑證在憑證提供程序 (CRED_PROV) 中設(shè)置,該提供程序后來被配置為主要 Emissary 客戶端 (CLIENT) 的默認(rèn)憑證提供程序。
配置沒有指定應(yīng)該使用什么身份驗(yàn)證方案,這讓我相信身份驗(yàn)證方案是根據(jù)服務(wù)器響應(yīng)決定的。如果我禮貌地要求客戶端使用基本身份驗(yàn)證,那么所有跡象都表明服務(wù)器憑據(jù)可能會以明文形式(base64 編碼)發(fā)送。
為此,我設(shè)置了一個(gè)請求基本身份驗(yàn)證的 Web 服務(wù)器,然后使用 SSRF 漏洞使 Emissary 服務(wù)器連接到我的惡意服務(wù)器。 Emissary HTTP客戶端很高興地從摘要身份驗(yàn)證切換到基本身份驗(yàn)證,并將憑據(jù)發(fā)送給我。以下是我的服務(wù)器顯示服務(wù)器憑證的輸出:
同樣,AddChildDirectoryAction 終端也容易受到 SSRF 的攻擊。對 /AddChildDirectory.action 終端的 POST 請求將觸發(fā)對攻擊者控制的主機(jī)的額外請求:
除了修復(fù) SSRF 漏洞之外,NSA還通過只允許摘要身份驗(yàn)證方案來防止身份驗(yàn)證方法的混淆。
反射的跨站點(diǎn)腳本 (CVE-2021-32092)
CodeQL在自動查找SonarSource研究人員報(bào)告的大多數(shù)漏洞和幾個(gè)新的關(guān)鍵漏洞方面做得很好,但是它沒有報(bào)告SonarSource研究人員最初報(bào)告的跨站腳本(XSS)漏洞。我檢查了查詢集,發(fā)現(xiàn)沒有針對這個(gè)特定XSS實(shí)例的查詢。
然后我開始與 CodeQL 團(tuán)隊(duì)合作,對 JAX-RS 終端上的 XSS 漏洞進(jìn)行相當(dāng)全面的分析。這個(gè) XSS 檢測現(xiàn)在也包含在主 CodeQL 存儲庫中!
在 REST 終端上準(zhǔn)確檢測 XSS 并不是一項(xiàng)簡單的任務(wù),因?yàn)樗鼈冎械拇蠖鄶?shù)將默認(rèn)為 application/json 響應(yīng)內(nèi)容類型,這對 XSS 是安全的。因此,我需要 CodeQL 來檢測用戶控制的數(shù)據(jù)(無論是反射的還是持久的)在沒有正確編碼的 HTTP 響應(yīng)中使用,而且還需要檢測此類響應(yīng)的內(nèi)容類型已更改為任何 XSS 友好類型。這可以通過以下幾種方式實(shí)現(xiàn):
通過使用 ResponseBuilder.type() 顯式設(shè)置響應(yīng)內(nèi)容類型;
通過使用 @Produces 注釋來注釋封閉方法;
通過使用 @Produces 注釋來注釋封閉類;
在與 CodeQL 團(tuán)隊(duì)一起進(jìn)行這些查詢改進(jìn)時(shí),我意識到我們對 Spring REST 終端的 XSS 查詢也沒有考慮響應(yīng)內(nèi)容類型,這可能導(dǎo)致許多誤報(bào),例如,帶有應(yīng)用程序/json內(nèi)容類型的響應(yīng)被標(biāo)記為可利用的。因此,我們還實(shí)現(xiàn)了所需的改進(jìn),以使Spring XSS查詢達(dá)到JAX-RS現(xiàn)在擁有精確度。
【安全學(xué)習(xí)資料】
總結(jié)
以上是生活随笔為你收集整理的【安全漏洞】Emissary 的SSRF漏洞(CVE-2021-32639)发现过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学了网络安全以后能做哪些岗位呢?来来来,
- 下一篇: 渗透操作系统——【靶场实战训练营】快来看