Friday, August 23, 2019

RACE - Minimal Rights and ACE for Active Directory Dominance

I recently spoke at DEF CON 27 on abusing Security Descriptors and ACLs i.e. permissions on Windows machines. 

You can find the slides here (also at the end of the post with minor updates). The demo videos which I used for my talk can be found here on and are also used below. 

The RACE toolkit is available on my GitHub repository.

This blog post covers whatever I could not do in my talk. There is only so much you can cover in 45 minutes. On top of that, there was some confusion and my talk was cut short by 10 minutes -.-

tldr; It is possible to execute interesting persistence and on-demand privilege escalation attacks against Windows machines by only modifying ACLs of various objects. We will need administrator privileges initially.

So, let's begin.

We are going to use 'labuser' as the attacker controlled user and 'ops' is the target domain.

About Windows Access Control Model:

Microsoft's documentation on Access Control Model explains it really well. But below is a quick summary:

Every authenticated user gets an access token. Each process or thread created by that user has a copy of that access token. The token contains identity (SIDs) and privileges of the user. 

Now, when a process tries to access a securable object (Files, Registry Keys, Services, Domain Objects etc.) it uses the access token. A securable object, by definition, has a security descriptor. A security descriptor can contain Access Control List (ACL) which is a list of Access Control Entries (ACE). There are two types of ACLs  Discretionary Access Control List (DACL) and SACL (System Access Control List). 

DACL controls access to an object and SACL controls logging of access attempts. 

So, when a process or thread tries to access a securable object, the system checks the permissions for the access token (and therefore the user) against each ACE in DACL. The process gets access in case of an explicit allow or if there is no DACL. All other cases result in an access denied. 

An ACE contains access control information. The relevant information to this discussion is access mask. The access mask in an ACE contains access rights. This governs what a user can do on an object. For example, a user may have permissions to stop a process whereas another may have the access rights to configure a process. This is what defines access in Windows. 

Minimal Permissions

Once we have understood the concept, let's think what makes a Domain Admin so powerful? 

A Domain Admin is so powerful because it has permissions to modify almost all objects on machines in a domain.

Do we need Domain Admin privileges for all the interesting things? Not really! We can use just enough rights to perform a particular task. That is, in place of having FullControl or GenericAll over an object we can use Minimal Permissions required to perform a task. 

For example, what allows a user to connect to a remote machine using PowreShell Remoting? By default, administrator rights are required. If we have a look at the ACL of the PowerShell Remoting Endpoint we understand that the Administrators group has FullControl over it:
Do we actually need 'FullControl' to access the target machine using PowerShell Remoting? No! We can connect to the target machine by adding an ACE for a user which we control and provide it Read, Write and Execute permissions. This will allow the user to access the target machine using PSRemoting without admin privileges. Please note that the user's privileges on the target machine will not be elevated!

This is what we are going to focus on. Some interesting backdoor/persistence techniques, some on-demand privilege escalation methods by modifying ACLs of various securable objects.

Introducing the RACE toolkit

To make it easy to execute ACL related attacks, I have written the RACE toolkit. RACE is dervied from Minimal Rights and ACE. You can find it on my GitHub :

RACE is a PowerShell module for executing ACL attacks against Windows targets.

RACE uses the ActiveDirectory module for some of the attacks (Set-ADACL and Set-DCPermissions functions). You can get it from a machine where AD DS RSAT is available or from here:

Persistence - PowerShell Remoting

As we saw above, it is possible to access a target machine as a non-admin user using PSRemoting by modifying the ACL of the PSRemoting endpoint. 

Using the below commands from RACE, we can modify the ACL of the default PSRemoting endpoint. Let's run it on the DC with DA privileges (please ignore 'I/O operation has been aborted'):
Now, we will be able to access the target machine 'ops-dc' as labuser using PowerShell Remoting. Please note that the privileges will still be of labuser.
Here is a video of the above attack:

There are no logs for the ACL modification of PowerShell endpoints. Although, when accessing the target machine there will be Events 4624 (Logon) and 4634 (Logoff).

How is this access useful? We can chain this with other modified permissions. We will come back to that later.

UPDATE 29/02/2019 - Forgot to mention that this is useful against PowerShell Web Access too. If we have credentials of lab user and PSWA is enabled on the target machine, we can access the target machine using the credentials.

Persistence - WMI

Similarly, we can modify ACLs to access a machine using WMI without admin privileges. In case of WMI, we need to modify ACLs for DCOM endpoint and also for namespaces. For namespaces, we can do it for all of them or only a specific one. The below command does it for all the namespaces:
 Now, we can simply run commands as 'labuser' on the target machine:
WMI Permanent Event Consumers - In my testing, with modified permissions to the root\subscription namespace it was possible to create permanent event consumers but the payload never executed. This is something which someone else can explore. 

Like PSRemoting,  there are no logs for ACL modification but logs 4624 and 4634 will be there when we use WMI to access the target machine.

On-demand Privilege Escalation - Windows Services

Windows services are very useful for persistence AND getting admin privileges back.

Here is how we can abuse admin privileges with windows services:

- Initially with admin privileges, we can create new services or modify existing services to run as SYSTEM. 
- We also modify ACLs of such services to allow permissions to config and restart for a user we control.
- As the user we control, reconfigure the target service on the target machine to change its executable path to our payload. 
- Restart the service to execute the payload. 

Creating new service:
Use the below command to provide labuser GenericAll rights over scmanager (needs admin rights):
SCManager is a special service which provides the ability to create new services on a machine. After the above command, labuser can create services on the target machine:
The above command sets the service start type to auto and the account to LocalSystem. The binpath or executable of the service is set to the specified payload. By default, the payload is to add the user specified by UserName parameter to the local administrators group.

After the above command, we can either wait for the service restart or a system reboot:

If you don't want to wait, run the below command (suggested by the tool) with admin privileges on the target machine to get restart permissions for the created service for our user:

Now, when we restart the 'evilsvc' service, 'labuser' is added to the local administrators group on the target machine.

Modifying existing service:

With admin equivalent permissions (CCDCLCSWRPWPDTLOCRSDRCWDWO) on any service, we can abuse it to escalate privileges. Please refer to the documentation for a full list of the rights.

The below command modifies the ACL of ALG service on the target machine to provide 'labuser' enough rights to configure and restart the service:
Next, run the below command as labuser:

Now, when we restart the ALG service, labuser is added to the local administrators group on the target machine.

Below is a video of the attack:

I prefer using an existing service in place of creating a new one.

Please note both the methods are verbose in the logs. Service creation, service configuration changes and service stop/start is logged. Therefore, this method is not recommended on DCs or when you want to be stealthy. 

On-demand Privilege Escalation - Registry Autoruns

Windows registry is a very attractive target for persistence with on-demand privilege escalation. As a very simple example, let's have a look at Image File Execution Options which is a popular method of running a payload as SYSTEM using 'sticky keys'. 

The idea is to modify the ACL of the Registry key responsible for Remote Registry (HKLM:\ SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg) and for sethc.exe (HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe) to be able to change registry remotely without needing admin privileges. To be able to trigger this remotely on a RDP logon session, NLA needs to be disabled by modifying (HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp).

Run the below commands with admin privileges on the target machine to setup the registry key permissions:

Then run the below command as labuser to set payload for sethc and to disable NLA:
Now, try to connect to the target machine using RDP and press the Shift key five times to get a command prompt with SYSTEM privileges!

The particular method we used is not very silent (even some AVs flag modification of Image File Execution Options registry key) and actually downgrades the security of the target machine. So please use this carefully in an actual operation. 

Implementing some better registry key based command execution is something which is in future goals of the RACE tool.

Persistence - DCOM

We can modify the ACL of the DCOM endpoint (recall that we already did that while abusing WMI) for persistence. Like WMI, we will have command execution with the privileges of only the current user. But as we will see soon, something like that is very helpful when chained with other ACL modifications. 

Run the below command with admin rights on the target machine to modify ACL of DCOM endpoint:
Now, run the below command as labuser to execute commands using DCOM on the target machine. By default, the method used for execution is MMC20.Application class.

On demand Privilege Escalation - Just Enough Administration (JEA)

JEA is a PowerShell v5 feature which provides control over administrative tasks by providing PowerShell Remoting endpoint with:
- Virtual accounts - temporary local accounts which are local admin on member machines and DA on DCs but no rights to manage resources on network. 
- Ability to limit the cmdlets and commands which a user can run through Role Capabilities. 

JEA is designed to 'allow non-admins to do some admin tasks' with 'least privileges'. This is precisely what we have been doing so far. 

So, JEA provides admin rights to anyone who is explicitly allowed to connect to the endpoint. But the control on those administrative rights is because of the commands and cmdlets they can execute as a JEA session starts in NoLanguage mode. Only explicitly allowed commands and cmdlets are allowed. It is possible to only allow a single command with only one parameter or argument allowed!

JEA endpoints also have transcripts enabled so that all the commands and their outputs are written to a flat text file. In addition to that, Event logs for 'WinRM Virtual Users\WinRM_VA_AccountNumber_domain_username' will be logged. PowerShell script block logging may also log any suspicious logs. 

With all these checks, how can we abuse JEA? Look at the JEA Security Considerations for some evil ideas ;) 

With admin privileges on the target machine, we can Register a new JEA endpoint, allow all the cmdlets and commands and allow a user we control to connect to it. We can set the transcript log path to user's temp directory and clear the transcripts when we connect to the machine. 

Let's use this against a DC. Run the below command with DA privileges to create a JEA Endpoint 'microsoft.powershell64' which allows access to labuser:
 Now, as labuser we can access the DC and get DA privileges for local context:
Neat, isn't it!

Below is a video of the attack:

Please note that there are no logs for new session registration. But, there are Events 4624, 4634 and 4717 when we access the target machine. Alos, keep in mind the PowerShell logs.

The best way to avoid against JEA abuse really is to audit the registered session configurations and role capabilities. A good guidance on audit and report on JEA is here.

Persistence - Registry

Windows registry stores many interesting credentials - Machine account, Local users and Cached domain credentials. By modifying the ACL for the registry keys where we store these credentials, it is possible to access these credentials without needing admin privileges later on. We need to modify permissions of the following registry keys:
- HKLM:\ SYSTEM\CurrentControlSet\Control\Lsa\
- HKLM:\Security\

Once we have modified the ACLs of these keys, we can then modify ACL of Remote registyr, WMI or PowerShell Remoting to access the machine and extract the credentials.

RACE uses code from the DAMP toolkit for this:

Use the below command to modify the permissions of the above registry keys and remote registry. We are targeting a DC so need DA privileges.:
Now, use the below command to extract the machine account hash (uses remote registry):
ICYMI, machine account of DC can run the DCSync attack!

Use the Get-RemoteLocalAccountHash function to ectract local acccount hashes. In case of the DC, this gives the NTLM hash of the DSRM account!

Remeber that we left a question - how modifying ACLs of PSRemoting is useful? This is a very good example. in case you cannot access remote registry (for example, filtered on firewall), you can modify the ACL of PSRemoting and the Registry keys and extract the secrets from the DC without admin privileges:
Below is a video of the attack:

Note that there is no log for change in permission of the registry keys. But as for the other attacks, there will be 4624 and 4634 log entries when accessing the DC.

On demand Privilege Escalation on DC - DNSAdmins

DNSAdmins is an AD security group which has the capability to load arbitrary DLLs from a UNC path in the DNS service. See this post and my post. This group is effectively DA equivalent if DNS service is running on a DC.

The group has Read, Write, Create All Child objects, Delete Child objects, Special Permissions on the DNS Server object. We can either:
- Modify ACL of the DNS Server object to have the same rights as the DNSAdmins group to abuse the DLL configuration feature.


- Modify the ACL of the DNSAdmins group because it is not a Protected Group (ACL not protected by AdminSDHolder)

Let's modify the ACL of the DNS Server object to be able to load DLL remotely and also provide service start and stop rights on the DNS service for a user we control. Use the below command:
Now, use the below command as labuser to load mimilib.dll from Mimikatz to load the DLL in DNS Service. Please note that the DNSServer module from DNS RSAT is required for the below command:

On demand Privilege Escalation on DC - DSRM Administrator

DSRM administrator is a special 'local administrator' account on a DC. This is very useful for persistence as it is seldom changed. By default, this user cannot logon from network. But this logon behavior can be changed by modifying the registry key - HKLM:\System\CurrentControlSet\Control\Lsa\DsrmAdminLogonBehavior and set its value to 2.

This means, once we have DA privileges, we can:
- Extract the hash for DSRM administrator (Invoke-Mimikatz -Command '"token::elevate" "lsadump::sam"') or we can  also chain this with modification of registry keys, as discussed previously, to obtain the DSRM hash without admin privileges.

- Modify the permissions of the above registry key so that a user we control can change it on demand.
- Use Mimikatz PTH to connect to the DC.

Lets try it. Run the below command to modify the DSRMLogonBehavior registry key and allow labuser to modify it anytime. If the key doesn't exist, it is created:
As labuser, we can modify the registry key. Note that this needs to be coupled with modification of ACL of a remote access method (PSRemoting, WMI, Remote Registry or DCOM). Let's use PSRemoting for that:

Now, we can use PTH (note the /domain parameter in the below command) to access the DC. We need to use NTLM authentication to access the DC as we are using a local account:

Persistence using DC - Resource-based Constrained Delegation (RBCD)

Resource-based Constrained Delegation enables the resource owner to set delegation to it. Unlike the traditional Delegation, DA privileges are not required to set RBCD.

As per this post, for Generic DACL abuse of RBCD, if a user we control has Write permissions on a computer object, that user can configure RBCD on the machine. This allows the ability to access the target machine as any user including DA.

Use the below command to give labuser permissions to configure RBCD on 'ops-file' by modifying the ACLs of ops-file computer object. This will need DA privileges:
As labuser, run the below command (needs the ActiveDirectory module) to configure RBCD from attacker machine ops-user1$ to ops-file. This enables us to access ops-file as any user when we impersonate the ops-user1 machine:
We can extract the AES256 keys for the ops-user1$ account by dumping credetials on that machine (Invoke-Mimikatz -Command '"sekurlsa::ekeys"').

Now, we can use Rubeus to impersonate a DA which effectively means local admin on ops-file.
Please note that we are merely impersonating the DA for accessing ops-file. We cannot access any other machine from ops-file as DA.

Persistence using DC - Exchange Groups

Exchange creates multiple groups on installation. Groups like Exchange Servers, Exchange Trusted Subsystem and Exchange Windows Permissions have interesting permissions. The groups are added in a new container 'Microsoft Exchange Security Groups'. 

None of the Exchange Groups is a protected group so we can modify their ACLs for persistence.
Let's target the Exchange Windows Permissions group which has WriteDACL permission on the domain object (or even forest root domain object depending on the installation).

In our example, we target the Exchange Windows Permissions group on the forest root powershell.local. 

Using DA privileges (on forest root in this case), run the below command to provide labuser WriteDACL permissions on the Exchange Windows Permissions group:
Now, as labuser, we modify the ACL of the Exchange Windows Permissions group and add WriteMember rights to labuser. Note that this is just one of the paths once we have WriteDACL on the group:
Next, add labuser (or a proxy user) to the Exchange Windows Permissions group. Because of this group membership, labuser will have WriteDACL rights on the domain object of the forest root:
Usig the WriteDACL rights with labuser, add DCSync rights for labuser:
Finally, run the DCSync attack:

Below is a video of the attack:

Other well known techqniues implemented in the RACE tookit are:


ICYMI, the ACL of the AdminSDHolder is overwritten on all Protected Groups by an automatic process called SDProp every 60 minutes. This means any changes we do to the ACL of AdminSDHolder will be propagated to all the Protected Groups too. Therefore, it is a very interesting persistence technique.

Use the below command as DA to add WriteDACL permissions for labuser on AdminSDHolder:
This allows us to push whatever permissions we want on all the Protected Groups as labuser:


The most famous ACL abuse. We can modify the ACL of the domain object to provide DCSync rights to a user we control. Run the below as DA:


DCShadow provides very useful forest persistence. See this and this.

With DA privileges on forest root and from a machine joined to forest root, run the following command to modify ACLs of multiple objects. This will allow to run DCShadow without DA:
The above command modifies ACLs for:

The domain object.
- DS-Install-Replica (Add/Remove Replica in Domain)
- DS-Replication-Manage-Topology (Manage Replication Topology)
- DS-Replication-Synchronize (Replication Synchronization)

The Sites object (and its children) in the Configuration container.
- CreateChild and DeleteChild

The object of the computer which is registered as a DC - ops-user1 above.
WriteProperty (Not GenericWrite)

The target object - serviceuser above
WriteProperty (Not GenericWrite)

We can now run DCShadow against serviceuser from ops-user1 as labuser.

Previous work

Directly taken from my talk slides:
- ACL abuse is not something new, system administrators have been using this for so many years!
- (French) Chemins de contrĂ´le en environnement Active Directory


Protecting your privileged users is definitely the best defense.

Event logs are also useful for detecting these attacks. While there are almost no logs for ACL changes in the default configuration, we can still use the security logs when someone accesses a target machine using Events 4624, 4634 and 4672 in case of admin logon.

For ACL change logs, configure Auditing for ACL changes. See this technet article for guidance.

Regular ACL auditing is also useful in weeding out unnecessary or malicious ACEs. We can use tools like BloodHound, ADACLScanner and PingCastle for that.

A project I created Deploy-Deception, can be used in creating accounts which have mis-configured ACLs and have verbose logging enabled. It is useful tricking an attacker in assuming they found object(s) with misconfigured ACLs

Future Work

Directly taken from my talk slides:

- Service Permissions are stored in Registry. So, that is a place ripe for abuse.
-  As noted earlier, WMI Permanent Event Consumer needs to be explored more.
- For the RACE toolkit, work on hiding the ACE we introduce is highly desirable. Also, implementation of more Registry Autoruns! Currently, Remove option does not work for multiple functions.

That is all! Hope you like it!

Slides of the DEF CON 27 talk:

Thursday, April 18, 2019

How NOT to use the PAM trust - Leveraging Shadow Principals for Cross Forest Attacks

I did a super interesting AD security assessment for a client recently. They are re-deploying their infrastructure and upgrading their forest(s) to Server 2016 Functional Level. There are so many interesting things which we did during the assessment but the most interesting for me was their attempt to establish Privileged Access Management (PAM) trust in an "interesting" way. It is a classic example of deploying something which sounds secure without actually understanding what it does. 

Microsoft introduced Privileged Access Management (PAM) with Server 2016. Among other things, it has very interesting features like -
- A bastion forest (Think the administrative forest in ESAE or the famous Red Forest)
- Shadow security principals
- Temporary group membership (Add a user to a group with time-to-live (TTL))

So what is PAM? 

PAM has been discussed in much detail here by Russel and here by Willem. Please read them for understanding what PAM has to offer. A quick explanation is below:

In a perfect world, PAM enables managing an existing production/user forest using a bastion forest which has a one-way PAM trust with the existing forest. The users in the bastion forest can be 'mapped' to privileges groups like Domain Admins and Enterprise Admins in the user forest without modifying any group memberships or ACLs. This is done by creating Shadow security principals in the bastion forest, which are mapped to SIDs for high privilege groups in the user forest and then add users from the admin forest as members of the shadow security principals.


Let's have a look at an example. We have powershell.local as our user forest and bastion.local as the bastion or admin forest. What we want to do it to be able to manage powershell.local from bastion.local without modifying any group membership or ACLs on powershell.local.

A one way PAM trust can be established between the two forest using the commands below (taken from Petri article linked above) :
On user forest (powershell.local in our example) -
On bastion forest -
Shadow Principals reside in a special container 'CN=Shadow Principal Configuration' in the Configuration container on bastion forest. We can create Shadow security principals on bastion.local using the below PowerShell code:
In the above command we are mapping the SID of Enterprise Admins group of the user forest powershell.local to a Shadow security principal "psforest-ShadowEnterpriseAdmin". Please note that we can also map the shadow principal to a user in the user forest.

Shadow Principals reside in a special container 'CN=Shadow Principal Configuration,CN=Services' under the Configuration container on bastion forest. We can create Shadow security principals on bastion.local using the below PowerShell code:
Now, it is possible to manage powershell.local forest from bastion.local without making any changes in the group memberships or ACLs on powershell.local.

This looks great! This takes away administrative overhead of managing groups and ACLs and reduces chances of lateral movement techniques like OverPTH, PTT and other credential relay techniques.

Now, there is something worth noticing about the above setup. To be able to use the shadow security principals, we had to allow SIDHistory in the PAM trust which means no SID Filtering. We will see in the next section how this can be dangerous if not configured properly.

The Misconfiguration


Let's get back to the scenario I saw during the assessment. The client enabled PAM and they were using a forest in production (not a separate bastion or admin forest) to manage other forest(s). The forest used to manage other forests was located at their headquarters and their forests for their sites across the country were managed using it. An applause for them to have separate forests for different locations :)

They were sold on the part that using PAM will protect the credential based attacks - no logon using credentials from the bastion forest to any other forest.

But, a PAM trust where you do not have an isolated bastion forest is disastrous. Why? Because in such a case if we compromise the bastion forest we get high privileges (Enterprise Admins or Domain Admins) in the other forest. And:
- There is no group membership (unlike Foreign Security Principals)
- No ACLs modification
- AFAIK, no other modification to look for in the forest which gets compromised!

Let's have a look at an example. Following is the setup in my lab (diagram built using
defensiveps.local is the bastion forest and powershell.local is the user/production forest.

Abusing the PAM trust

Here is how to identify and approach abusing a PAM trust:


First, let's enumerate if our current forest has any PAM trust with any other forest, that is, if our current forest can access any other forest without worrying about SID Filtering.

Using the ADModule, we can simply run Get-ADTrust and look for a trust which has ForestTransitive set to True and SIDFilteringQuarantined set to False - this means that SID Filtering is disabled.

Powerview (dev branch), calculates the TrustAttributes for you but does not tell you if SID Filtering is enabled when used from the user/production forest.

On the other hand, if you want to enumerate if your current forest is managed by a bastion forest (Blue Teams take note), look for ForestTransitive set to True and SIDFilteringForestAware set to True. In this case, TrustAttributes is also a very good indicator. It is 0x00000400 (1024 in decimal) for PAM/PIM trust. Simplifying it, it is 1096 for PAM + External Trust + Forest Transitive.
In this case (when rum from the bastion forest), PowerView (dev) tells if PIM Trust is enabled.

Next, let's enumerate the shadow security principals, its members from the current (bastion) forest and privileges in the user/production forest. We can use the following command from the ActiveDirectory module:
As clear in the above screenshot, we can look for Shadow securtiy principals in the special container 'CN=Shadow Principal Configuration,CN=Services' under the Configuration container on bastion forest. Following properties are the most interesting ones:

- Name - Name of the shadow principal

- member - Members from the bastion forest which are mapped to the shadow principal. In our example, it is the Domain Administrator of defensiveps.local.

- msDS-ShadowPrincipalSid - The SID of the principal (user or group) in the user/prodcution forest whose privileges are assgined to the shadow security principal. In our example, it is the Enterpise Admins group in the user forest.

Using the shadow principals

Now, if we compromise the user listed in "member" above we can use the shadow principals. In our example, we need to compromise the Administrator user fo defensiveps.local forest and then we will have enterpirse admins privileges on powershell.local forest!
This is very interesting! We crossed the forest security boundary with ease :) Remember that we need not have group membership or ACL on the user forest.

With the privileges achieved using shadow principals above, we can access the user forest using RDP (explicit credentials of the bastion user required), WMI, PowerShell Remoting etc. Please note that if Kerberos AES Encryption is not enabled for the PAM trust, we need to add the machines of existing forest in WSMan TrustedHosts and use '-Authentication Negotiate' option with PowerShell remoting cmdlets.
UPDATE (23/04/2019): Please note that we can also use SIDHistory injection using mimikatz to abuse the PAM trust. I left it out because using a shadow principal looks more normal in the user forest then SIDHistory injection. But, since Riccardo pointed out that it will still be useful, please take a note of it!


We can also use this for persistence. Please note that the persistence will be for the privileges on the user/prodcution forest and not the bastion forest itself. 

Once we have compromised the bastion forest, there are multiple ways we can use:

1. We can add a user to an existing shadow security principal container.

Please note that in this case, if someone looks at the details of the 'lowprivuser', he/she would appear to be a part of the psforest-ShadowEnterpriseAdmin 'group'.

2. Better, we can modify the ACL of the shadow principal object. We can provide a user we control, Full Permission overt shadow principal object but the fun is always with minimal permissions. So, with only Read Members and Write Members permissions on the shadow principal object, we can add and remove princiapls at will from the shadow principals. Take a look at the below screenshot:

Now, we can add or remove users at will with the privileges of 'reportdbadmin' user. On top of that, by-default there are no logs for any changes to the ACL or 'membership' of a shadow principal :)

Is PAM trust bad? Should I stop using a bastion forest?  Why is Microsoft so evil? What is the meaning of life?

PAM trust is not bad, IF used wisely! You can use a bastion forest with PAM trust but please be careful. Learn from the setup we discussed just now. Do not use a regular forest (with users doing non-admin activities) as bastion forest. As Willem pointed out in his article, when you use the PAM trust you extended the security boundary of the user forest to include the bastion forest. Treat the bastion forest as a special case and you will be fine.

UPDATE: I forgot to link this: Microsoft provides guidance on providing access to the bastion forest using Microsoft Identity Management (MIM).


On the bastion host, as we already discussed, there are no logs by-default for modification of membership or ACL of shadow principals.

On the existing/production forest, the detection seems pretty easy. There will always be the Special Logon (4672), Logon (4624) and Logoff (4634) events when anyone uses principal from the bastion forest to access the existing forest. But the problem here is to detect an anomaly as the same logs will be there for actual operations as well. Unless, an adversary is using a new user or doing something very noisy, it may be difficult to detect her with only these entries.

I hope this post enocurages everyone to have another look at their forest trusts. As always, please leave feedback :)

Wednesday, October 31, 2018

Using ActiveDirectory module for Domain Enumeration from PowerShell Constrained Language Mode

This is a quick post to make notes of something which I have been using and teaching for sometime.

We can use Micorosft's PowerShell ActiveDirectory module without RSAT and administrative privileges. I came to know about this from this blog post.

So, if you have access to a Server which has the module installed (like a DC), copy the Microsoft.ActiveDirectory.Management.dll from C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ActiveDirectory.Management to your own machine and then use the Import-Module cmdlet to import the DLL:
Please note that if you run Get-Command -Module ActiveDirectory, it would not return anything. To get that, copy the module directory as well from the server from following location: C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\. Then, use Import-Module, first the DLL and then the module:
UPDATE (16-Nov-2018) - It is now possible to load the module from memory by using Import-ActiveDirectory.ps1. Thanks to a PR by @D1iv3:
There are many benefits like very low chances of detection by AV, very wide coverage by cmdlets (I leave the usage of cmdlets for a later post :P), good filters for cmdlets, signed by Microsoft etc.

I have uploaded a copy of module from Server 2016 on Github:

The biggest benefit is that this module works flawlessly in PowerShell Constrained Language Mode (CLM) :)
That is all!

Tuesday, October 16, 2018

Forging Trusts for Deception in Active Directory

Deception has always been of interest to me. As a student of military history, I have always been fascinated by its implementation in warfare and looked at deception as something which is effective and generally low cost!
Couple of years back, I got involved in development and extensive testing (from red team perspective) of couple of enterprise deception solutions over a period of many months. In early 2018, during one of my Active Directory classes, a student  asked and ultimately hired me (thank you!) for testing three Deception products they were evaluating. 

With these experiences I realized that most of the focus for deception in Active Directory (AD) has been on honeyuser/honeytokens/honeycredentials. Tools like dcept and others are popular for this technique. There is a dearth of free and open source deception solutions for AD if we want to utilize deception to detect an adversary during the domain enumeration phase of an attack. That is something which we are going to address soon.

Also, to increase interest and community involvement, I gave a talk on 'Forging Trusts for Deception in Active Directory' at BruCON couple of weeks back (October 2018). Slides and video are at the end of this post.

What is Deception?

Deception is a psychology game. Red teams and adversaries have been using it for so long against unsuspecting users to trick them in opening malicious attachments or clicking on links. Once inside an AD environment, an adversary tries to use credentials of other users and pivot through other machines to mix with the existing logs and traffic.

Blue teams utilize deception by providing service, privileges or information can adversary is looking for. IMHO, blue teams, have an upper hand when it comes to deception, both in terms of psychology and technical controls.

The attacker psychology 

There is a psychological condition called Illusive Superiority which applies to most of the adversaries and red teams. They think of themselves as smarter and much more talented than the blue teams. Along with this, the tendency to go for the "lowest hanging fruit" and an urge for getting DA privileges quickly, makes them a fruitful target for deception :)

So, the idea is, defenders show the adversaries what they want to see. For example, a user whose password never expires or a Server 2003 computer.

Desired properties of a decoy

Taken directly from my slides, desired properties of a decoy:
  1. Should be desirable enough so that an attacker enumerates the object.
  2. Should be easily configurable.
  3. No configuration changes required on endpoints.
  4. Should not be triggered for normal admin activity.
Number 4 above is the hardest to achieve. If we are targeting enumeration, we must make the attacker activity or tools stand-out to avoid false positives.

Deploying Deception

So, how can we achieve above desired properties with just the built-in tools in AD? We can use Group Policy to set AD Access logging, configure 'interesting' objects and filter out false positives!

The Group Policy setting required for AD Access is Windows Settings | Security Settings | Advanced Audit Policy Configuration | DS Access - Audit Directory Service Access
AD Access Group Policy
Above setting results in a Security Event 4662 whenever an AD object is accessed. The logging needs to configured at the object level. For that configuration, we need to modify the SACL of the object and add relevant ACEs.

Let's have a look at the AddAuditAccessObjectAce function to understand ACE:

So, as an example, we can set auditing whenever 'everyone' uses 'ReadProperty' 'success'-fully against a user. This helps in detecting any enumeration against that user.

Introducing Deploy-Deception

These settings can be done using GUI. But thanks to PowerShell and the ActiveDirectory module, it can be automated.

To automate the setting up of decoy object with interesting attributes and lesser known properties to avoid false positives , I wrote Deploy-Deception. It is a PowerShell module which utilizes the ActiveDirectory module to deploy decoys easily and efficiently. You can find Deploy-Deception on Github here:

Let's have a look at setting up of different types of object decoys during different phases of an attack.

Enumeration - Decoy User Objects

User objects are the most interesting objects  Some user properties are of interest for an attacker:
  • Password does not expire
  • Trusted for Delegation
  • Users with SPN
  • Password in description
  • Users who are members of high privilege groups
  • Users with ACL rights over other users, groups or containers
We can use Deplou-UserDeception function to create a decoy user.
Let's create a decoy user 'usermanager' whose password never expires and a 4662 is logged whenever everyone reads any of its properties:

Please note that an actual user objects is created in the domain. Now, the above gets triggered very frequently as we have enabled the default logging for whenever anyone reads any property of the user usermanager. It means a 4662 will be logged even if someone simply lists all the users in the domain. This means, that this decoy will trigger logging for all the possible usage (normal or otherwise) like

net user /domain

Get-WmiObject -Class Win32_UserAccount

Get-ADUser -Filter * (MS ActiveDirectory module)

Get-NetUser (PowerView)

Find Users, Contacts and Groups GUI

That does not look good, right? So we need to find ways to differentiate attacker enumeration from normal activity. There is something very interesting with attacker enumeration tools, they like to extract as much information for an object as possible (which makes sense as you would not like to connect repeatedly to a domain controller). Now, this means that if we turn on auditing for an uncommon attribute, there is a large possibility (yes, possibility - share your false positives with me please :P) that only aggressive enumeration triggers the logging. There are many such attributes, have a look at the List of All Attributes. I liked once such attribute - x500uniqueIdentifier (GUID d07da11f-8a3d-42b6-b0aa-76c962be719a)

So, we now remove the ACE we added previously and add a new one which triggers logging only when x500uniqueIdentifier property is read:
This auditing is triggered only by tools like PowerView (or other tools like ADExplorer) which fetches all the attributes of an object. While not perfect, this is a huge improvement.

If you have enough confidence that none of your monitoring or management tools read all the properties of a user object, auditing for properties like SPN can also be set which triggers logging only when SPN (or all attributes) is read.
Still too many logs? The below command logs a 4662 log only when DACL (or all attributes) of the decoy user object is read:

Enumeration - Decoy Computer Objects

We can also set decoy computer objects. It is possible to create computer objects in domain without having an actual computer mapped to that object. Although, it is always advised to use actual computers or VM for decoy computer objects to avoid identification of decoys.

Some computer object properties which are of interest to an adversary:
  • Older Operating Systems
  • Interesting SPN
  • Delegation Settings
  • Membership of privileged groups
Let's have a look at some deployment using Deploy-Deception, we can use Deploy-DecoyComputer function. :
Above command creates a decoy computer that has Unconstrained Delegation enabled and a 4662 is logged whenever x500uniqueIdentifier or all the attributes of the computer are read.
Above command uses an existing computer object and sets Unconstrained Delegation. Logging is triggered whenever DACL or all the attributes of the computer are read.

We can also use DCShadow to modify a computer object which appears to be a DC. I briefly touched on this here. More on this particular topic some other day.

Enumeration - Decoy Group Objects

We can also deploy decoy Group objects. What properties of a group are interesting to an adversary?
  • Interesting name (containing words like admins, administrators etc.)
  • Members of the group are also member of high privileged groups or have 'interesting' user attributes. 
  • Membership of a high privilege group.

Groups provide interesting opportunities. We can make decoy users member of a decoy group thus creating 'layered' decoys. This way we get logs both when membership of the decoy group is listed and when attributes of the decoy user are listed. We will see soon how to use Logon restrictions to avoid mis-use of privileges of a user.

So in the below command, we create a decoy user 'dnsmanager' whose password never expires with logging when an obscure property is read, create a group with name 'Forest Admins', make dnsmanager part of the forest admins group and add the forest admins group to the built-in dnsadmins group. Logging is triggered when membership of the group is read. We can use Deploy-GroupDeception for this:

Enumeration and Lateral Movement - Privileged Decoy User Objects

We can also deploy high privilege user decoys to target both enumeration and lateral movement. We can create decoy users which have high privileges like membership of domain admins, rights to execute DCSync etc.

Now, the risk with having decoy users with such high privileges is if such a user gets compromised, its privileges can be abused. To avoid that,  we can use couple of protections:
  • Set the Logon Workstation to a non-existent machine
  • Deny logon to the user.
In both the above cases, AFAIK, user privileges cannot be used as the decoy user cannot logon to any box with any type of credential like password, hash etc.

Armed with this knowledge, let's create high privilege user decoys using Deploy-PrivilegedUserDeception :
The above command creates a user called 'decda' who is a part of the Domain Admins but cannot logon to any machine. Any attempt to list DACL of the user or list all attributes results in a 4662 log.

For the lateral movement part, we have used the DenyLogon protection. That means even if the user's password or hash or keys are compromised, it will not be possible to reuse those credentials. To get meaningful logs when credentials of such a user are used, we must enable the following Group Policy:
Configuration|Windows Settings|Security Settings|Advanced Audit Policy Configuration|Audit Policies|Account Logon | Audit Kerberos Authentication Service | Failure
This is how the failure looks like in GUI.
And a 4768 (Failure) is logged on the Domain Controller. In case of attacks like OverPass-The-Hash no such verbose error is returned.

Another option is to set LogonWorkstation to a nonexistent machine. It always makes sense to use a name similar for the workstation that is similar to your actual machines.
Above command creates a decoy user call 'decda', provides it with DCSync permissions and sets the LogonWorkStation to a non-existent machine. If the users credentials are compromised and re-used the error would exactly be the same as in case of DenyLogon and a 4768 is logged.

Both the protections can be used with a non-DA account as well. IMHO, this is better than leaving wrong passwords or hashes in memory (which is a well known technique).

This technique can always be coupled with others. For example,when targeting lateral movement, one of the easier ways to let an adversary 'retrieve' credentials for a decoy user is to use the -PasswordInDescription option of Deploy-UserDeception. Then, we can make that user a privileged user and use one of the protections discussed above:
The first command above creates a newuser called 'newda', sets the string 'The new password is Pass@123' as its description. The second command makes newda a member of the domain admins group, denies logon to the user and configures auditing whenever DACL or all attributes of newda are read.

No special tools are required to get the password from description! Remember targeting 'go for the lowest hanging fruit' ;)

While discussing users with privileges, there is another important aspect that must be discussed. It is about ACLs. A user which have interesting permissions over another user is always of interest to an attacker. (Side note: Make sure that you ACL auditing is a part of your security methodology - both for domain objects and other securables).

We can use Deploy-SlaveDeception to deploy decoy users where one of the users have FullControl/GenericAll rights over other user. This is interesting for an attacker and can be used to target both enumeration and lateral movement phase.

To target enumeration, following can be used:
The first and second command above, create users masteruser and slaveuser respectively and set auditing only when an obscure attribute is read. The third command provides masteruser GenericAll rights over slaveuser. Any adversary enumerating or scanning interesting ACLs in your domain will trigger 4662 for both the objects.

To target lateral movement, we can use PasswordInDescription option for masteruser or leave its credentials using other popular methods without any protection. We are ready to risk masteruser to be compromised and used (Please carefully consider risks before doing that). If masteruser modifies DACL of slaveuser we get a 4662 log in addition to any other alerts that are triggered whenever a honeytoken/honeyuser is used:
In the above command, a 4662 is logged only when masteruser changes DACL of slaveuser.

Enumeration - Domain and Forest Trust objects

Yet to be automated! There are many interesting possibilities though! For example, we can have a decoy forest trust (let's call it blue forest :P) where we can allow enumeration of users, computers and groups but deny access to any other resource. This can be achieved by setting up a forest trust with Selective Authentication where "Allowed to Authenticate" is set only on the DC but no other machine. This will allow an adversary to enumerate objects but they cannot access resources on other computers.

Red Team Revenge - Identifying Deception

So how do red teams identify which objects are actual and which are traps or decoys? As I mentioned in the beginning of the post, I have tested multiple Deception solutions over past months. There are multiple Enterprise solutions that use objects which can be identified by looking at their attributes. Some of such attributes:

  • objectSID - This object must always have DomainSID-RID format. Some enterprise solutions mess that up. If you find an object whose SID does not contain the domain SID. Make sure you investigate that object carefully.
  • lastLogon, lastlogontimestamp - User decoys can be identified by looking at these attributes. If there is a user that too high privileged one who has never logged on (lastLogon set to 31/12/1600 which is before the 'zero' date for LargeInteger datetime), there are good chances that it is a decoy. 
  • logonCount - Although not as good as lastLogon, logonCount is also a good indicator.
  • whenCreated - Coupled with lastLogon and logonCount, this becomes a good indicator. A user which is old but has never logged-on could be a decoy. You may like to notice that it may also be a dormant user, to be sure have a look at other attributes.
  • badPwdCount,badPasswordTime - Ever seen a human user who will not fat-finger their password? A user with 0 Badpwdcount (and other bad password attributes) is a good indicator of a decoy. 
  • Too many attributes - Some enterprise solutions fill up ALL or way too many possible attributes for an object. This can also be easily spotted. 
The best way is to match an object with a well known 'good' object. For example, if you suspect that a computer object in a list of all computers in the domain is a decoy compare it with the properties of the domain controller or attributes of your own foothold machine. The actual dc is always listed in the logonserver environment variable. For user object, the built-in DA always has RID 500. Compare its attributes with a user object you suspect of being decoy.

For multiple solutions which relied on not creating actual objects in the domain, using WMI to retrieve domain information shows correct objects and not the fake ones.

Red Team Revenge - Avoiding Deception

(Taken directly from my slides) Red Teams need to change their approach and their psychology of illusive superiority to avoid deception:
  • Please stop going for the lowest hanging fruit. Enterprise networks are mess but if something looks to good to be true, investigate carefully!
  • Avoid automated enumeration tools unless you absolutely know what they are doing in the background.
  • I have been urging this in my talks (on ATA) and trainings - Avoid the urge to go for the DA privileges so that you can brag about it in the reports! Focus on goals of your operation.

Blue Teams - Avoiding identification

If actual domain objects are used chances of identification are decreased. For example, a computer object which is not mapped to an actual computer has much higher chances of getting identified.

For user decoys, as discussed earlier, having at least one logon session decreases the chances of identification. Let's test this one out.

Let's have a look at a simple example. There is a well known deception identification script called HoneypotBuster. Let's create a decoy DA and run the script:

Our decoy DA was detected. Deploy-PrivilegedUserDeception has an option 'CreateLogon'. This parameter starts and stops calculator on the DC with the decoy DA user which populates the logon related properties of the user. To use this parameter, the LogonWorkstation protection must be set to the DC where the module is being executed. You can always change the behavior of the user later.
The above command creates decda, makes it a member of the Domain Admins group, restricts logon to the DC and creates a logon session (which also creates a profile on the DC). Now, if we run Honeypot Buster
Sweet, the FakeRank or confidence of the tool is down to 50. Honeypot buster uses a ranking system for objects and if a user has a logonCount less than 6 there would always be some confidence of it being fake. If we make the logonCount to 6 for decda by starting a process with its credentials 6 times, it would not show up in this tool.
Now if we run HoneypotBuster, decda is not detected! But that would be targeting this specific tool so let's not read much into this 'bypass'. 

Future Work and Community Involvement

It would be great if you deploy the decoys in your domain environments and share the results with me. That way, even if you cannot contribute to the code, you will immensely help the project.

OU objects are just around the corner and should not take much long to be included in the tool. I am also working on automating domain and forest trust decoys.I also have super ambitious plans of using virtualization to deploy decoys forests and computers in real time!

That is all! Thank you very much for reading this rather long post. You can find slides and video of my talk at BruCON below!