
log4j 漏洞一些特殊的利用方式
背景
正愁本周沒主題可寫,結(jié)果兩天前就曝了一個核彈級的漏洞“l(fā)og4j RCE”,這兩天官方的修補方案也逐漸完善。所以本篇就拿 log4j 作為主題講一下我的幾個發(fā)現(xiàn)。
RCE
log4j RCE 原理已經(jīng)有挺多人發(fā)過了,本文不過多贅述。簡單說就是日志在打印時遇到 ${ 后 Interpolator 類按照 : 分割出第一部分作為 prefix 第二部分作為 key。通過 prefix 去找對應(yīng)的 lookup,再通過對應(yīng)的 lookup 實例調(diào)用 lookup 方法傳入 key 作為參數(shù)。
log4j-core 自帶的 lookup 有很多實例,其中就包括了此次存在漏洞的 JndiLookup 實例。JndiLookup 則是直接把傳進來的 key 當(dāng)做 JNDI URL 用 InitialContext.lookup 去訪問,從而造成了 JNDI 代碼執(zhí)行漏洞。
WAF bypass
該漏洞曝光后各安全廠商也紛紛推出了解決方案,WAF、RASP、改源碼、改配置文件、更新到rc2等。
在此次漏洞中最沒有防御效果的就是 WAF 了。有提出?${?、jndi、ldap、rmi?等關(guān)鍵詞規(guī)則的防護。但研究后發(fā)現(xiàn)都會存在被繞過問題。
首先是 jndi、ldap 簡直太容易被繞過,只要用 lowerCase upperCase 就可以把關(guān)鍵詞分割開。
如果是用了正則的話那還可以使用 upper 把 jnd? 轉(zhuǎn)成 jndi。
注意:這里的??(\u0131)?不是?i(\x69)和I(\x49),經(jīng)過 toUpperCase 就會轉(zhuǎn)變成 I。從而繞過了 jndi 關(guān)鍵詞的攔截。
再就是 ${ 關(guān)鍵詞的攔截了,雖然這個范圍有點大可能會產(chǎn)生一些誤報,但鑒于漏洞的嚴(yán)重性還是有很多人建議攔截 ${
但這樣也未必能夠真正的解決,因為漏洞的觸發(fā)點是在打印日志的時候把可控內(nèi)容攜帶進去了。那么可控內(nèi)容從哪里來?
Header、URL、鍵值對參數(shù)、JSON參數(shù)、XML參數(shù) ...
現(xiàn)在隨著 JSON 數(shù)據(jù)格式的流行,很多系統(tǒng)都在使用 JSON 處理參數(shù),JSON 處理庫用的最多的就數(shù) Jackson和fastjson。
而 Jackson 和 fastjson 又有 unicode 和 hex 的編碼特性。
例如:
{"key":"\u0024\u007b"} {"key":"\x24\u007b"}
這樣就避開了數(shù)據(jù)包中有 ${ 的條件,所以 WAF 的防護規(guī)則還要多考慮幾種編碼。
信息泄露
sys、env 這兩個 lookup 的 payload 也在討論中被頻繁提起,實際上他們分別對應(yīng)的是?System.getProperty()?和?System.getenv(),能夠獲取一些環(huán)境變量和系統(tǒng)屬性。部分內(nèi)容是可以被攜帶在 dnslog 傳出去的。
除了 sys、env 以外我還發(fā)現(xiàn) ResourceBundleLookup 也可以獲取敏感信息,但沒有看到有人討論 Bundle,所以重點講一下。
public String lookup(final LogEvent event, final String key) { if (key == null) { return null; } final String[] keys = key.split(":"); final int keyLen = keys.length; if (keyLen != 2) { LOGGER.warn(LOOKUP, "Bad ResourceBundle key format [{}]. Expected format is BundleName:KeyName.", key); return null; } final String bundleName = keys[0]; final String bundleKey = keys[1]; try { // The ResourceBundle class caches bundles, no need to cache here. return ResourceBundle.getBundle(bundleName).getString(bundleKey); } catch (final MissingResourceException e) { LOGGER.warn(LOOKUP, "Error looking up ResourceBundle [{}].", bundleName, e); return null; } }
從代碼上來看就很好理解,把 key 按照 : 分割成兩份,第一個是 bundleName 獲取 ResourceBundle,第二個是 bundleKey 獲取 Properties Value
ResourceBundle 在 Java 應(yīng)用開發(fā)中經(jīng)常被用來做國際化,網(wǎng)站通常會給一段表述的內(nèi)容翻譯成多種語言,比如中文簡體、中文繁體、英文。
那開發(fā)者可能就會使用 ResourceBundle 來分別加載 classpath 下的 zh_CN.properties、en_US.properties。并按照唯一的 key 取出對應(yīng)的那段文字。例如:?zh_CN.properties
LOGIN_SUCCESS=登錄成功
那?ResourceBundle.getBundle("zh_CN").getString("LOGIN_SUCCESS")
?獲取到的就是?登錄成功
如果系統(tǒng)是 springboot 的話,它會有一個 application.properties 配置文件。里面存放著這個系統(tǒng)的各項配置,其中有可能就包含 redis、mysql 的配置項。當(dāng)然也不止 springboot,很多其他類型的系統(tǒng)也會寫一些類似 jdbc.properties 的文件來存放配置。
這些 properties 文件都可以通過 ResourceBundle 來獲取到里面的配置項。所以在 log4j 中 Bundle 是比sys和env更嚴(yán)重的存在。
在不出網(wǎng)的環(huán)境下可以通過 dnslog 的方式來外帶信息。
除了dnslog以外還可以通過這兩種方法來獲取信息。
ldap
dns
修復(fù)方案
log4j 更新到最新版本
[超站]友情鏈接:
四季很好,只要有你,文娛排行榜:https://www.yaopaiming.com/
關(guān)注數(shù)據(jù)與安全,洞悉企業(yè)級服務(wù)市場:https://www.ijiandao.com/

隨時掌握互聯(lián)網(wǎng)精彩
- 1 看總書記關(guān)心的清潔能源這樣發(fā)電 7904174
- 2 今年最強臺風(fēng)來襲 7809623
- 3 澳加英宣布承認(rèn)巴勒斯坦國 7713627
- 4 長春航空展這些“首次”不要錯過 7618607
- 5 43歲二胎媽媽患阿爾茨海默病 7521370
- 6 iPhone 17橙色斜挎掛繩賣斷貨 7425342
- 7 老奶奶去世3年 鄰居幫打掃門前落葉 7331845
- 8 三所“零近視”小學(xué)帶來的啟示 7236423
- 9 女兒發(fā)現(xiàn)父親500多萬遺產(chǎn)用于保健 7141458
- 10 英國航母從南?!傲锪恕?/a> 7042247