
Énumération anonyme d'Active Directory en une seule passe via SAMR et LSARPC — session nulle, sans identifiants, avec une sortie structurée réutilisable.
Un énumérateur Active Directory à passe unique pour une session anonyme (null), utilisant les named pipes \samr et \lsarpc. Aucun identifiant requis.
Il ne fait rien que les outils classiques ne peuvent pas faire. Ce qu'il fait, c'est tout rassembler en une seule exécution et présenter les résultats proprement. Lors d'un engagement, vous arrivez sans compte de domaine, vous trouvez le DC via DNS, et vous voulez la vue complète — comptes, détail par utilisateur, groupes, politique, et les éléments LSA/DNS — sans avoir à assembler des sessions rpcclient ou plusieurs scripts séparés puis à parser leur stdout à la main. Cet outil fait cette passe pour vous et écrit une sortie structurée et réutilisable :
manifest.json, des userlist.txt / computerlist.txt prêts à l'emploi, et une liste de RID sauvegardée que vous pouvez réutiliser au lieu de brute-forcer deux fois.Veuillez n'exécuter ceci que contre des systèmes que vous possédez ou que vous êtes explicitement autorisé à tester. Énumérer l'annuaire de quelqu'un d'autre sans autorisation n'est pas acceptable, et selon votre localisation, cela peut être illégal.
Il existe deux versions qui se comportent de manière identique. Utilisez celle dont vous disposez la bibliothèque :
adnullenum.py — basé sur impacket.$) sont séparés des vrais utilisateurs.Il signale aussi les comptes intéressants pour vous : des choses comme « mot de passe non requis », « le mot de passe n'expire jamais », AS-REP-roastable, délégation non contrainte, jamais connecté, ou une description qui mentionne un mot de passe.
Quelques éléments qui en découlent naturellement :
Tout ici est du SAMR/LSARPC anonyme standard, et les outils établis atteignent déjà les mêmes données. C'est un wrapper de commodité, pas une nouvelle capacité, donc il vaut la peine de connaître les alternatives :
--rid-brute, --users, --pass-pol) couvre la même énumération au sein d'un framework bien plus vaste.samrdump.py (utilisateurs/groupes/alias + détail par utilisateur) et lookupsid.py (RID cycling via LSA). Pas d'exécution unique, pas de repli SAMR→LSA, stdout uniquement.rpcclient expose les appels sous-jacents (queryuser, enumdomusers, querydominfo, lsaquery, lookupsids, …) mais de manière interactive et en stdout uniquement. Son enumdomusers liste les utilisateurs standard par nom, sans comptes machine ($), et le détail complet se fait via queryuser un par un. Sans boucle de RID cycling intégrée, il ne peut pas récupérer les ordinateurs ni contourner une énumération restreinte. Voir Le faire à la main.Ce qu'adnullenum ajoute, c'est l'emballage : une seule exécution en session nulle au lieu de plusieurs outils, SAMR en premier avec un repli LSA optionnel, des indicateurs de comptes intéressants sélectionnés, et une sortie multi-format soignée que vous pouvez transmettre directement à l'étape suivante ou rouvrir plus tard. Si ce flux de travail correspond à votre façon de travailler, utilisez-le ; si vous préférez un outil éprouvé, tournez-vous vers enum4linux-ng ou NetExec.
Vous avez besoin de Python 3.9+ et d'une bibliothèque SMB. Un environnement virtuel garde tout propre :
# 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
C'est tout. Lancez python3 adnullenum.py --help pour tout voir.
Tout passe par un seul --mode. La valeur par défaut est recon, ce qui est la chose sûre à exécuter en premier.
| Mode | Ce que vous obtenez |
|---|---|
recon | Infos de domaine, comptages, politique de mot de passe/verrouillage, et les détails LSA/DNS. Pas de brute-force. Juste un tour d'horizon. |
rids | Trouve quels comptes existent et les classe en utilisateurs / ordinateurs / groupes. |
users | Ce qui précède, plus le détail complet de chaque vrai utilisateur et le résumé des « comptes intéressants ». Ajoutez --include-groups pour lister aussi les groupes de chaque utilisateur. |
groups | Groupes de domaine et alias intégrés avec leurs membres. |
full | Tout. |
# 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 le domaine ne vous laisse pas lister les utilisateurs directement (courant), l'outil se rabat sur le RID cycling : il demande au DC de traduire les identifiants de compte en noms par lots de 1000. Par défaut, il balaie vers le haut jusqu'à avoir trouvé tout ce que le DC dit exister, ou jusqu'à ce que 5000 ID consécutifs reviennent vides. Vous pouvez le fixer à une plage exacte à la place :
python3 adnullenum.py 10.0.0.10 --mode rids --range 500-50000
Certains DC refusent entièrement le SAMR anonyme (enumdomains et la traduction de RID reviennent en ACCESS_DENIED). L'exécution n'abandonne pas :
\lsarpc, qui répond fréquemment quand SAMR ne le fait pas.--lsa-fallback, l'outil retente le même balayage via LSA LsarLookupSids en utilisant le SID de domaine, ce qui vous donne toujours l'inventaire des comptes (noms et types, ordinateurs inclus). Il est désactivé par défaut car c'est une seconde passe de brute-force ; sans le flag, l'exécution s'arrête à la reconnaissance et le signale.Trouver les comptes est la partie lente, donc l'outil sauvegarde la liste (rids.txt) dans le dossier de sortie de chaque exécution. Pointez une exécution ultérieure vers ce dossier avec --session et il saute le brute-force et réutilise ce que vous avez déjà trouvé :
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 prend le dossier d'une exécution précédente. (--rid-file fait la même chose à partir d'un fichier texte brut avec un RID par ligne.)
Chaque exécution dépose un dossier horodaté sous 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 et csv sont toujours écrits ; ajoutez --json pour un dossier json/ aussi.
Le dossier lists/ contient deux fichiers bruts conçus pour alimenter directement d'autres outils :
lists/userlist.txt — à déposer directement dans l'AS-REP roasting, le password spraying, ou une liste --users de cracker. En mode users/full, il contient uniquement les comptes activés ; en mode rids (pas de détail par utilisateur), c'est tous les utilisateurs.lists/computerlist.txt — les noms de comptes machine avec le $ conservé (le sAMAccountName), pour les vérifications de comptes machine pré-Windows 2000.Vous avez oublié de les regarder, ou vous n'avez exécuté que rids et voulez maintenant les listes ? Pointez vers le dossier de l'exécution et elles sont reconstruites à partir des CSV, sans réseau :
python3 adnullenum.py --lists-from output/20260917-1530_10.0.0.10_full
À l'écran, vous obtenez un aperçu plafonné pour qu'un grand domaine n'inonde pas votre terminal (--limit, 100 par section par défaut) — les fichiers contiennent toujours les données complètes. La couleur est activée quand vous êtes dans un terminal ; --no-color la désactive.
Une exécution full contre un DC de test (assaini). À l'écran, vous obtenez la reconnaissance, le balayage des RID, le résumé des comptes intéressants, et la liste des fichiers écrits :
$ 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 seul enregistrement de txt/users.txt (le groupe primaire et les groupes directs sont résolus en noms) :
[+] 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
Tout ici est du SAMR/LSARPC standard, donc vous pouvez extraire les mêmes faits appel par appel avec rpcclient de Samba. Connectez-vous d'abord anonymement :
rpcclient -U "" -N 10.0.0.10
| Cet outil | Équivalent rpcclient |
|---|---|
recon (infos de domaine + comptages) | querydominfo |
recon (politique de mot de passe) | getdompwinfo |
recon (domaine LSA + SID) | lsaquery, lsaenumsid |
rids (traduction nom/SID) | lookupnames <name>, lookupsids <SID> |
rids (liste côté serveur) | enumdomusers (utilisateurs standard uniquement — pas de comptes machine $) |
users (détail par utilisateur) | queryuser <rid> ou queryuser <name>, querydispinfo |
groups | enumdomgroups, querygroupmem <rid>, enumalsgroups builtin, queryaliasmem builtin <rid> |
enumdomusers renvoie les comptes utilisateur standard par nom uniquement ; les comptes machine ($) sont filtrés, et le détail complet implique d'exécuter queryuser un compte à la fois. rpcclient n'a pas de boucle de RID cycling intégrée, donc il ne peut pas récupérer les comptes machine (ni rien d'autre) quand l'énumération côté serveur est restreinte ; vous devriez scripter lookupsids sur une plage vous-même. Il n'a pas non plus de commande de politique de verrouillage et ne renvoie pas les DNS/forêt/GUID LSA ni les approbations, c'est pourquoi cet outil interroge directement PolicyDnsDomainInformation.
Pour les équivalents scriptés et la relation de cet outil avec eux, voir Comment il se compare.
Si vous êtes du côté bleu et voulez fermer cela, le chemin anonyme est la chose à fermer :
RestrictAnonymousSAM / RestrictAnonymous).Rien de tout cela n'empêche un utilisateur connecté de lire les mêmes données — c'est normal et attendu. Cela ne ferme que le chemin sans identifiants.
\samr, ou des appels de politique/lookup contre \lsarpc, en peu de temps.--sleep et --jitter peuvent étaler les appels, alertez sur le nombre total sur une fenêtre plutôt que sur le taux seul.--lsa-fallback pour essayer LSA LsarLookupSids pour l'inventaire (voir « Quand SAMR est verrouillé »). Si les lookups LSA sont aussi bloqués, seule la reconnaissance (nom de domaine + SID) est possible.MIT. Voir LICENSE.