Remote Desktop and Die – How to RDP Faster Without Getting Robbed


Unless you have not patched your domain controller in the past five years, chances are, if an intruder gets domain admin or enterprise admin level access, they probably did it through credential theft. One of the biggest recurring themes of countless intrusion and pentest reports is that to accomplish lateral movement and privilege escalation to domain-wide privileges, intruders need to compromise highly privileged domain accounts. This often happens when an attacker who has compromised a web server or workstation takes the credentials of an administrator who logs into or has recently logged into the system. Those credentials could be a password, hash, or Kerberos ticket-granting-ticket (TGT) stolen out of memory or commandeered via token-theft. If you can disable NTLM and force smart card use for your admins, you can reduce the window and the impact of this credential exposure and stop many other attacks, but this is the one big remaining way that bad guys can steal your credentials.

SANS' 2009 illustration of Compromising a Domain Controller

SANS' 2009 illustration of Compromising a Domain Controller

To address this problem, your administrators must remotely manage systems without leaving reusable credentials on remote systems. (no "double-hop") Admins can use remote registry, admin shares (like C$), powershell remote management, WMI, and remote task scheduling with non-reusable credentials, but not remote desktop. Administrators who RDP into infected systems give away their reusable credentials (i.e. hash, password if not smart card, kerberos TGT always) which allow anyone who has compromised the system to impersonate them. Unfortunately, remote desktop is hands-down the easiest way to perform many tasks, such as install or uninstall software, view different settings and troubleshoot issues.

So it is somewhat surprising that even among the legions of remote-desktop replacement software and services I have yet to find a solution that solves the reusable credentials problem. If one exists, please let me know!
-------
EDIT 9/29/2013: Don't know how I missed this, but Microsoft looks like they are planning on adding a "Restricted Admin Mode" to Remote Desktop in Windows 8.1 or later. (reference here) This will address the credential theft problem for RDP when it is used. Until they backport this functionality, or every system on your network has been upgraded past Windows 8, the temporary accounts will still be needed. So it will probably be a long time before it can be used on most networks, but it is a better long-term solution and it is nice to Microsoft is addressing this issue. Hopefully they will also have group policy to enforce it rather than leaving it optional.
-------
Thankfully, it is not hard to come up with one that works:

  • Whenever you or one of your administrators needs to remotely manage a workstation or server via remote desktop, first log into your trusted admin workstation with your domain administrative account
  • Then use this secureRDP.ps1 script or one like it to open a remote desktop connection to the target system.

This script addresses the above problems by using a temporarily-accessible local administrative account with a randomized password, creating it if necessary. It will work if run from a domain account with administrative privileges, even if denied RDP login rights. The Windows Remote Management (WinRM) service must be running to use remote powershell commands, but remote desktop does not have to be enabled; the script will enable RDP temporarily if necessary, and revert once the session is over.

Here are the details of how it works:

  1. Generate a cryptographically secure 120-bit random password
  2. Ensure unencrypted Windows Remote Management is disabled so that the password cannot be sent in the clear
  3. Check if the temporary account (username.lrdp) already exists on the target
  4. Create the account if it does not exist
  5. Change the password and activate the account if it does exist
  6. Ensure the temporary account is in the local administrators group
  7. Set the temporary account to expire the next day
  8. Enable RDP if necessary
  9. Automatically connect with the given credentials, and wait for session to end
  10. Disable the temporary account
  11. Revert RDP if changes were made

By using WinRM and a temporary account, you will never leave your reusable credentials on the target system. You will not expose any weak accounts to an outside attacker. Even if an attacker steals the credentials for the temporary account, the attacker will gain no additional privileges, and will be unable to move laterally with them. You can even leave terminal services (RDP) off by default, reducing your default attack surface and saving memory and CPU cycles.

As an added benefit, this script can run very quickly, and does not require that you re-enter any credentials to log into the target system. This makes it take less time and makes it more convenient for your admins than requiring them to re-enter their credentials to access a remote system like they would need to do normally. And it does not increase risk to your privileged credentials like saving domain admin credentials would. Although I will grant that it could have a better UI.

A solution for one of our biggest security issues while making it more convenient for admins? Now that's something we can use. Check it out in action:

, , , , , , , , ,

  1. #1 by Samuel on September 15, 2013 - 10:24 pm

    I enabled WinRM service. When I tried to use your PS script to connect form DC, to PC via RDP; I get an error as below:
    [192.168.100.144] Connecting to remote server failed with the following error message : The WinRM client cannot process
    the request. Default authentication may be used with an IP address under the following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. For more information on how to set TrustedHosts run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo : OpenError: (:) [], PSRemotingTransportException
    + FullyQualifiedErrorId : PSSessionStateBroken

    I tried these:
    winrm set winrm/config/client @{TrustedHosts=”RemoteComputerName”} –> On DC
    Enable-PSRemoting –force –> On PC

    Wen I got these errors, your script doesn’t work and Windows asks new users.lrdp’s password

    Do you have any suggestions

    • #2 by scriptjunkie on September 15, 2013 - 10:40 pm

      Try using the system name rather than IP address; Kerberos doesn’t like IP addresses. Does that work? If so, I might want to add a detect-ip-address-then-look-up-system-name routine.

      #Check whether we were given an IP address and fix
      if ($computerName -as [ipaddress]){
      "Uh-oh, it looks like you gave us an IP address. Attempting to convert to a computer name"
      $computerName = [System.Net.dns]::GetHostByAddress($computerName).HostName
      if(!$?){
      "Lookup failed! Is this a domain computer? Try again with a computer name."
      Break
      }
      }

  2. #3 by wadetx on October 9, 2014 - 10:22 pm

    When I run the script I see the account created on the target machine but it still stops and asks for a password which is the random password that I do not know. Any thoughts why the password is not working from the client side?

    • #4 by scriptjunkie on October 9, 2014 - 11:21 pm

      It’s possible you could have the group policy setting “Do not allow passwords to be saved” set. This can be set in the group policy editors under both Computer and User Configuration\Administrative Templates\Windows Components\Terminal Services\Client.

(will not be published)