Maintaining NTLM Authentication

Photo by Arget on Unsplash

I came across a web application that uses NTLMv2 for authentication. I logged in to the application (provided my credentials for the first time) and opened Chrome developer tool (F12) to check the requests. There was no session cookie or authorization header (Authorization: Negotiate or Authorization: Bearer) in the request. There was no other session-related information to prove that the user was logged in. I was surprised to see that the server still responded with content available only to authenticated users. I wondered how did the server know that I was logged in without any session-related data in the request.

No session cookie or authorization header (Authorization: Bearer) present in the request.

I captured the request in Burp Suite but the request was similar to that in Chrome. After googling for a while I talked to Manish who advised me to check what requests were going through Logger++ (Burp Suite extension) and Wireshark (packet capturing tool). Logger++ showed the same request as that in Chrome.

Next, I installed Wireshark and captured the request and finally I could see the NTLM handshake which was happening before every request (depends on few factors). As we can see Chrome performs NTLM handshake under the hood and those NTLM handshake requests are not shown in the Chrome developer tool. So it’s clearly difficult to make out anything about authentication just by observing the requests in the developer tool.

NTLM handshake captured in Wireshark.

One more thing to note here is that the browser does not ask for the credentials again and again. Once you have entered the credentials for the first time it will not ask for the credentials again until you close and reopen your browser. Browser kind of caches the credentials and uses them to perform NTLM handshake instead of asking the username and password again and again (clearly a very bad user experience).

A typical NTLM handshake looks like this.

1. Client sends a request to access a protected resource without any authentication information in the request. The server replies with 401 unauthorized status. It also includes WWW-Authenticate: NTLM header (defines the authentication method that should be used to gain access to a resource).

2. Client re-sends the same request along with Authorization: Negotiate header (Type1 message). The header contains the NTLM auth-scheme and other supported options. The server replies with 401 unauthorized status along with the random challenge string (Type2 message).

3. Client encrypts the challenge with the user’s password hash and sends it to the server in Authorization: Negotiate header (Type3 message). Server verifies the same and replies with protected resource if everything is fine.

Let’s take one more example.

No NTLM handshake after refreshing the page immediately.

When we try to access ‘sTable.xsl’ for the first time NTLM handshake takes place(Observe 1, 2, 3) but refreshing the page immediately does not cause any NTLM handshake again (observe 4).

Reasons as per my understanding

1. When the NTLM handshake is over(Observe 3) the server sends a header Persistent-Auth: true in the response.

“If the server successfully authenticates the request, it MAY indicate whether the Authorization header will be required for the next request on the connection. This is part of performance optimization and does not guarantee that an Authorization header will or will not be required.”
windows protocol

Obviously, this is valid only for few seconds let’s say 10 seconds. If we send any request within 10 seconds no NTLM handshake will take place. After 10 seconds there will be an NTLM handshake again before granting access to protected resource.

2. The connection is already authenticated and kept open for a specified number of seconds. Any request sent over this authenticated connection (within the time this connection is open) does not need an NTLM handshake again.

Multilegged authentication requires the state to be communicated between multiple streams. Network flows 3 and 4 in Figure 1 need to share state for authentication to succeed. Some multilegged authentication schemes (i.e. Kerberos and Negotiate) can authenticate either a connection or individual requests, which has historically caused a lot if issues with multilegged authentication in HTTP 1.1.

(Multi-legged authentication)

For the sake of simplicity, I’ve not included a lot of technicalities involved in NTLM authentication. Please check references for more details.

Thank you for reading!