adalanche v2024.1.11 releases: Active Directory ACL Visualizer
adalanche – Active Directory ACL Visualizer and Explorer
Active Directory security is notoriously difficult. Small organizations generally have no idea what they’re doing, and way too many people are just added to Domain Admins. In large organizations you have a huge number of people with different needs, and they are delegated access to varying degrees of power in the AD. At some point in time, someone makes a mistake, and that can cost you dearly.
User Interface
When launched, you get to see who can pwn “Domain Admins” and “Enterprise Admins”. Query targets are marked with RED. If you get a lot of objects on this one, congrats, you’re running a pwnshop.
The below examples loaded from the included domain beyond.local, which is a synthetic domain, that has been heavy-handedly been messed up using BadBlood. You can try the same analysis with: adalanche -domain beyond.local analyze
Your browser should pop up with:
No really exciting results on this synthetic AD. Yes, some users are Domain Admins and Administrators. But let’s expand the search a bit.
Analysis Methods
Press the “Analysis Methods” tab on the bottom portion of the page, and you get this:
(more methods has been added since this screenshot)
The tool can look for many scenarios but defaults to fairly simple ones that can get you control of an object. As this yielded nothing, let’s try to expand with all methods enabled. Checking the missing boxes, we submit another query.
LDAP query pop-out
When you press the “LDAP Query” tab on the bottom portion of the page, and you get the search interface:
You enter a query for things you want to search for. Optionally you can also add a secondary exclude query, separating the include and exclude queries with a comma.
- The “Queries” button is just for inspiration, with some predefined queries to get you going.
- The “Safe”/”Force” button allows you to run requests that return more than 1000 objects (potentially crashing your browser tab).
- “Max Depth” can limit results by not going further from a target than this depth.
Analyze:
- Normal searches for other objects that can pwn the selection in your LDAP query (i.e. who can reach these objects)
- Reverse searches for objects that you LDAP query targets can pwn (i.e. what can these objects reach)
I enabled “Force” as I was warned that the analysis would return more than 1000 objects, and pressed “Analyze / Normal”.
Whoa – that’s a lot. But can all these objects then suddenly do a system takeover? No, not necessarily, this depends on the analysis methods used. We enabled the CanDelete*, CanCreate*, and InheritsSecurity methods.
Let’s investigate what’s going on here – right-click on one of your targets, and choose “Set as target”.
Then right-click on someone else, and choose “Route to target”.
Then you’ll get a route, which shows the best way to the target.
So here the problem is just a matter of groups being nested members of other groups, but at the very end, you see that someone set the DELETE_CHILD flag on the parent container, yielding the right to delete (or potentially move) the target. That does look wrong, doesn’t it?
If you examine the “Domain Users” object, you will see that it doesn’t have the InheritsSecurity flag, so you can’t really pwn it by moving it around.
So try it out on your own data – see what your user can pwn by searching for (&(objectCategory=Person)(Name=YOURLOGIN)) and do a Reverse search. Maybe you’ll just end up with the groups that you are a member of, maybe you have access to more than you think …
Remember, you might get too many results. Limit the selection of targets with (&(attribute=something)(_limit=10)) to just get 10 random targets (see LDAP queries below)
Operational theory
adalanche works a bit differently than other tools, as it dumps everything it can from an Active Directory server, which it then saves to a highly compressed binary cache file for later use. This dump can be done by any unprivileged user unless the Active Directory has been hardened to prevent this (almost no one does this).
The analysis phase is done on a cache file, so you do not have to be connected to the systems when doing analysis. This way you can explore different scenarios, and ask questions not easily answered otherwise.
Analysis / Visualization
The tool works as an interactive map in your browser and defaults to a ldap search query that shows you how to become “Domain Admin” or “Enterprise Admin” (i.e. member of said group or takeover of an account which is either a direct or indirect member of these groups.
LDAP queries
The tool has its own LDAP query parser and makes it easy to search for other objects to take over, by using a familiar search language.
The queries support:
- case insensitive matching for all attribute names
- checking whether an attribute exists using asterisk syntax (member=*)
- case insensitive matching for string values using equality (=)
- integer comparison using <, <=, > and >= operators
- glob search using equality if search value includes ? or *
- case sensitive regexp search using equality if search value is enclosed in forward slashes: (name=/^Sir.*Mix.*lot$/ (can be made case insensitive with /(?i)pattern/ flags, see https://github.com/google/re2/wiki/Syntax)
- extensible match: 1.2.840.113556.1.4.803 (you can also use :and:) LDAP_MATCHING_RULE_BIT_AND
- extensible match: 1.2.840.113556.1.4.804 (you can also use :or:) LDAP_MATCHING_RULE_BIT_OR
- extensible match: 1.2.840.113556.1.4.1941 (you can also use :dnchain:) LDAP_MATCHING_RULE_IN_CHAIN
- custom extensible match: count – returns the number of attribute values (member:count:>20 gives groups with more members than 20)
- custom extensible match: length – matches on length of attribute values (name:length:>20 gives you objects with long names)
- custom extensible match: since – parses the attribute as a timestamp and your value as a duration – pwdLastSet:since:<-6Y5M4D3h2m1s (pawLastSet is less than the time 6 years, 5 months, 4 days, 3 hours, 2 minutes, and 1 second ago – or just pass an integer that represents seconds directly)
- synthetic attribute: _limit (_limit=10) returns true on the first 10 hits, false on the rest giving you a max output of 10 items
- synthetic attribute: _random100 (_random100<10) allows you to return a random percentage of results (&(objectclass=Person)(_random100<1)) gives you 1% of users
- synthetic attribute: _canpwn – allows you to select objects based on what they can pwn directly (&(objectclass=Group)(_canpwn=ResetPassword)) gives you all groups that are assigned the reset password right
- synthetic attribute: _pwnable – allows you to select objects based on how they can be pwned directly (&(objectclass=Person)(_pwnable=ResetPassword)) gives you all users that can have their password reset
Changelog v2024.1.11
- 1dc2108: Scrollbar bug for options panel (Lars Karlslund)
- 9974f5e: JS windows initialization change (Lars Karlslund)
- bb4fadb: Cleaned up constants in security descriptor module (Lars Karlslund)
- b7b64d4: Added sort and limit primitives to object slices (Lars Karlslund)
- 2251281: GUID for pwdLastSet attribute (Lars Karlslund)
- 4cecaa4: Fixed reference to now removed constant (Lars Karlslund)
- b167243: Go.mod reference missing somehow (Lars Karlslund)
- 6171951: Added COSE Bilkent layout engine option (Lars Karlslund)
- 02c07d7: Bump Gin version (Lars Karlslund)
- 1af7c1e: PKI Attribute decoding experiment (Lars Karlslund)
- cf21a2a: Various module upgrades (Lars Karlslund)
- db3af8e: Added UUID datatypes to flexinit (Lars Karlslund)
- 17451f8: Moved ParentDN to util, also create synthetic missing parents (Lars Karlslund)
- 78768a6: More info on passwords exposed via GPO cPassword entries (Lars Karlslund)
- 1014d17: Fixed schema parsing with superiors (Lars Karlslund)
- 5c785ed: Fix SID collision as it has no real world chance of doing anything (Lars Karlslund)
- ae77571: Fixed some name parsing where we’re missing the netbios domain part of it (Lars Karlslund)
- 570cef5: Update cytoscape.js to latest version (Lars Karlslund)
- 5e1d140: Merging over SIDs was way too generic, but maybe now it’s just too strict (Lars Karlslund)
- 18b8a9d: Fix for looking up a non existing attribute (Lars Karlslund)
- b158b9c: Switched to Bootstrap compatible UI (Halfmoon UI 2.x), upgraded jquery, jquery UI, cytoscape etc. UI improvements (and possible breakage) (Lars Karlslund)
- f806aa3: Clarify a couple of attributes (Lars Karlslund)
- e24e111: Missed some UI files (Lars Karlslund)
- 79bf7b8: Added comment about reasoning to refresh merge attribute list while merging (Lars Karlslund)
- f671596: Replaced all ‘interface{}’ usage with ‘any’ (Lars Karlslund)
- 65c6fcf: Improved on FindOrAddAdjacentSID, and use that while parsing groups that are pointing to missing DNs (Lars Karlslund)
- 07ea98c: Bump Gonk version (Lars Karlslund)
- de79909: Split include and exclude queries up in seperate input fields, and also add an option to exclude last objects by query (Lars Karlslund)
- 827571b: Go mod tidy circus (Lars Karlslund)
- 6d7b57d: Refactored the analysis function, moved graphs to own package, minor fixes, analysis performance optimization, node limiter, start/middle/end queries rather than the convoluted mess that was before (Lars Karlslund)
- 9057df0: The usual go mod tidy problem, arrrrrgh (Lars Karlslund)
- 1b81a94: Default maxdepth to -1 not 99 (Lars Karlslund)
- 12d1a63: Added minimum accumulated probability filter, fixed toasts (Lars Karlslund)
- 68846c0: Tooltips, don’t expand AU / EO option, iterator for Graph edges, backlinks fuzz implemented but not enabled in WebUI (causes chaos), graph edge can have data attached (Lars Karlslund)
- 40ba8f0: Generalized Protected Users lookup, changed the members of Authenticated Users logic (Lars Karlslund)
- e8cd715: Removed dark mode class on body (Lars Karlslund)
- 8f9f1be: Got rid of the ForeignSecurityPrincipal type entirely (Lars Karlslund)
- aeb557e: Changed tag “escalation” to “pivot” for edges internally (Lars Karlslund)
- 20f7e73: Tooltip for query input boxes (Lars Karlslund)
- 0a503ff: Added “extract words” feature for creating wordlist to use with hashcat rules (Lars Karlslund)
- 92c2f16: Time decoding for BadPasswordTime (Lars Karlslund)
- 391a863: Fixed accountexpires decoding, whoops (Lars Karlslund)
- 7fddd34: Added split to export words, added mastodon links (Lars Karlslund)
- 25921ed: Upgrade builds to Go 1.21 (Lars Karlslund)
- de7730b: Attribute objectCategorySimple -> type, parsing of securitydescriptors moved to rawobject, added securitydescriptor parsing to 5 other attributes, ACLs can now print without resolving SIDs, added RBCD edge, renamed some of the meta attributes, added predefined search for Unconstrained delegation computers and Constrained delegation (Lars Karlslund)
- 40f0f04: Rename log level function (Lars Karlslund)
- 53ea2e3: Various attributes and edges refactoring (Lars Karlslund)
- b8f39b4: Missed a few calls in the refactoring (Lars Karlslund)
- 08d311c: Loglevel stuff (Lars Karlslund)
- e736344: Constrained delegation edge (Lars Karlslund)
- 0b8d1c4: Fixed horrible 0 edge bug I introduced yesterday (Lars Karlslund)
- 2e09a32: Added some webservice debug functions (Lars Karlslund)
- 97160a6: Predefined filters update (Lars Karlslund)
- 06f46b4: Proper link to the UI in the console output (Lars Karlslund)
- baa607a: Disable browser spell check in query textareas (Lars Karlslund)
- 7de1a25: Effort to fix periodic window sizing glitch (Lars Karlslund)
- d29473d: Windows collector default to current working directory rather than failing (Lars Karlslund)
- f635426: Fix for constrained delegation edge (Lars Karlslund)
- 2f0f37a: Default to unencrypted LDAP, added port autodetection based on tlsmode (Lars Karlslund)
- b60c21f: Reflected Golang requirement is now 1.21 in readme (Lars Karlslund)
- b6098dd: New teaser graph in readme (Lars Karlslund)
- d2629c0: Switch development builds tag (Lars Karlslund)
- 752e2de: Revamped the readme (Lars Karlslund)
- f81bcbc: Updated year in copyright notice (Lars Karlslund)
- 6ea7c30: Added calculation of service SIDs (Lars Karlslund)
- 06416d5: Added SeMachineAccountPrivilege to localmachine ingestor, but no edges yet (Lars Karlslund)
- 207c0b2: Added InheritsSecurity edge to all objects and PublishedBy attributes to Cert Templates (Lars Karlslund)
- b899ddb: Fixed logic error in round 1 analysis which caused results to be unpredictable (Lars Karlslund)
- 65d3dd7: New JS code to handle window behaviour (Lars Karlslund)
- dfbc9e3: And is not or (Lars Karlslund)
- 92bb66d: Window click-to-front working again (Lars Karlslund)
- d73cd47: Various package updates (Lars Karlslund)