RDP Session Hijacking – tscon and SharpRDPHijack
Windows Terminal Services allows sessions to be transferred between connections using tscon.exe. When running as SYSTEM, you can connect to any disconnected session on the host without supplying the session owner's credentials. If a domain admin left a disconnected RDP session on a host you control, you take over their desktop with a single command.
This requires SYSTEM-level privileges on the host. Getting there is a privilege escalation task. Once you have SYSTEM, hijacking is trivial and leaves minimal forensic trace compared to other lateral movement techniques — no new process is created under the target user, and the session transfer looks like a legitimate reconnection.
Identifying Sessions
List all active and disconnected sessions on the current host:
Or the equivalent:
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME administrator rdp-tcp#0 1 Active . 1/10/2024 09:00 jsmith 2 Disc 1:23 1/10/2024 08:30 domainadmin 3 Disc 0:45 1/10/2024 07:15
Disc means disconnected — the user closed their RDP window without logging off. Their session is still alive in memory with all their tokens and network connections intact. Session IDs 2 and 3 are targets.
For remote hosts you have admin access to:
Explain command
| /server:$TARGET_IP | Specifies the remote server to query user sessions from. |
Hijacking with tscon – Service Method
tscon.exe run directly requires matching session ownership or SYSTEM. Creating a service that runs as SYSTEM bypasses this. From a local admin shell:
Elevate to SYSTEM first using PsExec or any other method:
Explain command
| -s | Run the remote process under the SYSTEM account. |
| cmd.exe | Target executable to launch remotely via PsExec. |
Then switch directly to the target session — connecting it to your current console session:
Explain command
| $SESSION_ID | Target session ID to hijack or connect to. |
| /dest:rdp-tcp#$YOUR_SESSION_ID | Specifies the destination session to redirect the target session into. |
Where $SESSION_ID is the ID of the session you want to hijack and $YOUR_SESSION_ID is your current session name from query user.
Without SYSTEM first, create a service that runs tscon as SYSTEM:
Explain command
| create hijack | Creates a new Windows service named 'hijack'. |
| binpath= | Specifies the binary path (command) the service executes on start. |
| cmd.exe /k | Runs cmd.exe and keeps the window open after executing the command. |
| tscon | Connects a Remote Desktop session to another session. |
| $SESSION_ID | Placeholder for the target RDP session ID to hijack. |
| /dest:rdp-tcp#$YOUR_SESSION_ID | Specifies the destination session to connect the hijacked session to. |
| start hijack | Starts the previously created 'hijack' service to trigger execution. |
The service runs as SYSTEM, executes tscon, connects the target session to your current RDP connection, and their desktop replaces yours. You are now in their session.
Clean up the service afterward:
Hijacking with SharpRDPHijack
SharpRDPHijack automates the WTS API calls and provides cleaner options including remote session querying and shadow session support:
Explain command
| --session | Specifies the target RDP session ID to hijack. |
| $SESSION_ID | Placeholder for the numeric ID of the target RDP session. |
Query sessions on a remote host:
Explain command
| --tsquery | Queries active RDP/Terminal Services sessions on the target host. |
| $TARGET_IP | Placeholder for the target host IP address to query sessions on. |
Hijack a specific session without a password (requires elevated context):
Explain command
| --session $SESSION_ID | Specifies the target RDP session ID to hijack. |
| --nopw | Hijack the session without requiring a password prompt. |
On Windows Server 2019 and later, hijacking a session that is currently redirected to an active RDP connection prompts for the user's password. Redirecting to the console session works without a password on all versions:
Explain command
| --session $SESSION_ID | Specifies the target RDP session ID to hijack. |
| --console | Redirects the hijacked session to the physical console session. |
Remote Hijacking
If you have SYSTEM on one host and want to hijack sessions on another, use PsExec to run the tscon command remotely on the target host:
Explain command
| \\$TARGET_IP | Target remote host to connect to via PsExec. |
| -s | Runs the process under the SYSTEM account. |
| cmd.exe | Specifies the executable to launch on the remote host. |
| /k | Runs the specified command and keeps the shell open. |
| query user | Lists currently logged-on users and their session IDs. |
| && | Executes the next command only if the previous one succeeds. |
| tscon $SESSION_ID | Connects to the specified RDP/terminal session ID. |
| /dest:console | Redirects the target session to the physical console session. |
This connects the target user's session to the physical console of the remote host. You then need another RDP connection to view it, or use the shadow feature.
Session Shadowing (View Without Hijacking)
Shadow mode lets you observe a session without taking it over. This is useful for watching what a user is doing without disrupting their session:
Explain command
| /shadow:$SESSION_ID | Specifies the session ID to shadow/monitor on the remote host. |
| /v:$TARGET_IP | Specifies the target remote host IP address to connect to. |
| /noConsentPrompt | Bypasses user consent prompt, shadowing session without target user approval. |
/noConsentPrompt removes the confirmation dialog that would otherwise alert the user. Requires admin rights on the target.
References
-
SharpRDPHijackgithub.com/bohops/SharpRDPHijack (opens in new tab)
bohops .NET implementation of RDP session hijacking using WTS API with shadow and console options.
-
tscondocs.microsoft.com/en-us/windows-server/administration/windows-commands/tscon (opens in new tab)
Microsoft Docs Official tscon parameter reference and session transfer behaviour documentation.
Was this helpful?
Your feedback helps improve this page.