This is the third and last part about RDP, protecting credentials and delegation models.
This time it’s about Remote Credential Guard, pros and cons and how to model this with LAPS and Just in Time Admin Access.
I haven’t had much time to write this so I will keep it short and simple with a few examples.
Remote Credential Guard
Remote Credential Guard (RCG) was introduced in Windows Server 2016 and Windows 10 version 1607. It’s a new way to protect your RDP session from credential thefts like Pass the Hash, some Pass the Ticket and other LSASS dumps on the target computer. It provides SSO and your credentials is never exposed on the remote machine. This helps in a way that if a admin of any level connects to a compromised machine, his domain credentials won’t be exposed on the target machine preventing lateral movement in that way.
It relies on Kerberos and all service ticket requests in the RDP session on the server is routed to the client.
A few requirements:
- Trust if connecting to machine in another Forest/Domain.
- Windows Server 2016 or Windows 10 version 1607
- Remote Desktop classic Windows app
Advantages and Disadvantages:
Compared to RDP Restricted Admin mode there are a few advantages.
- Only use Kerberos
- You don’t need to be member of the local administrators group on the target machine, it’s enough you’re a member of the Remote Desktop Users group
- The user connects to other resources as them self
- Multi-hop, the user can from one RDP session connect to another one
- Prevents usage of a credential after disconnection
And the main disadvantages are:
- This is not backported to older OS
- Isn’t supported by Remote Desktop Gateway
Setting this up:
It’s quite easy to configure this. If you’ve read part one to enabled Restricted Admin Mode, it’s the same registry key that needs to be configured:
reg add HKLM\SYSTEM\CurrentControlSet\Control\Lsa /v DisableRestrictedAdmin /d 0 /t REG_DWORD
And for this to be configured as default for the clients we use the same Computer Group Policy Setting:
Computer Configuration/Policies/Administrative Templates/System/Credentials Delegation
Enable: Restrict delegation of credentials to remote servers
and choose: Use the following restricted mode: Require Remote Credential Guard
Note: You can also choose: Prefer Remote Credential Guard if you have a mixed environment with older systems, it will fall back to Restricted Admin Mode if it is enabled, else the user won’t be able to logon to that system.
If not configured on the clients, the user can choose to start the RDP client in RCG mode: mstsc.exe /remoteguard
We can test this with the user Tony. He is not a member of any admin groups nor the Protected Users group. He will have the same SSO experience and can’t choose another user.
In the RDP session on SRV01 everything looks normal, whoami.exe /groups shows he is a regular user, not a local admin, he has some domain group memberships and Remote Desktop Users.
If we look at the Kerberos tickets with klist.exe we will see a slight difference from the normal. On the primary TGT the “Kdc Called” field will be empty.
And we will have the same result if we use mimikatz, Target Name (–).
And if we want to see some real difference we can connect to the server from a client configured with Credential Guard locally.
That’s cool. to put it in a simple way, the TGT on the destination server is a shadow TGT from the client and all TGST requests is routed back to the source client.
One thing to note is that if possible, it’s still a good idea to use the Protected Users group as an extra layer.
Two examples of how RCG will help us:
RDP Session hijacking:
If you are a admin on a server it’s possible with a few simple steps to hijack RDP sessions without the need to know the password for that user. I’m not going to go deep with this, if you want to read more with different examples Alexader Korznikov has a great blog post about it: Passwordless RDP Session Hijacking Feature All Windows versions
If a user manages to hijack your session, you will be disconnected (in those examples I’ve seen) and the damage depends on what you had accessed in that session. Locally on the server doesn’t matter since it was already compromised. Since the Service Ticket requests is routed to the client where you started your RDP sessions from isn’t connected anymore he won’t be able to request new ones. So, it all depends on what Service Tickets you had there.
Kerberos ticket theft:
Steal the NTLM hash and perform PtH won’t work here. But if a malicious user has local admin rights he could dump all the Kerberos Service Tickets from the server and perform Pass the Ticket to access other resources. Using the TGT however, won’t work.
In this scenario the Tony user has logged on to the server: SRV01 with standard RDP. Fox is an evil admin on that server and has stolen all the tickets. He has copied them to another server: SRV03.
On SRV03 he is a regular user with no admin rights and no special Kerberos tickets.
With e.g. Mimikatz he can change to the stolen TGT and will now be able to access a share only granted to the Tony user:
By using the stolen TGT the client will ask for a Service Ticket when trying to access that share and it will be created by the TGS and and Fox can now access all the resources granted to Tony.
Now, if Tony would have connected with RCG it would have been different. Here is the same scenario where he has stolen the TGT hand wants to access a share on DC01 granted to Tony. And to be clear about it we will try to use the Mimikatz Kerberos::ask command to request a specific Service Ticket.
As you can see this will fail. The missing piece is back at the client where the RDP connection started from. However, in this case, Fox dumped all the tickets on SRV01 and got on hold of a Service Ticket to another server. That one can still be used:
So, it’s not perfect and this works the same on computers configured with Credential Guard, the TGT will be protected, not the STs (and this is by design). If a malicious user can trick Tony to run something in his context and get a shell, he will be able to request and dump Service Tickets for reuse during its lifetime. The time slot will be narrower but is still a problem…
Another example of this, if a malicious user is admin on the target machine tony login to. He could list all the processes running on the system and see which ones runs in Tonys context. With Invoke-PSInject the attacker can run commands thru one of Tonys processes and that way e.g. run mimikatz DCSync feature if hes a Domain Admin, and then it’s game over. in this case maybe running RDPRA could be more desirable.
How to model and strengthen this:
Since RCG don’t require Tony to be a Local administrator on the target system (like Restricted Admin Mode) we can start with only allowing him to RDP to the server by adding him directly or indirectly to the local Remote Desktop Users group.
As a regular user he maybe won’t be able to do much, and it all depends on the purpose of the account. We can grant him some basics.
Generate RSOP data:
If he wants to troubleshoot Group Policy’s all you have to do is to delegate Generate RSOP logging. This is done on the appropriate OU level. Allow a Security Principal the Extended Right: Generate Resultant Set of Policy (Logging)
With this done, Tony can logon as a regular user and generate RSoP data for the computer, and if this also is set on a OU scoping other users he can generate for them as well.
If the user needs administrator privileges we can start with implementing LAPS
Local Administrator Password Solution (LAPS):
With LAPS we can set a random generated password on the local administrator account and is unique on every machine in the domain who has this configured. The password is stored in the corresponding computer account in the ms-Mcs-AdmPwd attribute which is marked as confidential.
With this we can allow Tony, or preferably another account to read this attribute, and when he needs to elevate to local admin he can use the local admin account temporarily.
If the server already is compromised, the password is already compromised. But the user won’t be able to perform any lateral movement with it, since they are unique on every machine.
Note: if you want to read more about LAPS and how to implement it: Local Administrator Password Solution
To add an extra layer to this, if the account that can read the passwords in AD is compromised we can deny remote access for local user accounts.
In Windows 8.1 and Windows Server 2012R2 two new SIDs where introduced:
- S-1-5-113: NT AUTHORITY\Local account
- S-1-5-114: NT AUTHORITY\Local account and member of Administrators group
If a user is authenticated as a local account the S-1-5-113 SID is added to the access token. If he’s a member of the Local Administrators group the S-1-5-114 SID will also be added. With this we can set allow/deny rules.
In this case we will set it in a GPO configuring User Rights Assignment.
Edit a GPO and navigate to: Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/User Rights Assignment
Deny access to this computer from the network
Deny log on through Remote Desktop Services
And link this to the appropriate OU. Testing this with the local administrator account you will get a error message.
This is also backported down to Windows 7 and Windows Server 2008 R2. There are some downfalls with some special account so planning is important (as always) If you want more info you can read this: Blocking Remote Use of Local Accounts
There will be cases where you will need to use Administrative Domain Credentials and we don’t want to use another account and use Run as. Another thing is that we haven’t completely mitigated the problem with PtT of the Service Tickets.
Just in Time Admin Access:
I have covered JiT with AD PAM Optional feature earlier and its components like Time-Based Groups and Shadow Principals. With this we can have delegated admin groups with a temporary membership controlled by time and it integrates well with Kerberos and don’t have any downfalls with replication convergence and such.
When the TTL-DN link value expires the user will be removed from the group locally on all DCs, Kerberos tickets will expire.
Note: The only downfall is if the user still has an active RDP session to the server he won’t lose it. He will lose his admin privileges in the session and if he closes the RDP a disconnected session will still be there but he won’t be able to reconnect. If the TTL has expired, this session will be useless for an attacker that has gained control of this server (This is only tested on Windows Server 2016).
Instead of having admin users always being an admin on multiple machines, shares or services by membership of Domain Security Groups, he will be a regular user requesting access to resources when needed.
Combine this with control of his hardened admin station being the starting point it will be very hard for an attacker to get anywhere.
To summarize this:
- Tony admin account is a regular user granted default Authenticated Users access in the domain
- Has his Admin workstation as its starting point (which he is no admin of)
- Can RDP to server without being a admin of that server
- When he RDPs to a server Kerberos is required
- NTLM hash isn’t there, the TGT is protected
- He uses primarily LAPS password to elevate
- LAPS protected account is siloed to the corresponding server and can only be used “localy”
- If an attacker owns the server he won’t get any further unless there are some Service Tickets that could be used and this is narrowed down to least possible time limit with time-based group membership
Hope you enjoyed it!
This 3-part series has been mainly about RDP and how we can protect it and use a lot of other features to make it and the Windows platform more secure. I hope this has inspired to new ideas and to use other features that comes with the Windows platform.