While the core concepts aren’t new, I believe the use of ADCS for domain computer takeover through Virtual Account abuse is previously undocumented/unexplored route to achieving your goals. I would like to start off by giving credit to my coworker, Michael(https://www.linkedin.com/in/michael-mcin/) for exploring today’s abuse paths but also for setting up a home environment to develop PoC for the blog.
Michael and I were both on a somewhat big internal penetration test (an assumed breach scenario) together and he had managed to get his hands on the credentials to the SA (System Administrator) account on one of the client’s MSSQL databases. Immediately the first thing checked for was the ability to execute commands and lo and behold, we could : ).
A major barrier came up and that was the fact that CrowdStrike Falcon was running. That complicated matters as we couldn’t just deploy something like GodPotato (which exploits SeImpersonatePrivilege to escalate to SYSTEM via token manipulation) to get from our virtual account having SeImpersonatePrivilege, to SYSTEM.
To get out of this, a light sneaky little thought came to my mind; if Virtual Accounts authenticate to remote domain resources as the Machine Identity, then could that be used to enroll in a Machine template, via ADCS on behalf of the machine the MSSQL instance was running on.
While we didn’t know for sure if we could just simply do this, we also had the second barrier of not knowing how to do this without certify due to CrowdStrike. An hour later after some deep diving into the Microsoft documentation, a method of using the certreq native binary (Windows’ built-in certificate request utility) with a certificate request manually filled out in an inf file was born that worked.
TLDR
When you achieve code execution in the context of a Microsoft Virtual/Service account, you can request a certificate for the computer you’re running on without needing any prerequisite permissions (other than the presence of ADCS). By exporting this certificate, you can use PKINIT to recover the NTLM hash of the machine account. With the NTLM hash in hand, we can use S4U2SELF to escalate privileges on the host via crafting a silver ticket.
The entire process can be accomplished using native PowerShell and default Microsoft binaries, requiring no extra tooling on the compromised host. This method requires no special privileges beyond those of the virtual account and works in any environment with ADCS, provided that a template exists with client authentication EKU and Domain Computer enrollment rights. It serves as a potential replacement for standard potato exploits, which are more easily detected and blocked by EDR/AV solutions. In environments without ADCS, the TGTDELEG trick can be used to extract the Machine TGT from the host. It also has the added benefit of getting you Domain Credentials without extra effort or headache of fully compromising a system if you do not need to.
What Are Virtual Accounts?
Virtual accounts are a feature in Windows that provide a dedicated user for services without the need of creating and managing a dedicated domain or local user account. They are “virtual” because their identity and authentication workflows are handled entirely by the local machine’s Security Account Manager (SAM). Common examples include the NT SYSTEM\ prefixes for Windows services like NT SYSTEM\Network Service or the IIS APPPOOL\ prefixes for IIS application pools, such as IIS APPPOOL\DefaultAppPool. A commonly abused trait of these accounts is that they by default have SeImpersonatePrivilege, allowing them to impersonate other users on the system.
Another feature of these accounts relevant to our abuse is that when a virtual account accesses domain resources, it uses the computer account (DOMAIN\COMPUTER$) credentials. This means that whenever you try to access an SMB share, or request a TGT, TGS or a certificate with a Virtual Account, you are doing these actions in the context of the host’s computer account.
Prerequisites
Before diving into the technique, you’ll need:
- Remote code execution as a virtual account
- ADCS available in the environment
- A template allowing enrollment for Domain Computers and a EKU useable for Client Authentication
- Network access to the Certificate Authority server and the Domain Controller/KDC
Where (Ab)Use of Virtual Accounts Starts
To simplify the PoC, we used PsExec to spawn a shell as the NT SYSTEM\Network Service account but you may use any virtual account of your choosing regardless of the authentication session you’re in. The original finding was done from us having achieved SA access to a database and using xp_cmdshell to execute commands as NT SYSTEM\NETWORK SERVICE.
First of all we need to create an inf file that defines the flags and information to pass to the CA when requesting the certificate:
$infContent = @"
[NewRequest]
Subject = "CN=$env:COMPUTERNAME"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = FALSE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.2 ; Client Authentication
"@
# Save the INF file
$infContent | Out-File -FilePath "C:\Windows\Tasks\cert.inf"
A few things to address on the format of our inf file; we are setting the subject to be the computer in which we are executing this on as we are assuming that you have compromised a virtual account and only have remote code execution on the target.
The other key thing is the setting of MachineKeySet to False as if it’s true then the private key would be determined to belong to the local computer account. While the key technically belongs to the computer account, setting this to FALSE allows us to export it without elevated privileges regardless.
Now that we’ve created the inf file, we’ll convert it into a certificate request file that we can submit to the CA:
certreq -new "C:\Windows\Tasks\cert.inf" "C:\Windows\Tasks\cert.req"
Having generated the certificate request file, we now need to submit it to the Certificate Authority. The -attrib parameter specifies which certificate template we’re requesting (in this case, the Machine template):
certreq -submit -config "CA-SERVER\CA-NAME" -attrib "CertificateTemplate:Machine" "C:\Windows\Tasks\cert.req" "C:\Windows\Tasks\cert.cer"
Note: This technique can be adapted for other scenarios, such as ESC1 abuse, by modifying the subject in the INF file or other abuse patterns.
With the issuing of the certificate, we will then need to convert its format and set a password to get the certificate in a pfx format that allows us to use it with PKINIT to get the NTLM hash of the machine account. Notice that we use the -user flag here to store the certificate in the user certificate store of the virtual account context we’re operating in, not because this is a user certificate:
$thumb = (certreq -accept -user -f "C:\Windows\Tasks\cert.cer" 2>&1 | Out-String | Select-String -Pattern '[0-9A-Fa-f]{40}' -AllMatches).Matches[0].Value; certutil -user -exportPFX -p "pass" $thumb "C:\Windows\Tasks\cert.pfx"

With the creation of the certificate in the pfx format, you have a variety of options to then move it from the target system to your system of choice to continue the abuse or using it on the host in question via tools such as PassTheCert.
With the pfx formatted certificate, we use certipy’s auth command which uses PKINIT to extract the NTLM hash of the TGT that is returned when we authenticate to the KDC with the certificate:

With the NTLM hash, we proceed to abusing the Kerberos extension S4U2SELF (Service for User to Self, which allows a service to obtain a service ticket to itself on behalf of any user) to impersonate the administrator to wscb02 and fully compromise it all from the Virtual Account and without running any payloads on the system:

No ADCS, No Problem: TGTDeleg
There is another important abuse path that’s similar but doesn’t require ADCS at all. Charlie Clark documented a way in which the tgtdeleg trick from Rubeus can be leveraged to extract the machine account’s TGT directly from memory when executed as a virtual account. This works because when a virtual account requests a TGT for delegation purposes, it does so in the context of the machine account. Much in the same way as above, equipped with the machine account’s TGT, you can then perform S4U2SELF to complete the takeover of the machine. More on that can be found here: https://exploit.ph/revisiting-delegate-2-thyself.html
Closing Thoughts and Next Steps
A little side note is that when the machine certificate is compromised; changing the machine account password, reformating/reimaging the computer and most other measures will not revoke the certificate generated so long as the hostname of the computer stays the same. In the case of compromise; you would need to revoke all issued certificates for the endpoint from the last known good date and backwards.
The important conclusion from this post is that potato exploits aren’t the only, and I’d argue not even the preferred method for escalating privileges on a system when running with a virtual account. Abusing ADCS via the machine account’s enrollment, or using the tgtdeleg trick with S4U2SELF are vastly superior methods of complete machine takeover without raising too many alarms or needing clean ups. They also have the added benefit of giving you valid domain credentials without the need to potentially trigger detections by additionally compromising an endpoint and dumping credential’s.
The next steps would be to continue to explore how many different scenarios could be abused that lead to one being able to generate a certificate and extract it as opposed to the standard abuse of vulnerabilities or credential leaking via NTLMV2 hashes.