diff --git a/readme-images/analysis-methods.png b/readme-images/analysis-methods.png index 0130ac6..1678cbc 100644 Binary files a/readme-images/analysis-methods.png and b/readme-images/analysis-methods.png differ diff --git a/readme-images/analysis-options.png b/readme-images/analysis-options.png new file mode 100644 index 0000000..94a58f9 Binary files /dev/null and b/readme-images/analysis-options.png differ diff --git a/readme-images/found-route.png b/readme-images/found-route.png index e0fcb55..ac22f93 100644 Binary files a/readme-images/found-route.png and b/readme-images/found-route.png differ diff --git a/readme-images/ldap-query.png b/readme-images/ldap-query.png index 90133d3..7c9f945 100644 Binary files a/readme-images/ldap-query.png and b/readme-images/ldap-query.png differ diff --git a/readme-images/object-types.png b/readme-images/object-types.png new file mode 100644 index 0000000..2b118ac Binary files /dev/null and b/readme-images/object-types.png differ diff --git a/readme-images/query-with-all-methods.png b/readme-images/query-with-all-methods.png deleted file mode 100644 index 3446696..0000000 Binary files a/readme-images/query-with-all-methods.png and /dev/null differ diff --git a/readme-images/route-to-target.png b/readme-images/route-to-target.png index b3ea302..0781a14 100644 Binary files a/readme-images/route-to-target.png and b/readme-images/route-to-target.png differ diff --git a/readme-images/set-as-target.png b/readme-images/set-as-target.png index f492949..a940ea2 100644 Binary files a/readme-images/set-as-target.png and b/readme-images/set-as-target.png differ diff --git a/readme-images/welcome.png b/readme-images/welcome.png index 3cc754c..6e9cb54 100644 Binary files a/readme-images/welcome.png and b/readme-images/welcome.png differ diff --git a/readme.MD b/readme.MD index 288802f..1657a0f 100644 --- a/readme.MD +++ b/readme.MD @@ -55,28 +55,43 @@ From domain joined Windows machine using other credentials than logged in: There are more options available, for instance on what LDAP contexts to collect, whether to collect GPOs or not etc. Please be aware that you can collect GPOs from Linux by mounting sysvol locally and pointing adalanche to this path for GPO collection - but you will lose ACL analysis for the individual files. -## BIG FAT NTLM BUG WARNING +### LDAP RESULT CODE 49 -*There is an unfixed bug that in some cases prevents NTLM authentication from working. AD controller responds with "DAP Result Code 49 "Invalid Credentials": 8009030C: LdapErr: DSID-0C0906B5, comment: AcceptSecurityContext error, data 52e, v4563".* +*There is a limitation in the LDAP library that adalanche uses, which can result in this error: "LDAP Result Code 49 "Invalid Credentials": 8009030C: LdapErr: DSID-0C0906B5, comment: AcceptSecurityContext error, data 52e, v4563".* -Until this is fixed, you can try this alternative method: +This is usually "Channel Binding" or "Signing" requirements for SSL enabled connections over LDAP, as part of Microsofts hardening efforts on making LDAP more secure. -- spin up a Windows VM -- set the computer name to the domain name -- add your domain user account to the local machine and set the password accordingly so it matches the domain -- proceed to dump things using integrated NTLM authentication (the default when running adalanche on Windows) +Here are suggested alternative solutions: -This has worked for me, even over trusts. If you have any idea what's going on with the bug, please reach out to me. +#### Dump data over plaintext LDAP -### Local Machine (Windows) +Use this command: + +adalanche collect activedirectory --port 389 --tlsmode NoTLS + +#### Dump data using SysInternals AD Explorer + +The SysInternals AD Explorer (adexplorer64.exe) is an enhanced GUI application that allows you to poke around in all objects and see all attributes. It leverages the Windows LDAP library (just like Users & Computers etc.) This supports both "Channel Binding" and "Signing" for LDAP transport. It also has a handy "snapshot" feature, that allows you do dump the entire AD into a proprietary file, which adalanche can ingest as an alternative to talking directly to LDAP. + +The procedure for using AD Explorer as a data source is: + +- Launch 'adexplorer64.exe' +- Connect to your domain, for simple setups you can just leave all fields blank and press connect +- Choose File | Create snapshot ... and save the file somewhere. There is no progress indicator, so just have patience +- Run adalanche to collect Active Directory object and GPO data: +adalanche collect activedirectory --adexplorerfile=yoursavedfile.bin + +You will then have compressed AD data and GPO data in your datapath like a normal collection run. You can delete the AD Explorer data file now, as this is converted into adalanche native format. + +## Gathering Local Machine data (Windows) For Windows systems that are members of your Active Directory domain (or standalone) you can collect more information from the local machines by running the collector module. There is a stand alone version released as a 32-bit Windows executable, and this works transparently also on 64-bit systems. The idea is that you orchestrate it centraliy with a Scheduled Task via a GPO or whatever means you see fit (psexec, login script etc). The collector does not require elevated privileges, and runs fine with either the local system account with pricileges stripped or as a random user. -adalanche-collector --outputpath \\some\share\where\youcanwrite\butnotread +adalanche-collector --outputpath \\\\some\\share\\where\\youcanwrite\\butnotread -You can run the local machine collector from the adalance binary too, but this is only included in the 64-bit Windows build: +You can run the local machine collector from the adalanche binary too, but this is only included in the 64-bit Windows build: adalanche collect localmachine [--options ...] @@ -103,55 +118,71 @@ Highly advanced command line to analyze and launch your browser: adalanche analyze -There are options here as well - try adalanche analyze --help +There are some options here as well - try adalanche analyze --help ### 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, congratz, you're running a pwnshop. + -*PLEASE NOTE THAT:* +When launched, you'll see some statistics on what's loaded into memory and how many edges are detected between objects. Don't worry, adalanche can handle millions of objects and edges, if you have enough RAM ;) -- SCREENSHOTS ARE OUTDATED AT THE MOMENT -- SOME UI ELEMENTS HAVE MOVED -- THERE ARE MORE ADVANCED ANALYSIS FEATURES NOT YET DESCRIBED HERE +The pre-loaded query allows you to see who can pwn "Administrators", "Domain Admins" and "Enterprise Admins". Query targets are marked with RED. +Press the "analyze" button in the query interface to get the results displayed. If you get a lot of objects on this one, congratz, you're running a pwnshop. - +Depending on whether you're over or underwhelmed by the resutls, you can do adjustments or other searches. + +#### Pre-defined searches + +To ease the learning experience, there are a number of sample quieries built into 'adalanche'. You access these by pressing the "Sample queries" button, and choosing one. This should give you some idea of how to do queries. + +#### Analysis Options + + + +Mode allows you to switch between: +- In normal mode you select targets, and adalanche figures out who can reach these targets (most common search) +- In reverse mode you select targets, and adalanche figures out what impact they have (What can "Domain Users" do?) +- The SrcTgt mode consists of TWO queries separated by commas, and it allows you to do a path search from the source(s) to the target(s). You target selection should be limited to no more than 5 of each, as the query results in S*T searches to be run in the engine. +If your query returns more than 1000 objects, adalanche will reject the query, because it has the potential to crash your browser. Using the "Force too much data" allows you to override this, and depending on your browser and computer, you might get away with more data. On my setup using Firefox, 2500 objects is unproblematic, but much more is possible but requires a lot of patience for the graph lauout to run. + +Remember, you might get too many results. Limit the selection of targets with (&(attribute=something)(_limit=10)) to just get the first 10 targets (see LDAP queries below) + +Prune island nodes removes unconnecteded objects in the results. + +Backlinks also shows edges to "higher ranking" results in your search, and has the potential to show you other interesting edges otherwise hidden. It does tend to result in a ball of yarn in the graph, but is useful in some cases. + +Analysis depth allows you do limit how many edges from the target selection is returned. Setting this to 0 will only result in the query targets (don't prune islands here, otherwise you'll get nothing), setting it to 1 results on only neighbouring edges to be returned. Quite useful if you get too much data back. + +Max outgoing limits how many outgoing edges are allowed from an object, and can help limit results for groups and objects that have many assignments. #### Analysis Methods -Press the "Analysis Methods" tab on the bottom portion of the page, and you get this: +Press the "Analysis Methods" tab to allow you to do edge based filtering. -(more methods has been added since this screenshot) +FML is not the usual abbreviation, but represents First, Middle and Last. Disabling the "Middle" selector, will also prevent "Last" in the results, unless it's picked up as the "First" due to the way the search is done. + +#### Analysis Objects + + -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. +This works the same way as the "Analysis Methods" limiter above. #### 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, seperating the include and expclude quereries with a comma. Things matching in the exclude query will never get added to the results. +You enter a query for things you want to search for. Optionally you can also add a secondary exclude query, seperating the include and expclude quereries with a comma. Things matching in the exclude query will *never* get added to the results. -The "Queries" button offers some predefined queries to get you going. +Sample search: -Analyze button gets the show on the road, and runs the query. +(objectClass=person),(name=*group*) -#### Options - -- "Force" button allows you to run requests that returns more than 1000 objects (potentially crashing your browser tab, I don't recommend more than 2500 objects but you can try your luck - be patient). -- "Max Depth" can limit results by not going further from a target than this depth. -- - -- 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) - -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) +Selects all objects with objectClass attribute set to person as targets, but will never add any objects where the name attribute matches the glob pattern *group* to the connected result objects. As you can match on edges too, this can become both complicated and powerful :-) ### Operational theory @@ -184,66 +215,85 @@ The tool has its own LDAP query parser, and makes it easy to search for other ob - synthetic attribute: _random100 (_random100<10) allows you to return a random percentage of results (&(objectCategory=Person)(_random100<1)) gives you 1% of users - synthetic attribute: _canpwn - allows you to select objects based on what they can pwn *directly* (&(objectCategory=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* (&(objectCategory=Person)(_pwnable=ResetPassword)) gives you all users that can have their password reset +- glob matching on the attribute name - searching for (*name=something) is possible - also just * to search all attributes +- custom extensible match: timediff - allows you to search for accounts not in use or password changes relative to other attributes - e.g. lastLogonTimestamp:timediff(pwdLastSet):>6M finds all objects where the lastLogonTimestamp is 6 months or more recent than pwdLastSet +- custom extensible match: caseExactMatch - switches text searches (exact, glob) to case sensitive mode ## Detectors and what they mean | Detector | Explanation | | -------- | ----------- | -| CreateUser | Permission in ACL allows entity to create user objects in the container | -| CreateGroup | Permission in ACL allows entity to create group objects in the container | -| CreateComputer | Permission in ACL allows entity to create computer objects in the container | -| CreateAnyObject | Permission in ACL allows entity to create any kind of objects in the container | -| DeleteChildrenTarget | Permission in ACL allows entity to delete all children via the DELETE_CHILD permission on the parent | -| DeleteObject | Permission in ACL allows entity to delete any kind objects in the container | -| InheritsSecurity | This flag simply indicates that the object inherits its security ACL from the parent. If it is moved, the permissins will change to what its new parent dictates | | ACLContainsDeny | This flag simply indicates that the ACL contains a deny entry, possibly making other detections false positives. You can check effective permissions directly on the AD with the Security tab | -| ResetPassword | The ACL allows entity to forcibly reset the user account password without knowing the current password. This is noisy, and will alert at least the user, who then no longer can log in. | -| Owns | The entity owns the object, and can do anything it wishes to it | -| GenericAll | The entity has GenericAll permissions on the object, which means more or less the same as "Owns" | -| WriteAll | The entity is allowed all write operations | -| WritePropertyAll | The entity can write to any property (same as above, ACL is just a bit different) | -| WriteExtendedAll | The entity is allowed to do all extended write operations | -| TakeOwnership | The entity can make itself the owner | -| WriteDACL | The entity can write to the DACL, effectively giving it all permissions after granting them | -| WriteSPN | The entity can freely write to the Service-Principal-Name attributes using SETSPN.EXE or similar tools. You can then kerberoast the account | -| WriteValidatedSPN | The entity can do validated writes to the Service-Principal-Name attributes using SETSPN.EXE or similar tools. You can then kerberoast the account | -| WriteAllowedToAct | The entity is allowed to write to the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute of the object, so we can get it to accept impersonations what would otherwise not work | | AddMember | The entity can change members to the group via the Member attribute | | AddMemberGroupAttr | The entity can change members to the group via the Member attribute (the set also contains the Is-Member-of-DL attribute, but you can't write to that) | | AddSelfMember| The entity can add or remove itself to the list of members | -| ReadMSAPassword | The entity is allowed to read the plaintext password in the object | -| HasMSA | | -| WriteKeyCredentialLink | The entity can write to the msDK-KeyCredentialLink attribute | -| WriteAttributeSecurityGUID | The entity can write to the AttributeSecurityGUID. I'm not sure if this will work, but it has the potential to allows you to add an important attribute to a less important attribute set | -| SIDHistoryEquality | The objects SID-History attribute points to this entity, making them equal from a permission point of view | +| AdminSDHolderOverwriteACL | The entity will get it's ACL overwritten by the one on the AdminADHolder object periodically | | AllExtendedRights | The entity has all extended rights on the object | +| CertificateEnroll | The entity is allowed to enroll into this certificate template. That does not mean it's published on a CA server where you're alloed to do enrollment though | +| ComputerAffectedByGPO | The computer object is potentially affected by this GPO. If filtering is in use there will be false positives | +| CreateAnyObject | Permission in ACL allows entity to create any kind of objects in the container | +| CreateComputer | Permission in ACL allows entity to create computer objects in the container | +| CreateGroup | Permission in ACL allows entity to create group objects in the container | +| CreateUser | Permission in ACL allows entity to create user objects in the container | | DCReplicationGetChanges | You can sync non-confidential data from the DCs | | DCReplicationSyncronize | You can trigger a sync between DCs | -| DSReplicationGetChangesAll | You can sync confidential data from the DCs (hashes!). Requires DCReplicationGetChanges! | | DCsync | If both Changes and ChangesAll is set, you can DCsync - so this flag is an AND or the two others | -| ReadLAPSPassword | The entity is allowed to read the plaintext LAPS password in the mS-MCS-AdmPwd attribute | -| MemberOfGroup | The entity is a member of this group | -| HasSPN | The entity has a SPN, and can be kerberoasted by any authenticated user | -| HasSPNNoPreauth | The entity has a SPN, and can be kerberoasted by an unauthenticated user | -| AdminSDHolderOverwriteACL | The entity will get it's ACL overwritten by the one on the AdminADHolder object periodically | -| ComputerAffectedByGPO | The computer object is potentially affected by this GPO. If filtering is in use there will be false positives | +| DeleteChildrenTarget | Permission in ACL allows entity to delete all children via the DELETE_CHILD permission on the parent | +| DeleteObject | Permission in ACL allows entity to delete any kind objects in the container | +| DSReplicationGetChangesAll | You can sync confidential data from the DCs (hashes!). Requires DCReplicationGetChanges! | +| GenericAll | The entity has GenericAll permissions on the object, which means more or less the same as "Owns" | | GPOMachineConfigPartOfGPO | Experimental | | GPOUserConfigPartOfGPO | Experimental | +| HasAutoAdminLogonCredentials | The object is set to auto login using the entitys credentials which is stored in plain text in the registry for any user to read | +| HasMSA | | +| HasServiceAccountCredentials | The object uses the entitys credentials for a locally installed service, and can be extracted if you pwn the machine | +| HasSPN | The entity has a SPN, and can be kerberoasted by any authenticated user | +| HasSPNNoPreauth | The entity has a SPN, and can be kerberoasted by an unauthenticated user | +| InheritsSecurity | This flag simply indicates that the object inherits its security ACL from the parent. If it is moved, the permissins will change to what its new parent dictates | | LocalAdminRights | The entity has local administrative rights on the object. This is detected via GPOs or the collector module | -| LocalRDPRights | The entity has the right to RDP to the object. This is detected via GPOs or the collector module. It doesn't mean you pwn the machine, but you can get a session and try to do PrivEsc | | LocalDCOMRights | The entity has the right to use DCOM against the object. This is detected via GPOs or the collector module | -| LocalSMSAdmins | The entity has the right to use SCCM Configuration Manager against the object. This is detected via the collector module. It does not mean that everyone are SCCM admins, but some are | +| LocalRDPRights | The entity has the right to RDP to the object. This is detected via GPOs or the collector module. It doesn't mean you pwn the machine, but you can get a session and try to do PrivEsc | | LocalSessionLastDay | The entity was seen having a session at least once within the last day | -| LocalSessionLastWeek | The entity was seen having a session at least once within the last week | | LocalSessionLastMonth | The entity was seen having a session at least once within the last month | -| HasServiceAccountCredentials | The object uses the entitys credentials for a locally installed service, and can be extracted if you pwn the machine | -| HasAutoAdminLogonCredentials | The object is set to auto login using the entitys credentials which is stored in plain text in the registry for any user to read | -| ScheduledTaskOnUNCPath | The object contains a scheduled task that sits on a UNC path. If you can control the UNC path you can control what gets executed | +| LocalSessionLastWeek | The entity was seen having a session at least once within the last week | +| LocalSMSAdmins | The entity has the right to use SCCM Configuration Manager against the object. This is detected via the collector module. It does not mean that everyone are SCCM admins, but some are | | MachineScript | Same as above, just as either a startup or shutdown script. Detected via GPOs | +| MemberOfGroup | The entity is a member of this group | +| Owns | The entity owns the object, and can do anything it wishes to it | +| ReadLAPSPassword | The entity is allowed to read the plaintext LAPS password in the mS-MCS-AdmPwd attribute | +| ReadMSAPassword | The entity is allowed to read the plaintext password in the object | +| ResetPassword | The ACL allows entity to forcibly reset the user account password without knowing the current password. This is noisy, and will alert at least the user, who then no longer can log in. | +| ScheduledTaskOnUNCPath | The object contains a scheduled task that sits on a UNC path. If you can control the UNC path you can control what gets executed | +| SIDHistoryEquality | The objects SID-History attribute points to this entity, making them equal from a permission point of view | +| TakeOwnership | The entity can make itself the owner | +| WriteAll | The entity is allowed all write operations | +| WriteAllowedToAct | The entity is allowed to write to the ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute of the object, so we can get it to accept impersonations what would otherwise not work | | WriteAltSecurityIdentities | The entity is allowed to write to the Alt-Security-Identities attribute, so you can put your own certificate there and then authenticate as that user (via PKinit or similar) with this certificate | +| WriteAttributeSecurityGUID | The entity can write to the AttributeSecurityGUID. I'm not sure if this will work, but it has the potential to allows you to add an important attribute to a less important attribute set | +| WriteDACL | The entity can write to the DACL, effectively giving it all permissions after granting them | +| WriteExtendedAll | The entity is allowed to do all extended write operations | +| WriteKeyCredentialLink | The entity can write to the msDK-KeyCredentialLink attribute | | WriteProfilePath | The entity can write to the user profile path of the user | +| WritePropertyAll | The entity can write to any property (same as above, ACL is just a bit different) | | WriteScriptPath | The entity can write to the script path of the user, giving them instant remote execution when the user logs on | -| CertificateEnroll | The entity is allowed to enroll into this certificate template. That does not mean it's published on a CA server where you're alloed to do enrollment though | +| WriteSPN | The entity can freely write to the Service-Principal-Name attributes using SETSPN.EXE or similar tools. You can then kerberoast the account | +| WriteValidatedSPN | The entity can do validated writes to the Service-Principal-Name attributes using SETSPN.EXE or similar tools. You can then kerberoast the account | + +## Plotting a path in the GUI + +There is a right click menu on objects, so you can to searches in the displayed graph. First right click a target: + + + +Then find a source to trace from: + + + +If there's a connection from source to target, you'll get the entire attack path presented like this: + + + +You can also pick any object on the graph, and to a normal or reverse search from it. ## Current limitations @@ -254,7 +304,7 @@ The tool has its own LDAP query parser, and makes it easy to search for other ob ## Frequently Asked Question: How does this compare to BloodHound? -Since this is a frequent question, here's a short list of things I know that differentiate. I haven't looked at BloodHound for a long while, and not while doing adalanche - I wanted to try to figure things out myself and not be opinionated because of designs from others. +Since this is a frequent question, here's a short list of things I know that differentiate. I haven't looked at BloodHound for a long while, and haven't used it all while doing adalanche - I wanted to try to figure things out myself and not be opinionated because of designs from others. | Feature | adalanche | BloodHound | | ------- | --------- | ---------- |