Why doesn't delegation work over the network?

One question that keeps on coming up when you’re writing a server in NT is: “Why can’t I access remote resources from my server when impersonating my client?” It shows up on our internal aliases about once a month in one form or another. 

This situation is also known as “delegation.”

There are actually two different answers to the question.

The first answer applies if you’re not running with the active directory; the other applies if you’re using AD.

If you’re not using the active directory, then your clients are typically authenticated via the NTLM or DIGEST authentication mechanism. Both of these mechanisms work in similar fashions: When the user logs into the client machine, the machine logging the user on computes a one-way hash of the user’s credentials.

When the client connects to the server, the server computes a “challenge”, which is tailored to the client, and sends the challenge to the client. The client then encrypts the challenge using the one-way hash as a key, and sends the encrypted challenge to the server. The server, in turn hands the challenge and the encrypted result to the domain controller to validate that the challenge and the response could only have been generated by the user (if the user’s a local user, it uses the local security authority (LSA)). Note that the server doesn’t ever see the user’s password OR the hash of the users password. The server just knows the challenge and the response to the challenge, neither of which contains the user’s password.

When the domain controller responds to the client, it includes enough information to allow the local machine to create the token for the user. So far so good.

Now let’s consider what happens when the server tries to access a remote resource, say a file on another machine. The server impersonates the user, and attempts to open the file. The remote machine sees the new connection, computes the challenge, and sends it to the client. Now the server needs to encrypt the challenge with the hash of the user’s password. But the server doesn’t KNOW the hash of the user’s password. It was never told that information. The domain controller does, and so does the client, but the server doesn’t. All the server could know is the challenge and the encrypted challenge. And thus, since the server has no way of responding to the challenge, the delegation fails.

 

Now for the other case, when you use Kerberos, if the client authenticated with the server using the Kerberos authentication package (which requires the active directory), then the picture’s a bit brighter. It turns out that one of the design criteria of Kerberos was supporting delegation. In Kerberos authentication, the domain controller gives the server a “ticket” that identifies the client. The cool thing about the ticket is that it can be handed to a remote machine, which can then validate the ticket against the domain controller. So if you’re using the active directory, then it’s POSSIBLE for the client to be authenticated with the remote machine.

But, as always, there’s a catch. NT wants to limit the number of services that can do delegation, since it’s conceivable that such a service could be used to mount an attack (since a ticket can be saved and re-used for several hours after it’s been granted, a service that can do delegation can act as if it was the client user for several hours beyond when the user actually connected). So you need to mark the service account for your service (or the machine account if the service’s running as LOCALSYSTEM, LOCALSERVICE, NETWORKSERVICE, or if you’re using a named pipe). This KB article shows how to do this in Win2K, the same techniques work for Win2K3. 

 

Btw, see my post on Security Terms for clarification on any vocabulary that’s confusing J.