Background
Are you tired of working from home due to COVID? While this is quite a unique situation we find ourselves in, it also provides some fresh opportunities. Lately we have assessed several environments that was meant to provide a secure way for working from home. For one specific engagement, a client delivered one of their laptops that was domain joined. The laptop was accompanied with credentials of a low privilege domain user. The secure connection to their office was provided using DirectAccess.
In this post I will describe some challenges we faced while attacking the client infrastructure that ultimately lead to us contributing IPv6 support to Rubeus.
Rough start
Usually we can quickly escalate to local administrator. However, this time it was different. The BIOS was password protected, various security features were enabled and disk encryption was in place. Several attempts were made to escalate privileges while logged in as a domain user but all of them failed miserably.
Well, if things don’t work out locally, we could always target the domain environment. A potential goldmine in Active Directory environments are Group Policies. While not that popular anymore, Group Policies could be configured with an encrypted password (CPASSWORD). This, for example, could be used to automatically deploy a local admin user. We searched for this and within seconds got a hit! One of the policies contained a ‘CPASSWORD’ value. Because the decryption method is known, it was possible to view the content of CPASSWORD in plain text.
After decrypting the password, a simple check showed that the user did not exist anymore. At best the password could have been reused for other accounts, but sadly this was a dead end too.
Let’s dig deeper!
At this point we needed more insight into the Active Directory structure. There are multiple ways to do this, we choose to use BloodHound. To collect the necessary information, we ran the BloodHound ingestor, SharpHound. BloodHound is able to use graph theory to reveal hidden and often unintended relationships within an Active Directory environment. Going for a quick win, we searched for the shortest path to Domain Admin. Sadly none of the paths starting with the user that was provided by the client had a path to a high value target.
Crawling desperately through the BloodHound results, one word stood out: GenericAll. It turned out that our domain user had ‘GenericAll’ rights to what I am going to call ‘system_x’.
This primitive typically allows for an attack called ‘Kerberos Resource-based Constrained Delegation’. You can find more information about this attack on a blog post of Will Schreuder (@harmj0y).
A high level overview of the attack flow is:
• We have low privileged domain user;
• This user has ‘GenericAll’ privilege over a target computer ‘System_X’;
• User creates a new computer object ‘ocd’ in Active Directory (by default authenticated users are able to add 10 machine accounts to the domain);
• User leverages WRITE privilege on the ‘System_X’ computer object and updates the computer object’s ‘msDS-AllowedToActOnBehalfOfOtherIdentity’ attribute;
• ‘System_X’ now trusts ‘ocd’ as a result of the modified msDS-AllowedToActOnBehalfOfOtherIdentity attribute;
• We request Kerberos tickets for ocd$ with the ability to impersonate a Domain Administrator.
I had not used this attack before, and time was running out. At this point we were glad that the (offensive) security community is quite awesome! Will Schreuder published a demo and the necessary scripts for the attack on Github. We downloaded the rbcd_demo.ps1 PowerShell script and after reviewing the source code (you never know) we updated it to reflect our target environment and ran it with our current low privileged user.
The following shows a part of the result of running the script.
PS C:\tmp>. .\powerview.ps1
PS C:\tmp>. .\powermad.ps1
PS C:\tmp>. .\rbcd_demo.ps1
[+] Machine account ocd added
BinaryLength : 36
AceQualifier : AccessAllowed
IsCallback : False
OpaqueLength : 0
AccessMask : 983551
SecurityIdentifier : S-1-5-21-9881537<<snip>>90004242-202897
AceType : AccessAllowed
AceFlags : None
IsInherited : False
InheritenceFlags : None
PropagationFlags : None
AuditFlags : None
At this stage I was jumping in the air and making western gun pistol signs as I noticed that a machine account was created as specified in the script. However, our stroke of luck was quickly over… To impersonate a user on our target machine and request a Kerberos ticket, the script calls Rubeus.exe that sadly threw the following error:
“[X] Error resolving hostname to an IP address: no IPv4 address found”
This issue bugged me, and after staring at the error message for quite some time, the words IPv4 lit up (in my mind anyways). I was communicating with the target network using Microsoft DirectAccess, and DirectAccess uses IPv6. To verify this I pinged the domain controller which was indeed responding on IPv6, not IPv4. This unfortunately meant that Rubeus did not support IPv6. Lucky for me I noticed this on a Friday so my colleague, Roy Reinders (@royrndrs), implement IPv6 support in Rubeus over a weekend. This meant I still had Monday to finish the attack and the assessment.
All excited for a Monday (probably for the first time ever) we tried the new build of Rubeus. The PowerShell script ran, a machine account was created, the password hash of the newly created machine was retrieved and…
[*] Impersonating user '_adminx' to target SPN 'cifs/system_x'
[*] Using domain controller: dc01.ka.ocdtest (fe81:418a:c778:7777::ac38-4648)
[*] Building S4U2proxy request for service: 'cifs/system_x'
[*] Sending S4U2proxy request
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/system_x':
doIKzjCC[...SNIP...]fGwRjaWZzGxdwa3ZtbTAwMDMua2EucHJvcmFpbC5ubA==
[+] Ticket successfully imported!
A Kerberos ticket is retrieved for the impersonated user!
Just to be sure we verified with klist tickets
to check if the ticket was really cached.
PS C:\WINDOWS> klist tickets
Current LoginID is 0:0x890c8
Cached Tickets: (1)
#0 Client: _adminx @ KA.ocdtest
Server: cifs/system_x @ KA.ocdtest
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 5/14/2020 12:01:22 (local)
End Time: 5/14/2020 12:01:22 (local)
Renew Time: 5/21/2020 12:01:22 (local)
Session Key Type: AES-128-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called
The IPv6 implementation worked! At this point you would want to verify if you can use the ticket. Since we impersonated a Domain Administrator account, the following command could be used for verification:
dir \\system_x\C$
But, we got no response… drat! Again, I was confronted with the fact that we were in a DirectAccess environment. As you can see in the ticket above, access is granted for ‘cifs/system_x’. We should access the target resource with it’s IPv6 address. But to access a UNC path on an IPv6 address, a special ‘hostname’ naming convention must be used. This meant that the attack had to be executed again, but this time using it’s IPv6 ‘hostname’ instead of the regular hostname.
When writing down the IPv6 address ‘hostname’, all of the ‘:’ characters should be replaced by a ‘-‘. The end should contain ‘.ipv6-literal.net’. You can find a fictional example below:
fd00-517a-c816-8888—ac01-2135.ipv6-literal.net.
After firing off the script and grabbing a cup of coffee I noticed the following error:
"0x7 – KDC_ERR_S_PRINCIPAL_UNKNOWN”
Researching this error, I learned that Kerberos does support IPv6 Service Principal Names, however this is not enabled by default.
The end
Although it was not possible to fully exploit the misconfiguration, it was a fantastic opportunity to dive into DACL’s, Rubeus and DirectAccess all while contributing some IPv6 support to Rubeus.
The following lessons were learned:
• Drop any assessment where the infrastructure makes use of IPv6. Ok, this is a joke, but it seems that the pentesting world is not completely ready for this;
• No matter how insignificant the ACE-rights may seem to be, it could be important! (cough, GenericWrite, cough);
• Keep searching, keep trying and ask for help!
Mitigation
• Implement the ‘principle of least privilege’ in Active Directory;
• Audit ACL change logs;
• Regular automated or manual auditing of existing ACL’s.
References
https://www.harmj0y.net/blog/activedirectory/a-case-study-in-wagging-the-dog-computer-takeover