Skip to main content
  1. Lab-devsec/

Mustache Project - Home Lab UTM Locale

Alessio Barnini
Author
Alessio Barnini
Table of Contents

Scenario: Mustache Corp Srl detiene il brevetto Formula M-80 — la formula scientifica per far crescere baffi stile anni '80 in 30 giorni. Vale milioni. L'attaccante (Kali, 192.168.64.200) vuole esfiltrarla. Tu sei il Security Engineer che la difende (Ubuntu, 192.168.64.3).


Stack Tecnologico Target
#

Costruito sulle offerte di lavoro reali del mercato EU remoto (Cloud Security Engineer / DevSecOps, 2026).

LayerTecnologiaPerché è qui
Configuration managementAnsibleRichiesto esplicitamente. Hardening automatico.
CI/CDGitHub ActionsPipeline deploy automatico app Mustache Corp
SIEMWazuh (Elastic underneath)Offerte chiedono Elastic/SIEM — Wazuh è Elastic + regole security
IDS/IPSSuricataNominato esplicitamente nelle offerte
Firewalliptables / ufw (Linux)Base di ogni firewall Linux enterprise
IAM on-premSamba 4 AD (Ubuntu)Domain controller Linux-native — Windows Server nella fase cloud
IAM cloudAWS IAM / Azure Entra IDAggiunto nella fase cloud dopo Security+
Container layerDocker + ComposeApp target e servizi ricostruibili in secondi
SegmentazioneDocker networks + iptablesmustache-dmz / mustache-lan isolate via regole
OrchestrazioneKubernetes (k3s)Sprint 7+
ProxySquidForward proxy, content filtering, logging
WAFModSecurity (OWASP CRS)Difesa layer 7 davanti a DVWA
DeceptionOpenCanaryHoneynet — detection lateral movement
AttaccanteKali Linux (UTM locale)192.168.64.200 — attacca Ubuntu
FrameworkMITRE ATT&CKOgni attacco simulato mappato su una tecnica ATT&CK
Provisioning cloudTerraformFase cloud Hetzner dopo Security+ — non serve in locale

Crown Jewels
#

formula-M80.pdf          → /data/confidential/ su Ubuntu  (il vero target)
DB MySQL (Docker)        → tabella `brevetti`, campo `formula_m80`
/mustache-admin          → pannello admin nginx, protetto da credenziali RBAC

Deception Layer
#

OpenCanary (Docker)      → sembra MySQL su porta 3306-fake — trigger alert se connesso
.env sul web container   → DB_HOST=opencanary, DB_PASSWORD=Mustache2024! (falso)
password-backup.txt      → honeyfile nella webroot, inotifywait monitorato
formula-M80-DRAFT.pdf    → copia falsa con Canary Token — alert se aperta ovunque

Architettura — UTM Locale
#

Kali Linux (192.168.64.200) — ATTACCANTE
        │ host-only network 192.168.64.0/24
┌─────────────────────────────────────────────────┐
│           ubuntu-server (192.168.64.3)│                                                 │
│  iptables (firewall stateful — Fase 3)│  Samba 4 AD DC — dominio mustache.corp          │
│  Suricata (IDS/IPS — Fase 3-4)│  Wazuh server+agent (SIEM — Fase 1)│  fail2ban                                       │
│  Squid proxy (Fase 3)│                                                 │
│  ┌──────────────────────────────────────────┐  │
│  │  Docker Network: mustache-dmz            │  │
│  │  nginx + ModSecurity WAF  (80/443)       │  │
│  │  DVWA                     (via nginx)    │  │
│  │  .env falso + honeyfile                  │  │
│  └──────────────────┬───────────────────────┘  │
│                     │ solo nginx → mysql:3306   │
│  ┌──────────────────▼───────────────────────┐  │
│  │  Docker Network: mustache-lan (isolata)  │  │
│  │  MySQL — Formula M-80 crown jewel        │  │
│  │  OpenCanary — fake MySQL (honeynet)      │  │
│  └──────────────────────────────────────────┘  │
└─────────────────────────────────────────────────┘

Mac (192.168.64.1) — host / admin

Regola chiave iptables: Kali non raggiunge mai direttamente MySQL. Passa da nginx→WAF→MySQL via Docker network. OpenCanary è irraggiungibile dall'esterno tranne tramite il .env falso.

Costo totale: €0/mese (fase cloud Hetzner ~€30/mese dopo Security+)


Kill Chain Attaccante (MITRE ATT&CK)
#

T1595 — Reconnaissance      → nmap -sS 192.168.64.3
T1190 — Exploit Public App  → SQLi su login form DVWA
T1059 — Command Execution   → web shell su nginx container
T1552 — Credentials Files   → trova .env con DB_HOST=opencanary
T1021 — Lateral Movement    → tenta connessione a OpenCanary:3306  ← ALERT honeynet
T1083 — File Discovery      → trova password-backup.txt             ← ALERT honeyfile
T1048 — Exfiltration        → scarica formula-M80-DRAFT.pdf        ← ALERT Canary Token
T1110 — Brute Force         → SSH su Ubuntu                        ← fail2ban + Wazuh

Wazuh correla ogni step. Il sabato esegui la kill chain completa e documenti gli alert.


Repository GitHub
#

github.com/[barno]/mustache-project/
├── README.md                         ← architettura + scenario + kill chain
├── ansible/
│   ├── site.yml                      ← playbook master (chiama tutti i ruoli)
│   ├── inventory/hosts.yml
│   └── roles/
│       ├── common/                   ← SSH hardening, fail2ban, base packages
│       ├── wazuh-agent/
│       ├── suricata/
│       └── nginx-waf/
├── docker/
│   ├── docker-compose.yml            ← mustache-app + MySQL + OpenCanary
│   ├── app/Dockerfile
│   └── db/init.sql                   ← crea tabella brevetti + Formula M-80
├── .github/workflows/
│   └── deploy.yml                    ← push → SSH su Ubuntu → docker-compose up
└── writeups/
    └── kill-chain-sprint-03.md       ← attacco documentato con screenshot alert

Sprint 1 — Cap 1: SIEM & Visibility + Configuration Management
#

Goal: Wazuh operativo su Ubuntu, log centralizzati, hardening automatico via Ansible. Gibson: Cap 1 — Security Controls, CIA triad, Detective controls, log aggregation. MITRE: T1110 (Brute Force) — primo attacco rilevabile. DoD: Wazuh mostra eventi in real-time; SSH brute force da Kali genera alert; fail2ban banna l'IP.

Configuration Management — Ansible
#

  • Scrivere ansible/roles/common/: SSH hardening (no password, no root), fail2ban, update automatici
  • Scrivere ansible/inventory/hosts.yml con host Ubuntu (192.168.64.3)
  • ansible-playbook site.yml — applica hardening a Ubuntu
    • Come sai che hai finito: ssh root@192.168.64.3 fallisce; ssh barno@192.168.64.3 -i key funziona

Crown Jewel Setup
#

  • Su Ubuntu: docker-compose up -d → MySQL + tabella brevetti con formula_m80
  • Su Ubuntu: creare /data/confidential/formula-M80.pdf (contenuto fittizio)
  • Docker: nginx up con pagina login "Mustache Corp Portal"
  • Piazzare .env falso e password-backup.txt nella webroot del container

SIEM — Wazuh
#

  • Installare Wazuh server+agent su Ubuntu (script ufficiale)
  • Abilitare FIM su /data/confidential/
  • Configurare inotifywait su password-backup.txt → log a Wazuh
    • Come sai che hai finito: modifichi formula-M80.pdf → alert Wazuh in < 60 sec

Verifica finale Sprint 1
#

□ ansible-playbook: SSH password disabilitato su Ubuntu
□ Wazuh: vedo eventi da Ubuntu in real-time
□ FIM: modifica formula-M80.pdf → alert entro 60 sec
□ fail2ban: 5 tentativi SSH da Kali → IP bannato + alert Wazuh
□ GitHub: repo creato, ansible/ committato

Sprint 2 — Cap 2: IAM + Active Directory
#

Goal: AD DS operativo, utenti Mustache Corp su dominio, RBAC implementato. Gibson: Cap 2 — AAA, RBAC, least privilege, account lockout, MFA, account lifecycle. MITRE: T1078 (Valid Accounts), T1110 (Brute Force) — rilevabili con AD event logs su Wazuh. DoD: login come honeyadmin genera alert critico; webadmin non può accedere a MySQL.

🔗 Lab già completati (da integrare nel contesto Mustache)
#

Questi lab coprono le competenze del cap 2. Adattali al dominio mustache.corp.

  • [[[TODO] lab-active-directory-sso-kerberos|lab-active-directory-sso-kerberos]] → Samba AD DC, RBAC con gruppi, SSO + ticket Kerberos
  • [[[TODO] lab-linux-acl-dac|lab-linux-acl-dac]] → setfacl/getfacl per proteggere /data/confidential/

Active Directory Mustache Corp
#

  • Installare Samba 4 su Ubuntu come Domain Controller
  • Creare dominio mustache.corp
  • Creare OU MustacheCorp con utenti: webadmin, dbadmin, siem-operator, honeyadmin
  • Group Policy: account lockout dopo 5 tentativi, password complexity, audit logon events
    • Come sai che hai finito: net accounts /domain mostra le policy; log Samba visibile

RBAC Linux + ACL
#

  • AllowUsers su Ubuntu per ruolo (webadmin solo su container nginx, dbadmin solo su MySQL)
  • setfacl su /data/confidential/formula-M80.pdf → solo dbadmin ha lettura
    • Come sai che hai finito: getfacl /data/confidential/formula-M80.pdf mostra ACE corrette

Wazuh — Samba Event Logs
#

  • Configurare Wazuh per ingestire log Samba (/var/log/samba/log.samba)
  • Regola custom: alert CRITICO se honeyadmin effettua login
    • Come sai che hai finito: login come honeyadmin → alert Wazuh in < 30 sec

PAM + Lockout
#

  • Configurare faillock su Ubuntu: 5 tentativi → lockout 15 min
  • Test da Kali: 5 SSH fail → account bloccato + alert Wazuh
    • Come sai che hai finito: faillock --user barno mostra i tentativi falliti

Verifica finale Sprint 2
#

□ AD: utenti Mustache Corp esistono nel dominio mustache.corp
□ Group Policy: lockout dopo 5 tentativi (verificato da Kali)
□ honeyadmin login → alert CRITICO Wazuh in < 30 sec
□ webadmin accesso a MySQL → Permission denied
□ setfacl su formula-M80.pdf: solo dbadmin legge
□ Samba logs visibili in Wazuh

Sprint 3 — Cap 3: Architecture + Network Segmentation
#

Goal: Doppio firewall (iptables stateful), Docker networks come segmentazione, Suricata vede tutto, kill chain completa rilevabile. Gibson: Cap 3 — screened subnet, Zero Trust, firewall types, jump server, IDS/IPS, network appliances. MITRE: T1595 (Recon/PortScan), T1021 (Lateral Movement) — rilevati da Suricata. DoD: nmap da Kali → Suricata alert in < 10 sec; MySQL irraggiungibile da Kali direttamente.

🔗 Lab già completati (da integrare nel contesto Mustache)
#

Questi lab coprono le competenze del cap 3. Verifica che le regole valgano per il setup Mustache.

  • [[[TODO] lab-router-acl-iptables|lab-router-acl-iptables]] → ACL iptables/ufw per filtraggio per IP/porta/protocollo
  • [[[TODO] lab-iptables-stateful|lab-iptables-stateful]] → conntrack stateful — ESTABLISHED,RELATED per return traffic
  • [[[TODO] lab-jump-server-ssh|lab-jump-server-ssh]] → Mac→Ubuntu→container: bastion host pattern
  • [[[TODO] lab-squid-proxy|lab-squid-proxy]] → Squid forward proxy con content filtering e logging
  • [[[TODO] lab-snmp-v2-v3|lab-snmp-v2-v3]] → monitoraggio sicuro v3 (auth SHA + cifratura AES)
  • [[[TODO] lab-cisco-cap03|lab-cisco-cap03]] → topologia DMZ/VLAN/ACL su Packet Tracer (conceptual reference)

Firewall iptables — Mustache Corp
#

  • iptables stateful su Ubuntu: permetti solo 80/443 TCP + 22 SSH da Mac in ingresso
  • Implicit deny tutto il resto verso Ubuntu host
    • Come sai che hai finito: nmap -p 1-1000 192.168.64.3 da Kali → solo 2-3 porte aperte

Docker Network Segmentation
#

  • Creare Docker network mustache-dmz e mustache-lan
  • nginx e DVWA su mustache-dmz; MySQL e OpenCanary su mustache-lan
  • iptables: blocca traffico diretto Kali → mustache-lan (solo nginx può attraversare)
    • Come sai che hai finito: da Kali mysql -h 172.x.x.x → timeout; via DVWA → funziona

nginx + ModSecurity WAF
#

  • Docker: nginx reverse proxy davanti a DVWA, ModSecurity con OWASP CRS
  • GitHub Actions: push su main → SSH su Ubuntu → docker-compose pull && up -d
    • Come sai che hai finito: SQLi basilare su DVWA → WAF risponde 403; push GitHub → deploy automatico

Suricata — IDS passivo
#

  • Installare Suricata su Ubuntu in modalità af-packet sull'interfaccia host-only
  • Abilitare ruleset ET Open, regola custom per SQLi nei payload HTTP
    • Come sai che hai finito: nmap -sS 192.168.64.3 da Kali → alert Suricata in < 10 sec

Honeynet — OpenCanary
#

  • Docker: OpenCanary configurato come MySQL fake su porta 3306 in mustache-lan
  • Wazuh: alert CRITICO se connessione a OpenCanary
    • Come sai che hai finito: tentativo connessione al fake DB → alert CRITICO in < 30 sec

Verifica finale Sprint 3 — Kill Chain Completa
#

Esegui questa sequenza da Kali, documenta ogni alert in Wazuh:

1. nmap -sS 192.168.64.3              → T1595 — Suricata alert port scan
2. SQLi su DVWA (low security)        → T1190 — WAF log + Suricata HTTP alert
3. Web shell su nginx container       → T1059 — Wazuh process alert
4. mysql -h IP_opencanary             → T1021 — ALERT CRITICO honeynet
5. cat password-backup.txt            → T1552 — ALERT honeyfile inotifywait
6. mysql -h 172.x.x.x (mustache-lan) → T1021 — timeout (iptables blocca)
7. Scarica formula-M80-DRAFT.pdf      → T1048 — ALERT Canary Token via email

□ Tutti e 7 gli step hanno generato alert su Wazuh
□ Kill chain scritta in writeups/kill-chain-sprint-03.md con screenshot
□ Commit GitHub: "sprint-03: full kill chain documented"

Sprint 4 — Cap 4: IDS/IPS avanzato + Suricata inline
#

Goal: Suricata passa da IDS passivo a IPS inline; OpenCanary presidia 3 porte fake; SYN flood bloccato automaticamente. Gibson: Cap 4 — IDS/IPS, detection methods, honeypot/honeynet/honeyfile, honeytoken. MITRE: T1498 (DoS), T1046 (Network Scanning), T1021 (Lateral Movement → OpenCanary). DoD: SYN flood da Kali → Suricata blocca in < 5 sec; SSH su OpenCanary fake → alert CRITICO Wazuh in < 30 sec.

Suricata — da IDS a IPS (nfqueue)
#

  • Modificare config Suricata: modalità nfq (inline) invece di af-packet (passivo)
  • iptables: traffico in ingresso → NFQUEUE prima di essere accettato
  • Test SYN flood: hping3 -S --flood 192.168.64.3 da Kali → traffico bloccato automaticamente
    • Come sai che hai finito: durante hping3, curl http://192.168.64.3 da Mac → timeout (bloccato da Suricata IPS)

Regole Custom Suricata
#

  • Regola port scan aggressivo (T1046): > 20 porte/sec → drop + alert
  • Regola SSH brute force (T1110): > 5 tentativi SSH in 60 sec → drop
  • Regola SQLi HTTP (T1190): pattern UNION SELECT o ' OR '1'='1 nei payload → alert
    • Come sai che hai finito: nmap -sS --min-rate 1000 192.168.64.3 → Suricata log mostra [Drop] + alert in Wazuh

OpenCanary — Deception Layer esteso
#

  • Avviare OpenCanary con porte fake: SSH (2222), HTTP (8080), FTP (2121)
  • Wazuh: regola custom alert CRITICO per ogni connessione alle porte OpenCanary
  • Test da Kali: ssh -p 2222 192.168.64.3 e curl http://192.168.64.3:8080 → alert CRITICO entro 30 sec
    • Come sai che hai finito: Wazuh dashboard mostra alert con rule.level >= 12 per ogni tentativo

Honeytoken — Canary Token su formula-M80
#

  • Generare Canary Token PDF su canarytokens.org
  • Sostituire formula-M80-DRAFT.pdf con il Canary Token PDF
  • Test: aprire il PDF da Kali → email di alert arriva entro 60 sec

Verifica finale Sprint 4
#

□ SYN flood da Kali → Suricata IPS blocca automaticamente (curl timeout durante flood)
□ nmap aggressivo → regola custom Suricata scatta, drop visibile nei log
□ ssh -p 2222 192.168.64.3 → alert CRITICO Wazuh in < 30 sec
□ curl http://192.168.64.3:8080 → alert CRITICO Wazuh in < 30 sec
□ Apri formula-M80-DRAFT.pdf → email Canary Token arriva entro 60 sec
□ writeups/kill-chain-sprint-04.md con screenshot aggiornati

Sprint 5 — Cap 5: Securing Hosts + IaaS Responsibility + Encryption
#

Goal: Applicare la shared responsibility model in pratica su una VPS IaaS reale (Hetzner), poi hardening host + PKI interna su Mustache Corp. Gibson: Cap 5 — virtualization, shared responsibility model (IaaS/PaaS/SaaS), hardening, disk encryption, PKI, TLS. Contesto: In IaaS il provider gestisce solo l'hardware. OS, firewall, patch, middleware = responsabilita' del cliente. La VPS Hetzner con Chatwoot/n8n e' il banco di prova reale.


IaaS Shared Responsibility — Hetzner VPS (lab su server reale)
#

La VPS Hetzner con Chatwoot e n8n e' IaaS puro. Al momento non ha ufw. I database sono blindati dai container Docker (bind su 127.0.0.1), ma manca il layer di difesa in profondita'.

  • Audit porte aperte

    ss -tlnp
    • Come sai che hai finito: hai la lista completa di cosa e' esposto su 0.0.0.0
  • Installare e configurare ufw

    ufw default deny incoming
    ufw default allow outgoing
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw allow 22/tcp    # o la porta SSH che usi
    ufw enable
    • Come sai che hai finito: ufw status verbose mostra le regole; ss -tlnp da esterno mostra solo 80/443/SSH
  • Hetzner Cloud Firewall (difesa in profondita')

    • Aggiungere le stesse regole sul firewall di rete nella console Hetzner
    • Questo blocca il traffico prima che arrivi al server (layer separato da ufw)
    • Come sai che hai finito: scan da esterno con nmap -p 1-1000 <IP> mostra solo le porte autorizzate
  • Verifica che Docker non bypassa ufw

    • Docker di default modifica iptables e puo' esporre porte bypassando ufw
    • Controllare /etc/docker/daemon.json → aggiungere "iptables": false se necessario o usare DOCKER-USER chain
    • Come sai che hai finito: porta interna Docker non raggiungibile dall'esterno anche dopo docker-compose up

Encryption + PKI — Mustache Corp (UTM locale)
#

  • CA privata con step-ca su Ubuntu
  • Certificati TLS interni per nginx (non self-signed, emessi dalla CA)
  • formula-M80.pdf cifrato con GPG, chiave in password manager
  • TLS 1.3 only su nginx, testssl.sh → zero vuln
  • MITRE: T1557 (Adversary-in-the-Middle) — verificare che TLS lo prevenga

Sprint 6 — Cap 6: Threat Actors + Vulnerability Management
#

Stub — da espandere quando si studia Cap 6

  • OpenVAS/Greenbone scan contro DVWA — identificare CVE con CVSS scoring
  • Remediation di 3 vulnerabilità trovate, nuovo scan → differenza documentata
  • Simulare ransomware su Ubuntu: script cifra /tmp/test/ → Wazuh FIM alert
  • MITRE: T1486 (Data Encrypted for Impact)

Sprint 7 — Cap 7: Application Security + Web Attacks + Kubernetes
#

Stub — da espandere quando si studia Cap 7

  • DVWA: SQLi, XSS, Command Injection (low → high, documentare la progressione)
  • DNS filtering con Pi-hole (container)
  • Email security: Postfix + OpenDKIM + SPF
  • [[[TODO] lab-dll-injection-ld-preload|lab-dll-injection-ld-preload]] — DLL injection via LD_PRELOAD + Wazuh FIM
    • Scrivere malware.so che intercetta puts()
    • Iniettare via LD_PRELOAD su processo in esecuzione
    • Sostituire .so su disco → Wazuh FIM rileva la modifica in < 60 sec
    • dpkg --verify per confrontare hash contro database pacchetti
  • GitHub Actions — CI/CD security ← comparso spesso nelle offerte di lavoro
    • Pipeline deploy già presente in .github/workflows/deploy.yml
    • Aggiungere step di sicurezza: npm audit, SAST (Semgrep o CodeQL), secret scanning
    • Branch protection su main: PR obbligatoria, status check CI verde prima del merge
    • Secrets management: credenziali Ubuntu mai in chiaro nel workflow, solo via GitHub Secrets
    • Obiettivo: capire come si protegge una pipeline CI/CD, non solo come si usa
  • Kubernetes (k3s): migrare mustache-app da Docker Compose a k3s
    • Network Policy k3s = segmentazione mustache-dmz/lan ma per i pod
    • RBAC k3s = IAM per workload
    • kubectl audit log → Wazuh
  • MITRE: T1190 (Web exploit), T1071 (C2 over HTTP/DNS)

Sprint 8 — Cap 8: Vulnerability Management + Cloud (Hetzner upgrade)
#

Stub — da espandere dopo Security+. Qui si migra da UTM locale a Hetzner.

  • Terraform: provisioning infra Hetzner (6 VPS + private networks)
  • Ansible: applica tutti i ruoli dei sprint precedenti sulla nuova infra cloud
  • Windows Server 2022: aggiungere VM Hetzner con AD DS reale
  • NetFlow export → ntopng — baseline traffico normale vs attacco
  • AWS o Azure: replicare il layer DMZ (VPC/VNET + Security Groups)
  • WireGuard: accesso admin sicuro al lab cloud
  • MITRE: mappare tutte le tecniche usate nei sprint precedenti su ATT&CK Navigator

Note Operative
#

  • Kali su UTM (192.168.64.200) — attacca Ubuntu (192.168.64.3)
  • Ogni sprint: commit + writeup kill chain con screenshot alert su GitHub
  • docker-compose down quando non studi → risparmio risorse Mac
  • Screenshot obbligatori: Wazuh dashboard prima/dopo ogni attacco simulato
  • Lab singoli cap-02/cap-03 già completati: richiamarli nel writeup con il link al file lab specifico

Related