How Authentication Works when you use Remote Desktop
A couple weeks ago I created a thread about logging into Windows. Have you ever wondered how that works for things like Remote Desktop? pic.twitter.com/8r16tHkclN
— Steve Syfuhs (@SteveSyfuhs) September 8, 2020
Twitter Warning: Like all good things this is mostly correct, with a few details fuzzier than others for reasons: a) details are hard on twitter; b) details are fudged for greater clarity; c) maybe I'm just dumb.
The first thing the client does is ask what protocol is supported. In this case the target responded and said please do NLA -- network level authentication. The client then immediately prompts for credentials. Doesn't do anything special, just prompts.
Once the user enters their creds NLA kicks in. NLA is the first stage of the CredSSP protocol, which is how those creds you typed in make it to the target server securely. NLA works by first opening an SPNEGO Negotiate connection with the target.
The target happily responds and depending on a few conditions might do a couple different things. In the first case the target provides its machine account's Kerberos Ticket Granting Ticket. It's encrypted so only Active Directory can decrypt it, so its safe to pass around.
The client has the targets TGT and then does a Kerberos TGS-REQ to AD asking for a service ticket to the target name (EDIT host/) termsrv/target.domain.com, and passes the TGT into the additional-tickets field to do something called user-to-user or encrypt-in-session-key auth.
User-to-user is interesting because the KDC will encrypt the service ticket it's about to mint using the session key contained in the additional-tickets TGT instead of the usual long term key of the service itself. In any case the ticket is returned to the client.
In the second case user-to-user is skipped, and the client just requests a ticket to termsrv/target.domain.com and the KDC encrypts the ticket using the service long term key. Nothing exciting here.
In the third case NTLM happens. Blegh.
In the forth case something like PKU2U happens. This is special to AAD-joined target machines only. More on this later.
Anyway... the client has the service ticket to the target and the fun begins. The client converts the ticket into an AP-REQ and fires it off to the target. The target receives it and decrypts it using either the session key in it's machine TGT, or using it's machine password.
The target then generates a session key and stashes it in a place LSA can get to. An AP-REP is returned to the client containing this session key. Following along? It's complicated I know.
Okay, now the client has this session key. Remember how the client prompted for your creds a while back? Well now CredSSP takes those creds and encrypts them using the session key. The client then fires this blob off to the target server.
And the target receives the blob. It takes the session key it stashed away a while back and decrypts the blob. Now it has a username and password. That username and password is passed to the logon UI bits and now we're back to that original thread. Magic!
There are some notable differences here though. For instance remote connections never go through cached logon.
But what about things like smart cards and Windows Hello and Remote Credential Guard?
On Smart Cards and Windows Hello
Smart Cards and Windows Hello are effectively the same thing... ish. They differ in lots of ways, but to RDP it's all certs and stuff.
Smart Card-based CredSSP works similarly to passwords. The NLA portion works just the same. The difference is the creds themselves. It turns out RDP emulates the smart card hardware and literally passes hardware commands back and forth over the channel.
This is, incidentally, why it takes so long for RDP sessions to start when using smart cards. It's proxying hardware commands over the channel encrypted to that session key. It's kinda wild.
On Remote Credential Guard
Remote Credential Guard is something entirely different though. It's an incredibly clever mechanism that prevents clients from sending any primary credentials to the target machine, therefore mitigating any risk of leaking them if the target is compromised.
RCG works by creating a reverse proxy of sorts from the target to the client. Whenever an application on the target needs a ticket of some sort to something it asks LSA as all ten billion apps have done since 1990. LSA is aware of RCG and so it opens a channel back to the client.
Over the channel the target LSA asks the client to ask (ish) the client LSA for a ticket to whatever the target needs. The client obliges, and forwards the ticket. The target now has a ticket, and never saw the creds. It's ingenious.
Now the cool thing about RCG, aside from the security properties, is that it also solves a problem that plagues Windows Hello for Business Key Trust deployments -- specifically that you can't use your WHFB credentials during RDP.
RCG solves this problem by avoiding it entirely -- it doesn't even care what credentials you used. It just asks the client to do all the heavy lifting, and the client is happy to do all the heavy lifting.
Anyway... a few posts back I mentioned PKU2U. PKU2U is what happens when you take Kerberos, remove any concept of centralized authority, and convert all credentials to asymmetric keys. Seriously.
PKU2U was invented to solve the Homegroup problem. You have two machines that don't inherently trust one another or any shared authority. Well, if you spin up certificates for each side and then exchange them during the initial setup, you get something that kinda sorta works...
And it keeps two or more machines trusting each other without any of this symmetric key garbage.
But I digress. Why does PKU2U matter?
Well, it turns out when AAD was being built into Windows, AAD didn't know how to do Kerberos, and it sure as hell wasn't going to use NTLM for anything. What AAD did have was certificates. Lots of certificates.
And so when you have an AAD-enlightened machine a few certificates are stamped onto the box. When you kick off a PKU2U connection the client connects up to AAD to request a custom certificate just for this, and then kicks off the handshake with the target.
The target sees its PKU2U, checks the certificate from the user chains up to AAD, goes and gets it's certificate from AAD, returning it in the handshake. The client checks the server cert chains to AAD, and voila. Some key agreement goop occurs and now we have a session key.
This incidentally is why its difficult to RDP to AADJ machines. Your client doesn't have the AAD certificates. This was recently fixed where the certs are stamped on the client machine when you register your AAD account. This is also why turning off NLA "fixes" the issue.
Okay, but why NLA?
So that brings up the question: what exactly happens when I turn NLA off? Oh boy. Let me tell you. First of all, it skips NLA (duh). NLA is there to guarantee you're sending creds to a machine you genuinely expect to, not some person in the middle.
NLA provides that guarantee by asking a trusted 3rd party like AD or AAD. Without NLA, there's no check, so no guarantee, so no trust.
Without NLA you're connecting to some remote IP that can't provide any meaningful guarantee it is who you want it to be and you're typing your password into a textbox it has presented to you. If you find that trustworthy, check out this link to your "bank".