A study on Windows HTTP authentication (Part II)
This is the follow-up article to Dissecting NTLM EPA with love & building a MitM proxy. If you do not have basic understanding of HTTP authentication, NTLM EPA and HTTP proxifying with TLS interception, we recommend that you take a look at the previous article.
In this article will be discussed:
- NTLM service binding, the other part of NTLM EPA (Extented Protection for Authentication).
- Kerberos reminders (in a few words) and Kerberos over HTTP, is Kerberos really more secure than NTLM EPA?
- The new features of Prox-Ez (the Swiss Army Knife of HTTP authentication):
- A description of their implementation.
- Different usage examples.
NTLM EPA service binding
For details about NTLM, please visit the previous article.
Previously was discussed the Channel Bindings protection added by EPA, however, this protection is inherently linked with TLS and therefore does not protect the good old plain HTTP. Thankfully, Microsoft developed another solution shipped with NTLM EPA called Service Binding. It was only natural that we started digging into it.
This feature adds an SPN (Service Principal Name) into the NTLM authentication's last message:
This attribute is included in the attributes list (AV_PAIRS) of the NTLMv2 response message, it is therefore protected by the MIC value and cannot be tempered with. Upon reception, the web server will check if the provided SPN is allowed. If so, and if the authentication is valid, the web page will be returned.
The value of this attribute is determined by the browser, and corresponds to the value in the address bar (ie. reaching a domain joined server with a custom DNS record will make the browser send said record as part of the SPN).
During our research, we discovered that this feature was quite hidden and not widely used. In fact, there is no graphic option in IIS (Internet Information Services) to configure it. To do so, one has to start by enforcing the Extended Protection in Authentication menu > Windows Authentication > Advanced Settings as such:
Once this is done, the websites configuration file has to be modified, as stated in the Microsoft documentation. It is commonly located in C:\Windows\System32\inetsrv\Config:
We will now take a look at the configuration snippet that affects the website we are working on:
<location path="Default Web Site"> <system.webServer> <security> <authentication> <windowsAuthentication enabled="true" useKernelMode="false"> <providers> <clear /> <add value="NTLM" /> </providers> <extendedProtection tokenChecking="Require" flags="Proxy,ProxyCohosting"> <spn name="HTTP/win2019srv01.ff.dom" /> </extendedProtection> </windowsAuthentication> <anonymousAuthentication enabled="false" /> </authentication> </security> </system.webServer> </location>
The flags attribute of the extendedProtection tag holds the behavior of EPA. In default EPA configuration, this attribute does not exist, you have to add it manually. As explained in the documentation, when the attribute does not exist or when the None value is used (alone), the default behavior of NTLM EPA is enforced.
Funny thing is, when the default NTLM EPA configuration is used, the Service Binding is not enforced. This basically means that if you require NTLM EPA and you leave the unencrypted HTTP version of the application available, the latter is still vulnerable to KB5005413: Mitigating NTLM Relay Attacks on Active Directory Certificate Services (AD CS)) in web.config does not impact service binding).... (The additional code snippet Microsoft recommends to add (from
Other than that, what we deduced from our tests is the following table summarizing the configuration options and the behaviors of IIS:
|Empty / None||Only verify CBT||HTTP is not protected ; HTTPs is protected|
|Proxy||Only verify SPN||HTTP is not working (no authentication possible) ; HTTPs is protected|
|Proxy,ProxyCohosting||Only verify SPN||Both HTTP and HTTPs are protected and work|
|Proxy,NoServiceNameCheck||Does not verify anything||HTTP is not working (no authentication possible) ; HTTPs is not protected but a SPN has to be provided (any value)|
|Proxy,ProxyCohosting,NoServiceNameCheck||Does not verify anything||Both HTTP and HTTPs are not protected (no SPN required)|
CBT: Channel Bindings Token (NTLM EPA -- channel bindings)
SPN: Service Principal Name (NTLM EPA -- service binding)
The Kerberos authentication is also affected by these parameters. In fact, when SPN checking is enabled, the Kerberos authentication will only succeed when the target SPN of the AP_REQ message corresponds to one in the configured list.
Finally, there is an option called AllowDotlessSpn which allows specifying short names (NETBIOS names) in SPNs. If this option is not specified, and short names are used in the allowed SPNs definition, the server will fail handling requests and always return 401 errors.
Indeed, when the configuration is broken, the server will simply return 401 errors, without any WWW-Authenticate header...
Kerberos over HTTP
Microsoft in its knowledge base (KB5005413) recommends enabling EPA on AD CS servers as a primary mitigation against Petit Potam. In addition, they recommend disabling NTLM authentication when possible and replacing it by Kerberos Authentication since it is supposed to use mutual authentication. That is why we decided to have a look at Kerberos over HTTP and implement it in our Proxy.
First of all, we need to do a quick recap about Kerberos. Kerberos is an authentication protocol used in Active Directory environment.
The first exchanges are between the client and the KDC:
- AS_REQ, allows the client to ask for a TGT (Ticket Granting Ticket), if PreAuthentication is enabled, the AS_REQ contains a timestamp encrypted with the client's secret key.
- AS_REP, contains the TGT that will allow the client to ask for a specific ST (Service Ticket).
- TGS_REQ, similar to an AS_REQ, allows the client to ask for a specific ST (Service Ticket). The ST is bound to an SPN that uses following format: service/server (ex: http/server.domain.com). This request is authenticated using the TGT.
- TGS_REP, similar to an AS_REP, contains the ST as well as the associated Session Key.
After that, the client communicates directly with the service. These exchanges allow mutual authentication between the client and the service:
- AP_REQ: allows the client to authenticate to the server by sending the ST to the server and by proving it knows the associated Session Key.
- AP_REP: allows the server to authenticate to the client by proving it knows the Session Key encrypted in the ST using its own key.
It has to be noted that Windows stores the MD5 hash of each AP_REQ it receives. Since the seq-number is different for each AP_REQ and is encrypted with the session key, it is not possible for an attacker to do AP_REQ replay.
Let's see how a Kerberos over HTTP authentication works with an example.
(1) First, the client sends an HTTP request to the server. As the content is protected by authentication, the web server responds with a 401 error page (2), including the WWW-Authenticate: Negotiate. This header means that an authentication is required and that the client will have to choose its authentication protocol, usually between Kerberos and NTLM. If NTLM has been disabled, the authentication would fail.
On a Linux client, Google Chrome and Firefox do not know how to handle the WWW-Authenticate: Negotiate header. This is where, for example, Prox-ez can be useful.
On a Windows client, Google Chrome will try to perform Kerberos authentication if the web page was requested using a domain name, and NTLM if the web page was requested using an IP Address. Surprisingly enough, the Kerberos authentication will take place even if the client's Windows workstation is not part of a domain. First of all, (3) Google Chrome will perform a standard AS-REQ without pre-authentication.
(4) If the KDC requires pre-authentication for this account it will send the corresponding error, leading to (5) Google Chrome sending a AS-REQ with pre-authentication.
(6) The KDC responds with a AS-REP containing the TGT.
(7) Google Chrome will then perform a standard TGS-REQ for the http/webservice Service Principal.
(8) The KDC responds with a TGS-REP containing the ST.
And this is where it gets specific to HTTP. (9) Google Chrome will request the web page again but adding an Authorization header containing an SPNEGO negTokenInit token (https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SPNG/%5bMS-SPNG%5d.pdf) that in turn contains the actual AP_REQ (built from the ST previously obtained). The AP_REQ contains an encrypted part proving that the client knows the Session Key. In this case the AP_REQ requires the server to authenticate too.
(10) The web server will send the web page to the client including an SPNEGO negoTokenTarg token containing the actual AP_REP and an encrypted part proving that the server was able to use the Session Key. If the authentication process did not go through, the server will just send a 401 error again.
Finally, once the exchange is properly completed and as long as the TCP connection is kept alive, the client can browse the website as an authenticated user.
Some web servers will set an authentication cookie on the client browser in order to prevent the Kerberos authentication from running each time the TCP connection is dropped. Otherwise, the whole process would have to be performed to authenticate the client yet again.
A security overview of Kerberos over HTTP
As already discussed, Microsoft implemented two security measures in order to prevent attackers from performing Replay attacks on the AP_REQ:
- The encrypted part of the AP_REQ contains a timestamp, so the server will refuse the AP_REQ if it is more than 5 minutes old.
- The host will compute an MD5 hash of each AP_REQ authentication message. If it receives the same AP_REQ more than once, the host will refuse it with a KRB_AP_ERR_REPEAT error.
Moreover, the encrypted part of each AP_REQ contains the SPN of the specific service. Nevertheless, the Windows hosts do not check the SPN and only verify if the service account is able to decrypt the AP_REQ.
It means that if a server is running more than one service with the same identity (let's say the machine account for example), an attacker could try to perform a replay attack. In this case, the host will detect that the AP_REQ has already been sent to another service. However if the attacker is using some kind of proxy, he could relay (and not replay) the AP_REQ on another service (for example from HTTP to SMB):
Furthermore, an attacker could also take advantage of that behavior to perform a replay attack on another host using the same service account (as it is often the case with SQL servers) since the two hosts do not share the list of MD5 hashes of used AP_REQs.
It is nonetheless possible to specify and enforce a strict SPN in IIS web server by modifying the C:\Windows\System32\inetsrv\Config\ApplicationHost file as it is the case for NTLM EPA Service Binding (see above).
Prox-Ez features (and what's new)
Lots of improvements were made since the creation of Prox-Ez. If you want an overview of Prox-Ez's internals, a high level description was given in the previous article.
Since last year, Burp also implemented NTLM EPA authentication. Nevertheless, it still does not support the WWW-Authenticate: Negotiate header, pass-the-hash, pass-the-ticket and so on. They all lead to authentication errors.
We decided to add to our proxy the support of all the HTTP Authentications that you could find on a Windows based infrastructure including:
- Standard NTLM authentication
- NTLM EPA channel binding
- NTLM EPA service binding
- Pass-the-hash capabilities (from LM or NT hashes)
- Kerberos authentication
- Standard user/password capabilities
- Pass-the-ticket capabilities (from TGT or ST)
- Overpass-the-hash capabilities (from the NT hash)
The objective is also to give a simple script to work with HTTP authentication. It is based on a single file, with minimal dependencies. Feel free to tweak, patch and modify it so that it matches your needs, PRs are welcome.
Below is a list of the other nice features that you may find useful:
- Dump of SSL/TLS keys to easily analyze traffic.
- Option to disable NTLM EPA extension.
- Option to force specific SPN.
- Nice debug output.
Here are a few examples, to provide a quick preview of the potential of Prox-Ez.
- Connect to a website using pass-the-hash (to check for ADCS templates using the NT hash of a user for instance).
You have found the perfect hash, but cannot use it to authenticate on websites. Prox-Ez can do that for you, whether the website supports NTLM or Kerberos.
Take a look at the GIF below for an example:
- Connect to a website using an existing TGT.
You already have a TGT and want to use it with Firefox to connect to a website.
The following GIF shows how to do so with Prox-Ez (with the -d debug mode):
- You want to use a tool that does not support Kerberos authentication when you need it.
For instance, during an assessment, we once needed to use certipy against an ADCS instance requiring Kerberos authentication. By using Prox-Ez, we were able to completely hide the HTTP authentication from certipy and perform it in its place. That way, we could specify the correct SPN and correctly authenticate using an existing TGT.
This process in shown in the following GIF: