In May 2022 Microsoft has fixed a vulnerability related to certificate logon to Active Directory. As a non-privileged user you could escalate privileges by impersonating a Domain Controller, as you can join machines to the domain and thus control the dnsHostName attribute.
Microsoft fixed this in an indirect way: Since last May, Windows Certification Authority Servers (ADCSs) are embedding a new certificate extension that contains the Security Identifier (SID, AD attribute objectSID) if the certificate template is configured for subject names coming from the certificate request. Until November 2023, logon with certificates without the new extension will still work: Only a KDC warning is logged at the Domain Controller. Microsoft has extended this deadline. Originally they announced they would turn on Full Enforcement in May 2023. In November 2023, smartcard logon, 802.1x using Windows NPS, logon of mapped certificates to IIS, etc. will stop working if certificates without the SID extension are used – thus certificates that had been issued before the May 2022 updates had been installed on the CA.
In this post, I am presenting a quick Proof of Concept: How to add the new extension manually IF THE TEMPLATE ALLOWS CUSTOM SUBJECT NAMES. It’s important to emphasize that this is not a new vulnerability. It is a feature actually mentioned explicitly in the Microsoft protocol specification! And it is – to my knowledge – currently the only way you would be able create “out-of-band” logon certificates that will keep working after November 2023. There is currently no automated solution for certificates with custom names that are – for example – issued via SCEP/NDES, via the enrollment web app /certsrv or command line tools[*]. For example, smartcards might be issued manually to a small number of “external” VPN users, or a mobile device management (MDM) system might read AD attributes and then populate the “custom” name sent in a request using SCEP. Maybe, MDM vendors are working on it – just guessing.
[*] Edit on April 1, 2023: Actually there is! This month PKI Solutions have released a policy module that will embed SIDs into NDES-issues certificates, and it will allow to define rules for dealing with potentially forged SIDs!
Edit 2, on April 15, 2023: How could I have missed this Nov. 2022 post by the authors of the Certified Pre-Owned research paper? They have described the option to add a SID manually, and link to this post by Carl Sörqvist with details about how to inject the SID manually. … in a PoC more polished that what my post here is about.
The purpose of this post is twofold:
- Remind everybody that the new extension does not make your typical manually enrolled “web server templates” (that allow custom names) much more secure. In the old days, you just had to add only a UPN to your certificate request to impersonate an enterprise administrator. Now you have to add a UPN and the corresponding SID. Of course, if you only have access to the
/certsrv
enrollment application, you would not be able to find an administrator’s SID, but you may guess the User Principal Name. But in order to logon to Active Directory you would need to have access to much more of the DCs’ ports anyway. - Provide a workaround if you have a bunch of manually issued logon certificates that should keep working after November 2023. I guess, the reason that Microsoft left open the option to add the SID yourself is to allow Mobile Device Management systems and the like to update their solutions respectively. Edit: Again, I want to link to the new open source policy module that can help with that!
This is a super rough PoC – it needs to be turned into a tool / script / solution that takes care of the proper ASN.1 encoding.
Encoding of the SID in the certificate extension
Most tools show the SID of a user as string starting with S-
. But the attribute objectSID
is actually stored as a series of bytes that does not correspond to character S character dash etc. This article explains the encoding in depth.
here is the Administrator’s SID, displayed in adsiedit.msc – nice string versus hexadecimal representation of bytes:
In an auto-enrolled logon certificate issued to the Administrator (based on the name in AD) , the SID is embedded like this:
Looking closer with certutil -asn [certfile].cer
shows the ASN.1-encoded string. The actual SID string starts at 53 2d 31
, S-1
, and the bytes included in the certificate extension start at 30 3d a0
– thus at the inner structure of the octet string.
0449: | 30 4c ; SEQUENCE (4c Bytes) 044b: | 06 09 ; OBJECT_ID (9 Bytes) 044d: | | 2b 06 01 04 01 82 37 19 02 | | ; 1.3.6.1.4.1.311.25.2 0456: | 04 3f ; OCTET_STRING (3f Bytes) 0458: | 30 3d ; SEQUENCE (3d Bytes) 045a: | a0 3b ; OPTIONAL[0] (3b Bytes) 045c: | 06 0a ; OBJECT_ID (a Bytes) 045e: | | 2b 06 01 04 01 82 37 19 02 01 | | ; 1.3.6.1.4.1.311.25.2.1 0468: | a0 2d ; OPTIONAL[0] (2d Bytes) 046a: | 04 2b ; OCTET_STRING (2b Bytes) 046c: | 53 2d 31 2d 35 2d 32 31 2d 31 34 36 38 30 31 32 ; S-1-5-21-1468012 047c: | 37 35 35 2d 38 30 30 35 36 31 33 31 37 2d 34 35 ; 755-800561317-45 048c: | 37 34 37 33 30 39 39 2d 35 30 30 ; 7473099-500
It interesting that this corresponds to the string starting with S-1
and not to the sequence of the “true” bytes! Maybe this choice was made to keep the SID value readable in tools that display certificates.
Are we allowed to add the SID? Is this a “hack”?
No, totally legit and described “officially” by Microsoft here, the specification of the CA behavior:
szOID_NTDS_CA_SECURITY_EXT
OID = 1.3.6.1.4.1.311.25.2.…
Description: Contains objectSid of the Active Directory object whose information is being used to construct the subject information of an issued certificate. The CA MUST consider this extension from request attributes only when the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT flag is set on the corresponding certificate template object.
When a certificate template is configured for subject names coming from the request (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
), then the CA treats the SID like a “name” – like a custom Common Name, UPN, e-mail … address.
Enrolling for a certificate with custom name
As I said, this is a rough PoC: I am just taking the ASN.1 encoded bytes from a legit Administrator certificate to create a request with a custom attribute with certmgr.msc, from a template that allows for custom names. Using some ASN.1 library / tool one needs to take the “string SID” starting with letter S and properly encode it.
The OID of the custom extension, as visible in any certificate with AD-based names, or from the Microsoft spec:
1.3.6.1.4.1.311.25.2
The relevant bytes in hex, in this PoC just copied from the ASN view of a legit Administrator cert:
303DA03B060A2B060104018237190201A02D042B532D312D352D32312D313436383031323735352D3830303536313331372D3435373437333039392D353030
I am starting certmgr.msc as a user who is not the administrator. Adding custom names: the User principal name
of the Administrator and throwing in a second, non-existing UPN for fun. Using a different Common Name to illustrate that the CN is not important when logging on to AD.
(Now you also know what the title of the post refers to.)
… and I am adding the OID and bytes of the SID as a custom extension:
The certificate is issued fine – both the names and the SID show up as expected. Comparing with the screenshot of the legit Administrator’s certificate above shows that the SID is embedded correctly.
Both UPNs have been added to the Subject Alternative Name
extension:
Here is the SID:
Testing Logon
I am using IIS and certificate mapping (as usual) – see the 2014 post for details on how to configure IIS for that. The “web app” consists of a single default.htm page. I don’t bother to create ASP(X) code to display the logged on user (as I did here for example), but I will simply check IIS logs after the logon. If certificate mapping works, the user name is displayed in the format DOMAIN\username
. Note that requiring a client certificate is not the same as certificate mapping – it is required but not sufficient. If you do not activate mapping, the user name will not show up in the logs even if the TLS handshake and validation of the client certificate is fine (which you can check e.g. via CAPI2 logs in Windows).
I am interactively logging on as another user who is not a domain administrator (but who has given logon rights to a DC to allow for a one-box test lab), and access my “webapp”. I have several certificates in the store, so I will always see a popup with a selection of certificates.
The samAccountName
of that user is webadmin
. If webadmin
selects a certificate created from a template configured of pulling names from AD, they are logged on as webadmin
, as per IIS logs. HTTP 403.7
indicates that a client certificate is required:
2023-03-30 12:56:37 ::1 GET /webapp - 443 - ::1 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+Trident/7.0;+rv:11.0)+like+Gecko - 403 7 64 0 2023-03-30 12:56:41 ::1 GET /webapp - 443 PANIC\webadmin ::1 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+Trident/7.0;+rv:11.0)+like+Gecko - 301 0 0 27 2023-03-30 12:56:41 ::1 GET /webapp/ - 443 PANIC\webadmin ::1 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+Trident/7.0;+rv:11.0)+like+Gecko - 200 0 0 4
Now I am selecting the certificate forged before, the one with funny names, the Administrator’s UPN, and his SID:
It works, my “web app” (= default.htm text files with string test :-) ) is displayed and the log file shows the correct mapping:
2023-03-30 13:14:29 ::1 GET /webapp/ - 443 - ::1 Mozilla/4.0+(compatible;+MSIE+7.0;+Windows+NT+10.0;+WOW64;+Trident/7.0;+.NET4.0C;+.NET4.0E) - 403 7 64 5
2023-03-30 13:15:02 ::1 GET /webapp/ - 443 PANIC\Administrator ::1 Mozilla/4.0+(compatible;+MSIE+7.0;+Windows+NT+10.0;+WOW64;+Trident/7.0;+.NET4.0C;+.NET4.0E) - 200 0 0 55
The system log does NOT show warning message about weak mapping (see the last post for examples). So, using such certificates, I should be prepared for Full Enforcement mode in November 2023.
Turning on Full Enforcement Mode
Preparing for November 2023, I want to test Full Enforcement mode. I am adding the registry key as described in the Microsoft article:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kdc
StrongCertificateBindingEnforcement
…
2 – Checks if there’s a strong certificate mapping. If yes, authentication is allowed. Otherwise, the KDC will check if the certificate has the new SID extension and validate it. If this extension is not present, authentication is denied.
Aaaaand … the forged certificate with SID – issued to Lord of the SID / administrator@pan.ic does still work! \o/
Final cross-check, to see if enforcement would kick in as expected: I am enrolling for another manual “offline” certificate, from the template that allows for custom names. This time, I am only adding the UPN of administor@pan.ic
, but not a custom extension including the SID.
As expected, logon is now denied with an unauthorized error. – 403.7
is followed by 401.2
. In the system event log, the following KDC error is logged.
The Key Distribution Center (KDC) encountered a user certificate that was valid but could not be mapped to a user in a secure way (such as via explicit mapping, key trust mapping, or a SID). Such certificates should either be replaced or mapped directly to the user via explicit mapping. See https://go.microsoft.com/fwlink/?linkid=2189925 to learn more.
User: Administrator
Certificate Subject: @@@CN=User without SID
Certificate Issuer: Panic CA
Certificate Serial Number: 4B000000352151D883E5F5905F000000000035
Certificate Thumbprint: 90D986B29146DF8B778858E40A99B198CC483461
Cross-checking the serial number – and the weird subject name :-) – I confirm that is related to the logon attempt made as webadmin, using the certificate without SID extension.
~~~
Further reading:
Certified Pre-Owned article and white paper by Will Schroeder and Lee Christensen, comprehensive description of ADCS related security issues / misconfigurations. I think this was the first time that really all risks related the Microsoft PKI have been described in one paper, in such a structured way, and and that level of detail.
Certificates and Pwnage and Patches, Oh My! a detailed update by by Will Schroeder and Lee Christensen, also covering the changes introduced by the May 2022 patch in their implications. (Added two weeks after publishing this post).
Super detailed blog post by researcher Oliver Lyak who discovered the bug(s) that MS fixed in May 2022. This post was released with a version of the offensive tool Certipy based on the Certified Pre-Owned research, plus further attacks (e.g. related to full control permissions on a non-privileged user, so that you can modify the user’s userPrincipalName attribute.)
The impressive 2022 research paper by Oliver Lyak – this CVE made Microsoft make changes to certificate logon: Certifried: Active Directory Domain Privilege Escalation (CVE-2022–26923).
Microsoft’s fix: KB5014754—Certificate-based authentication changes on Windows domain controllers.
After the May 2022 updates have been published, I have written these related posts:
All that research strongly suggested you finally turn off the flag that allows for “injecting” a SAN into the CA’s pending queue, together with the request (using the SAN:upn=
syntax). Though cumbersome, you can achieve the same with crafting a custom request and “injecting” extensions with certutil … and ASN1 encoded arguments: How to Add a Subject Alternative Name Safely
But actually, that flag became much less of a risk. Even before Full Enforcement is turned on, an explicit mismatch between UPN and SID will prevent the “certificate hacker” from logging on: Defused That SAN Flag!
I published my first “offensive security” related article about abuse of misconfigured certificate templates in 2019 – spotting a template issue on a vulnerable machine on hackthebox (which was not the intended way to solve the machine). At that time, ADCS was not on the radar of security researchers yet. I used tools built into Windows and a hardware crypto token to own the box. In 2020, I repeated the attack but created a PoC using Linux and its native Kerberos tools. I am still honored that these two articles have been quoted as prior work in the Certificate Pre-Owned white paper. My very first article about the dangers of UPNs in certificate was this (2014) – only hinting at the dangers in a cautious way as I was not familiar yet with offensive security culture :-)
But now, I guess, I finally need a new research project!
~~~
You could use
https://github.com/Sleepw4lker/PSCertificateEnrollment
instead of doint it manually
Thanks a lot! Yeah – I haven’t checked all the offensive tools! I might focus too much on trying to use the built-in tools (if any). Still using the classic MS white paper on “advanced certificate requests” as my resource for requests that require ASN.1 encoding https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc782583(v=ws.10) :-)
… and noticing now that this is not an “offensive” tool :-) … Thanks again!