GriffonAD
A new tool to exploit bad configurations in Active Directory (based on Bloodhound json files).
Nothing is executed on the target, it generates commands for you and you just have to copy-paste these commands (with a few modifications). The main goal is to let the user a full control on what is modified: all commands are fully commented and parameters to change are highlighted in red.
Griffon supports many scenarios, take a look into config.ml !
Challenge
You can play with Griffon by installing a vulnerable AD: lab.
Installation
A pull request has been sent to impacket for dacledit but it's still in review. This script allows you to edit ACL with more granularities.
pip install -r requirements.txt cp tools/dacledit.py path_to_impacket/examples/
4 steps to Domain Admin
Step 1
Retrieve Bloodhound json files:
./bloodhound.py -u USER -d DOMAIN -p PASSWORD -ns DNS_IP -c DCOnly
Step 2: ACLs analysis
Only interesting users are kept. If you have underlined yellowed users, that sounds good!
./griffon.py *.json
Other options:
--select FILTER : display only targets where the name starts with FILTER
: display only targets where the name starts with FILTER --groups : display all groups with their rights (+ --members )
: display all groups with their rights (+ ) --ous : display all ous with their gpo links (+ --members )
: display all ous with their gpo links (+ ) --graph : open a js graph to view relations between objects
: open a js graph to view relations between objects --sysvol PATH : search for local members (Backup Operators and Administrators) and local privileges
Note Example on how Griffon displays the information with --sysvol : If there is a GPO applied on the OU MY_OU where Alice is defined as a member of Administrators (Policies / Windows Settings / Restricted Groups) and Alice has the privilege SeDebug, then new rights will be available: Alice (RestrictedGroups, [Administrators] -> [email protected]) (AdminTo, [email protected]) (SeDebugPrivilege, [email protected]) To retrieve SYSVOL, you can use this command: echo -e "recurse
prompt
mget *" | smbclient -U 'DOMAIN/USER%PASSWORD' '\\IP\SYSVOL'
Tip About the many target: it means that you can have multiple targets. It depends of the right you have: GenericAll : on all users and groups with admincount=0 if the user is in the Account Operators group
: on all users and groups with admincount=0 if the user is in the Account Operators group AddKeyCredentialLink : on all users with admincount=0 if the user is in the Key Admins group
: on all users with admincount=0 if the user is in the Key Admins group AllowedToDelegate : means an unconstrained delegation
: means an unconstrained delegation SeBackupPrivilege : can access to DC/C$ ( FIXME theorically also on all computers, does it requires RDP?)
Note Supported ACEs here: supported
Step 3: Search paths
From owned users, it reads the text file owned .
Tip Line format is: SAMACCOUNTNAME:TYPE:SECRET SAMACCOUNTNAME : insensitive case, a computer ends with a $
: insensitive case, a computer ends with a TYPE = password | aes | nt A password for a computer MUST BE set in hex. The separator can be changed with the option --sep (you can put a string with more than one character).
# Warning: if you put multiple secrets for one user, only the last one will be kept! cat owned WORKSTATION$:password:0d3c811f9c817a0cf3... Tracy:aes:1D5A2C4E52584F0A699D0853D2EBF8EBDB6713183D9A303AB8AAACB87818BDEE Tracy:aes:6AD07E6F0F25DE8906D444EEC50BD83C Tracy:nt:4869b177d39962457ff9fb185b35c5ba Tracy:password:Spring2025 ./griffon.py lab/json/* --fromo
Other options:
--fromv : from vulnerable users (NP users (only for unprotected users), blank passwords, and kerberoastable users)
: from vulnerable users (NP users (only for unprotected users), blank passwords, and kerberoastable users) --from USER : test paths from an arbitrary user
: test paths from an arbitrary user --rights : view ACE names instead of actions
: view ACE names instead of actions --onlyadmin : display only paths to domain admin (paths prefixed by the
: display only paths to domain admin (paths prefixed by the --no-follow : don't try to continue on new owned targets but display all available scenarios for the current target. For example: with a GenericAll on a user, you can reset the password, add a shadow key credential... If this option is unset, it will take the first scenario (in config.ml it's ForceChangePassword). With this option, you will see all scenarios but without continuing the path on the new owned target.
Step 4: Generate the script
./griffon.py lab/json/* --fromo -s0 --dc-ip 10.0.0.2
Embedded tools
./tools/attr.py : generic script to modify one ldap attribute
: generic script to modify one ldap attribute ./tools/addspn.py : modify the attribute servicePrincipalName
: modify the attribute servicePrincipalName ./tools/logonscript.py : modify the attribute msTSInitialProgram
: modify the attribute msTSInitialProgram ./tools/addmember.py : modify the attribute member
: modify the attribute member ./tools/toggleNP.py : enable or disable the donotpreauth flag
: enable or disable the donotpreauth flag ./tools/getbyname.py : get all attributes of one object
: get all attributes of one object ./tools/readpol.py : export Registry.pol to json and rewrite the pol file
: export Registry.pol to json and rewrite the pol file ./tools/xmltask.py : generate an xml for schedule task (mimic a real xml)
: generate an xml for schedule task (mimic a real xml) ./tools/scriptsini.py : re-format a scripts.ini with correct encoding
: re-format a scripts.ini with correct encoding ./tools/gpttmpl.py : re-format a GptTmpl.inf with correct encoding
: re-format a GptTmpl.inf with correct encoding ./tools/readgmsa.py (from gMSADumper.py): simplified and login parameters uniformization
(from gMSADumper.py): simplified and login parameters uniformization ./tools/aesKrbKeyGen.py : login parameters uniformization
: login parameters uniformization ./tools/dacledit.py : -mask + bugfix (pull request to impacket in review)
Customization
The file config.ml is fully customizable, you can set your preferences based on scenario priorities (more at config.md). You can also define conditional predicates by adding flags with the parameter --opt . For example, a flag was already defined in config.ml if you don't wan't to use the ForceChangePassword. It will then fallback on the default next scenario which is AddKeyCredentialLink.
./griffon.py lab/json/* --from MALORY --opt noforce
Available options:
--opt noforce : no ForceChangePassword
: no ForceChangePassword --opt noaddcomputer : don't use the scenario 'add a computer' with RBCD
: don't use the scenario 'add a computer' with RBCD --opt allgpo : iterates on all gpo scenarios, by default it will use only the GPOAddLocalAdmin
: iterates on all gpo scenarios, by default it will use only the GPOAddLocalAdmin --opt nofull : if we have WriteDacl, give only specific right to continue (not FullControl)
: if we have WriteDacl, give only specific right to continue (not FullControl) --opt allkeys : for the Key Admins group (+Enterprise), iterate on all users and computers
You can also write options in config.py .
Tests
badblood: 10000 users, 3000 computers, 100 groups Json parsing + analysis = 2 seconds (4 cores, 8 threads, 1.6GHz) Memory consumption peak = 150 MiB the js graph is very slow when permissions are too random
tested only with bloodhound-python
Credits
Impacket (the kerberos login function inside ./tools/ldap_auth.py is a copy)
https://github.com/Tw1sm/aesKrbKeyGen
https://github.com/micahvandeusen/gMSADumper
Bloodhound for the opsec comments
Disclaimer