
Enumeración anónima de Active Directory en una sola pasada sobre SAMR y LSARPC — sesión nula, sin credenciales, con salida estructurada y reutilizable.
Un enumerador de Active Directory de una sola pasada para una sesión anónima (null), utilizando las named pipes \samr y \lsarpc. No se requieren credenciales.
No hace nada que las herramientas clásicas no puedan hacer. Lo que hace es reunirlo todo en una sola ejecución y presentar los resultados de forma limpia. En un engagement llegas sin ninguna cuenta de dominio, encuentras el DC a través de DNS, y quieres la imagen completa: cuentas, detalle por usuario, grupos, política y los detalles de LSA/DNS, sin tener que encadenar sesiones de rpcclient o varios scripts separados y luego parsear su stdout a mano. Esto hace esa pasada por ti y escribe una salida estructurada y reutilizable:
manifest.json, userlist.txt / computerlist.txt listos para usar, y una lista de RIDs guardada que puedes reutilizar en lugar de hacer fuerza bruta dos veces.Por favor, ejecuta esto solo contra sistemas que poseas o estés explícitamente autorizado a probar. Enumerar el directorio de otra persona sin permiso no está bien, y dependiendo de dónde estés puede ser ilegal.
Hay dos versiones que se comportan de forma idéntica. Usa la biblioteca que tengas:
adnullenum.py — construido sobre impacket.$) se separan de los usuarios reales.También marca cuentas interesantes por ti: cosas como "contraseña no requerida", "la contraseña nunca expira", AS-REP-roastable, delegación sin restricciones, nunca inició sesión, o una descripción que menciona una contraseña.
Un par de cosas que se derivan naturalmente de esto:
Todo aquí es SAMR/LSARPC anónimo estándar, y las herramientas establecidas ya alcanzan los mismos datos. Esto es un envoltorio de conveniencia, no una nueva capacidad, así que vale la pena conocer las alternativas:
--rid-brute, --users, --pass-pol) cubre la misma enumeración dentro de un framework mucho más grande.samrdump.py (usuarios/grupos/alias + detalle por usuario) y lookupsid.py (RID cycling sobre LSA). Sin una sola ejecución, sin fallback SAMR→LSA, solo stdout.rpcclient expone las llamadas subyacentes (queryuser, enumdomusers, querydominfo, lsaquery, lookupsids, …) pero de forma interactiva y solo stdout. Su enumdomusers lista usuarios estándar por nombre, sin cuentas de máquina ($), y el detalle completo es queryuser de uno en uno. Sin un bucle de RID-cycling integrado no puede recuperar equipos ni sortear la enumeración restringida. Ver Hacerlo a mano.Lo que adnullenum añade es el empaquetado: una sola ejecución de sesión nula en lugar de varias herramientas, SAMR primero con un fallback LSA opcional, flags curados de cuentas interesantes, y una salida ordenada multiformato que puedes pasar directamente al siguiente paso o reabrir más tarde. Si ese flujo de trabajo encaja con cómo trabajas, úsalo; si prefieres una herramienta probada en batalla, recurre a enum4linux-ng o NetExec.
Necesitas Python 3.9+ y una biblioteca SMB. Un entorno virtual lo mantiene ordenado:
# clone / copy the files, then from the project folder:
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install impacket # for adnullenum.py
Eso es todo. Ejecuta python3 adnullenum.py --help para verlo todo.
Todo se ejecuta a través de un único --mode. El predeterminado es recon, que es lo seguro para ejecutar primero.
| Modo | Qué obtienes |
|---|---|
recon | Información del dominio, recuentos, política de contraseñas/bloqueo, y los detalles de LSA/DNS. Sin fuerza bruta. Solo un vistazo. |
rids | Encuentra qué cuentas existen y las clasifica en usuarios / equipos / grupos. |
users | Lo anterior, más el detalle completo de cada usuario real y el resumen de "cuentas interesantes". Añade --include-groups para listar también los grupos de cada usuario. |
groups | Grupos de dominio y alias integrados con sus miembros. |
full | Todo ello. |
# 1. Is anonymous access open, and how big is this domain?
python3 adnullenum.py 10.0.0.10
# 2. Grab everything
python3 adnullenum.py 10.0.0.10 --mode full
# 3. Just the account inventory, wider net for a big domain
python3 adnullenum.py 10.0.0.10 --mode rids --start-rid 1000 --max-rid 200000
# 4. Go slower to stay quiet
python3 adnullenum.py 10.0.0.10 --mode users --sleep 1 --jitter 40
# 5. Also write JSON (txt and csv are always written)
python3 adnullenum.py 10.0.0.10 --mode full --json
Si el dominio no te permite listar usuarios directamente (habitual), la herramienta recurre al RID cycling: pide al DC que traduzca los IDs de cuenta a nombres en lotes de 1000. Por defecto barre hacia arriba hasta que ha encontrado todo lo que el DC dice que existe, o hasta que 5000 IDs seguidos vuelven vacíos. Puedes fijarlo a un rango exacto en su lugar:
python3 adnullenum.py 10.0.0.10 --mode rids --range 500-50000
Algunos DCs rechazan SAMR anónimo por completo (enumdomains y la traducción de RIDs vuelven ACCESS_DENIED). La ejecución no se rinde:
\lsarpc, que con frecuencia responde cuando SAMR no lo hace.--lsa-fallback, la herramienta reintenta el mismo barrido sobre LSA LsarLookupSids usando el SID del dominio, lo que aún te da el inventario de cuentas (nombres y tipos, incluidos los equipos). Está desactivado por defecto porque es una segunda pasada de fuerza bruta; sin el flag la ejecución se detiene en recon y lo indica.Encontrar las cuentas es la parte lenta, así que la herramienta guarda la lista (rids.txt) en la carpeta de salida de cada ejecución. Apunta una ejecución posterior a esa carpeta con --session y se salta la fuerza bruta y reutiliza lo que ya encontraste:
python3 adnullenum.py 10.0.0.10 --mode rids
# -> output/20260917-1530_10.0.0.10_rids/
python3 adnullenum.py 10.0.0.10 --mode users \
--session output/20260917-1530_10.0.0.10_rids
--session toma la carpeta de una ejecución anterior. (--rid-file hace lo mismo desde un archivo de texto plano con un RID por línea.)
Cada ejecución deja una carpeta con marca de tiempo bajo output/:
output/20260917-1530_10.0.0.10_full/
├── rids.txt # the account IDs found (reuse with --session)
├── manifest.json # summary: counts, interesting accounts, run details
├── access_denied.txt # only if something was denied/restricted (with a timestamp)
├── output
├──── lists/ # ready-to-use lists (see below)
├──── txt/ # easy to read
└──── csv/ # easy to grep / open in a spreadsheet
txt y csv siempre se escriben; añade --json para una carpeta json/ también.
La carpeta lists/ contiene dos archivos planos hechos para alimentar directamente a otras herramientas:
lists/userlist.txt — para meter directamente en AS-REP roasting, password spraying, o la lista --users de un cracker. En modo users/full contiene solo cuentas habilitadas; en modo rids (sin detalle por usuario) es todos los usuarios.lists/computerlist.txt — nombres de cuentas de máquina con el $ conservado (el sAMAccountName), para las comprobaciones de cuentas de máquina pre-Windows 2000.¿Olvidaste mirarlos, o solo ejecutaste rids y ahora quieres las listas? Apunta a la carpeta de la ejecución y se reconstruyen desde los CSVs, sin necesidad de red:
python3 adnullenum.py --lists-from output/20260917-1530_10.0.0.10_full
En pantalla obtienes una vista previa limitada para que un dominio grande no inunde tu terminal (--limit, por defecto 100 por sección) — los archivos siempre tienen los datos completos. El color está activado cuando estás en un terminal; --no-color lo desactiva.
Una ejecución full contra un DC de prueba (saneado). En pantalla obtienes el recon, el barrido de RIDs, el resumen de cuentas interesantes, y la lista de archivos escritos:
$ python3 adnullenum.py 10.0.0.10 --mode full
[*] Connecting to 10.0.0.10:445 anonymously ...
[+] SAM domain: CORP (S-1-5-21-1111111111-2222222222-3333333333)
...
[ COUNTS ]
Users: 43
Groups: 0
Aliases: 17
[ PASSWORD POLICY ]
Min length: 7
Max age: 42 days
Properties: COMPLEX
[*] Bruting RIDs via SAMR (chunk=1000, open-ended 500-100000, stop-after 5000)
[*] up to RID 1498: 31 resolved, gap=0
[*] stop: 5000 consecutive empty RIDs (--stop-after 5000)
[+] Resolved: 5 users, 4 computers, 22 groups, 0 other
[*] Deep-querying 5 users (skipping 4 computers)
[!] Administrator (RID 500) PWD_NEVER_EXPIRES
[!] Guest (RID 501) (disabled) PWD_NOT_REQUIRED, PWD_NEVER_EXPIRES
[!] svc_sql (RID 1104) ASREP_ROASTABLE
[+] 5 users: 3 enabled, 2 disabled, 3 interesting (full detail in the users file)
[ FILES WRITTEN in output/20260101-120000_10.0.0.10_full ]
txt/recon.txt / csv/recon.csv domain info + password/lockout policy
txt/inventory.txt / csv/inventory.csv all resolved accounts
txt/users.txt / csv/users.csv full per-user detail
txt/groups.txt / csv/groups.csv groups + aliases with members
rids.txt existing RIDs (reuse with --session)
lists/userlist.txt usernames, one per line
lists/computerlist.txt machine accounts (with $)
manifest.json run metadata + counts
Un único registro de txt/users.txt (el grupo primario y los grupos directos se resuelven a nombres):
[+] RID 500
Enabled: True
SamAccountName: Administrator
SID: S-1-5-21-1111111111-2222222222-3333333333-500
Description/AdminComment: Built-in account for administering the computer/domain
Last Logon: 2026-09-03 17:58:26+09:00
Password Last Set: 2026-01-23 05:14:35+09:00
Primary Group: Domain Users (513)
Account Control: NORMAL_ACCOUNT | PASSWORD_NEVER_EXPIRES
Logon Count: 92
Direct Domain Groups: Domain Users; Administrators; Domain Admins
>> INTERESTING: PWD_NEVER_EXPIRES
Todo aquí es SAMR/LSARPC estándar, así que puedes obtener los mismos datos llamada a llamada con el rpcclient de Samba. Conéctate anónimamente primero:
rpcclient -U "" -N 10.0.0.10
| Esta herramienta | Equivalente en rpcclient |
|---|---|
recon (información del dominio + recuentos) | querydominfo |
recon (política de contraseñas) | getdompwinfo |
recon (dominio LSA + SID) | lsaquery, lsaenumsid |
rids (traducción nombre/SID) | lookupnames <name>, lookupsids <SID> |
rids (lista del lado del servidor) | enumdomusers (solo usuarios estándar — sin cuentas de máquina $) |
users (detalle por usuario) | queryuser <rid> o queryuser <name>, querydispinfo |
groups | enumdomgroups, querygroupmem <rid>, enumalsgroups builtin, queryaliasmem builtin <rid> |
enumdomusers devuelve cuentas de usuario estándar solo por nombre; las cuentas de máquina ($) se filtran, y el detalle completo significa ejecutar queryuser de una cuenta en una. rpcclient no tiene un bucle de RID-cycling integrado, así que no puede recuperar las cuentas de máquina (ni nada más) cuando la enumeración del lado del servidor está restringida; tendrías que scriptear lookupsids sobre un rango tú mismo. Tampoco tiene comando de política de bloqueo y no devuelve el DNS/bosque/GUID de LSA ni los trusts, por lo que esta herramienta consulta PolicyDnsDomainInformation directamente.
Para equivalentes scripteados y cómo se relaciona esta herramienta con ellos, ver Cómo se compara.
Si estás en el lado azul y quieres cerrar esto, la ruta anónima es lo que hay que cerrar:
RestrictAnonymousSAM / RestrictAnonymous).Nada de esto impide que un usuario con sesión iniciada lea los mismos datos — eso es normal y esperado. Solo cierra la ruta sin credenciales.
\samr, o llamadas de política/búsqueda contra \lsarpc, en poco tiempo.--sleep y --jitter pueden repartir las llamadas, alerta sobre el recuento total en una ventana en lugar de solo sobre la tasa.--lsa-fallback para probar LSA LsarLookupSids para el inventario (ver "Cuando SAMR está bloqueado"). Si las búsquedas de LSA también están bloqueadas, solo es posible el recon (nombre de dominio + SID).MIT. Ver LICENSE.