log4j2漏洞復(fù)現(xiàn)及漏洞分析
一、漏洞復(fù)現(xiàn)
Apache Log4j2是一個(gè)基于Java的日志記錄工具。該工具重寫(xiě)了Log4j框架,并且引入了大量豐富的特性。該日志框架被大量用于業(yè)務(wù)系統(tǒng)開(kāi)發(fā),用來(lái)記錄日志信息。大多數(shù)情況下,開(kāi)發(fā)者可能會(huì)將用戶(hù)輸入導(dǎo)致的錯(cuò)誤信息寫(xiě)入日志中。
由于Apache Log4j2某些功能(lookup)存在遞歸解析功能,未經(jīng)身份驗(yàn)證的攻擊者通過(guò)發(fā)送特別構(gòu)造的數(shù)據(jù)請(qǐng)求包,可在目標(biāo)服務(wù)器上執(zhí)行任意代碼。
實(shí)際受影響范圍如下:
Apache Log4j 2.x < 2.15.0-rc2
JDK在11.0.1、8u191、7u201、6u211及以上的高版本,將一定程度上導(dǎo)致利用失敗。
復(fù)現(xiàn)環(huán)境:
IDEA 2018 (用最新版的2022編譯時(shí)彈不了,應(yīng)該加了安全限制)
JDK 1.8.0_144
Log4j版本:2.13.3
因?yàn)閷儆趍aven項(xiàng)目,直接通過(guò)pom.xml下載依賴(lài)組件即可:


然后直接運(yùn)行即可:
選擇的jdk版本為1.8

然后先運(yùn)行JNDIExploit,java -jar JNDIExploit-1.2-SNAPSHOT.jar -i IP地址

最后點(diǎn)擊右上角的run就行,最后運(yùn)行結(jié)果如下圖所示:

二、漏洞分析
一般log4j2項(xiàng)目中會(huì)引用到兩個(gè)組件包,log4j-api和log4j-core,log4j-api是日志接口,log4j-core是日志標(biāo)準(zhǔn)庫(kù)。

Log4j2的Lookup主要功能是通過(guò)引用一些變量,往日志中添加動(dòng)態(tài)的值。這些變量可以是外部環(huán)境變量,也可以是MDC中的變量,還可以是日志上下文數(shù)據(jù)等。

env:允許系統(tǒng)在全局文件(如 /etc/profile)或應(yīng)用程序的啟動(dòng)腳本中配置環(huán)境變量,然后在日志輸出過(guò)程中,查找這些變量。例如:${env:USER}。
java:允許查找Java環(huán)境配置信息。例如:${java:version}。
jndi:允許通過(guò) JNDI 檢索變量。
log4j2中包含兩個(gè)關(guān)鍵組件LogManager和LoggerContext。LogManager是Log4J2啟動(dòng)的入口,可以初始化對(duì)應(yīng)的LoggerContext。LoggerContext會(huì)對(duì)配置文件進(jìn)行解析等其它操作。
常見(jiàn)的Log4J用法是從LogManager中獲取Logger接口的一個(gè)實(shí)例,并調(diào)用該接口上的方法。運(yùn)行下列代碼查看打印結(jié)果。

log4j2支持多種日志級(jí)別,通過(guò)日志級(jí)別我們可以將日志信息進(jìn)行分類(lèi),在合適的地方輸出對(duì)應(yīng)的日志。哪些信息需要輸出,哪些信息不需要輸出,只需在一個(gè)日志輸出控制文件中稍加修改即可。級(jí)別由高到低共分為6個(gè):fatal, error, warn, info, debug, trace(堆棧)。

當(dāng)日志級(jí)別(調(diào)用)大于等于系統(tǒng)設(shè)置的intLevel的時(shí)候,log4j2才會(huì)啟用日志打印。在存在配置文件的時(shí)候,會(huì)讀取配置文件中<root level="error">值設(shè)置intLevel。當(dāng)然我們也可以通過(guò)Configurator.setLevel("當(dāng)前類(lèi)名", Level.INFO);來(lái)手動(dòng)設(shè)置。如果沒(méi)有配置文件也沒(méi)有指定則會(huì)默認(rèn)使用Error級(jí)別,也就是200。
在本次漏洞分析過(guò)程中日志等級(jí)為L(zhǎng)evel.LEVEL,它的intLevel()為200,而本環(huán)境中默認(rèn)的日志級(jí)別為ERROR(200),如下圖所示:



轉(zhuǎn)換器名稱(chēng)msg對(duì)應(yīng)的插件實(shí)例MessagePatternConverter對(duì)于日志中的消息內(nèi)容處理存在問(wèn)題,在大多數(shù)場(chǎng)景下這部分是攻擊者可控的。MessagePatternConverter會(huì)將日志中的消息內(nèi)容為${prefix:key}格式的字符串進(jìn)行解析轉(zhuǎn)換,用來(lái)讀取環(huán)境變量等
傳入的message會(huì)通過(guò)MessagePatternConverter.format(),判斷如果config存在并且noLookups為false(默認(rèn)為false),然后匹配到${則通過(guò)getStrSubstitutor()替換原有的字符串,比如這里的${java:os},如下圖所示:

屬性占位符之Interpolator(插值器)
log4j2中環(huán)境變量鍵值對(duì)被封裝為了StrLookup對(duì)象。這些變量的值可以通過(guò)屬性占位符來(lái)引用,格式為:${prefix:key}。在Interpolator(插值器)內(nèi)部以Map<String,StrLookup>的方式則封裝了多個(gè)StrLookup對(duì)象。
這些實(shí)現(xiàn)類(lèi)存在于org.apache.logging.log4j.core.lookup包下,可以看到處理event的時(shí)候根據(jù)前綴選擇對(duì)應(yīng)的StrLookup進(jìn)行處理,目前支持date,jndi,java,main等多種類(lèi)型,如果構(gòu)造的event是jndi,則通過(guò)JndiLoopup進(jìn)行處理,從而構(gòu)造漏洞。如下圖所示:

使用${jndi:key}時(shí),將會(huì)調(diào)用JndiLookup的lookup方法。

因?yàn)镴NDI支持從指定的遠(yuǎn)程服務(wù)器上下載class文件,加載到本地JVM中,并通過(guò)適當(dāng)?shù)姆绞絼?chuàng)建對(duì)象,從而可以利用JNDI注入來(lái)執(zhí)行命令。
三、利用條件
在版本小于Apache Log4j 2.x < 2.15.0-rc2及JDK滿(mǎn)足的情況下,還需以下兩點(diǎn):
1、代碼中日志等級(jí)的優(yōu)先級(jí)高于或等于默認(rèn)級(jí)別(ERROR(200),數(shù)值越低優(yōu)先級(jí)越高)才可以成功。
2、必須能夠控制log方法中的參數(shù)內(nèi)容。
四、修復(fù)方法
在log4j2.component.properties配置文件,增加如下內(nèi)容為:
log4j2.formatMsgNoLookups=true
或者刪除jndilooup類(lèi)文件
posted on 2022-09-28 08:50 st404 閱讀(1557) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)