>
av.Amit VijayanCYBERSECURITY & RESEARCHLet\u2019s connect
Back to the library

Threat Hunting Playbooks

Hunting RDP Session Hijacking: When tscon Hands an Attacker Someone Else's Desktop

Thumbnail for: Hunting RDP Session Hijacking: When tscon Hands an Attacker Someone Else's Desktop

Why this matters now

An attacker who steals an administrator credential does not always need to log on as a new user, drop malware, or steal a password hash. On a Windows host with Remote Desktop Services, they can simply take over a session that is already running. The built-in utility tscon.exe moves an existing Remote Desktop session to a different destination, so the attacker inherits the victim's desktop, open applications, and access tokens — without ever triggering a new logon for the victim's account. The victim, meanwhile, is disconnected and may assume the session merely timed out.

MITRE ATT&CK tracks this under T1563.002, Remote Service Session Hijacking: RDP Hijacking. It is a lateral-movement and privilege-escalation technique in one move: a low-privilege remote session can become a domain administrator's live desktop if that administrator left a disconnected session on the same host. Helpdesks use the same primitives legitimately to shadow a user's session, which is exactly why the technique blends in — the tool is signed, built into Windows, and rarely monitored.

How RDP session hijacking works

The attack has three ordinary-looking steps. First, the attacker enumerates sessions on the target host with qwinsta (also known as query session), which lists session IDs, usernames, states such as Active or Disconnected, and session types. A disconnected administrator session is the prize: its processes and tokens are still alive on the host.

Second, the attacker connects that session to their own with tscon.exe <session ID> /dest:<their session name>. The command requires administrative rights on the host or the specific Remote Desktop Services permission to connect to another session, which is why stolen admin credentials and session hijacking so often arrive together. No password for the victim's account is needed, and no new interactive logon is created for the victim.

Third, the attacker works inside the victim's desktop. Anything the victim could do — open files, run administrative tools, access internal applications with saved credentials — the attacker can now do, under the victim's identity. A related primitive is session shadowing, invoked through mstsc /shadow:<session ID>, which lets an observer view or control a session remotely; shadowing can be configured to require the user's consent, but that protection only helps if it is actually enforced by policy.

The telemetry gap is the point. Because the victim already authenticated, defenders who hunt only for new logons will miss the takeover entirely. The durable signals are the enumeration, the tscon.exe process itself, and the disconnect/reconnect events that bracket the switch.

The KQL hunts

All queries target Microsoft Defender's DeviceProcessEvents table, with a logon check in Hunt 4. Tune the lookback to your retention.

Hunt 1 — tscon.exe anywhere in process telemetry

The highest-fidelity hunt in this playbook. tscon.exe has almost no reason to appear outside deliberate administrative work, so every hit deserves a look.

DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName =~ "tscon.exe"
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc

Hunt 2 — Session enumeration followed by tscon on the same host

Enumeration alone is noisy; enumeration followed by a hijack is not. Join qwinsta or query.exe session queries to a later tscon.exe execution by the same account on the same device.

let Enumeration = DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName in~ ("qwinsta.exe", "query.exe")
| where ProcessCommandLine has "session"
| project EnumTime = TimeGenerated, DeviceName, AccountName;
let Hijack = DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName =~ "tscon.exe"
| project HijackTime = TimeGenerated, DeviceName, AccountName, ProcessCommandLine;
Enumeration
| join kind=inner Hijack on DeviceName, AccountName
| where HijackTime between (EnumTime .. (EnumTime + 1h))
| project EnumTime, HijackTime, DeviceName, AccountName, ProcessCommandLine
| order by HijackTime desc

Hunt 3 — Session shadowing with mstsc /shadow

Shadowing is the quieter cousin of hijacking. A mstsc.exe command line carrying /shadow outside an approved helpdesk workflow is a session takeover in progress, even if no tscon.exe ever runs.

DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName =~ "mstsc.exe"
| where ProcessCommandLine has "/shadow"
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine,
          InitiatingProcessFileName
| order by TimeGenerated desc

Hunt 4 — tscon across many hosts, or by an unexpected account

Legitimate session management is concentrated in a small helpdesk or admin group on a small set of hosts. Breadth, or an account outside that group, is the attacker-shaped signal.

DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName =~ "tscon.exe"
| summarize Hosts = dcount(DeviceName), HostList = make_set(DeviceName, 25),
            FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
    by AccountName
| where Hosts > 1
| order by Hosts desc

Baseline the accounts that legitimately run tscon.exe first, then alert on any account outside that list. A single host hit by a service account or a standard user account is worth escalating on its own.

Splunk equivalents

Process-creation telemetry is Windows Security Event 4688 or Sysmon Event 1; session reconnect and disconnect events are Security Events 4778 and 4779.

SPL 1 — tscon.exe in process-creation telemetry

index=wineventlog (EventCode=4688 OR EventCode=1) New_Process_Name="*tscon.exe"
| table _time, host, Account_Name, New_Process_Name, CommandLine, Parent_Image

SPL 2 — Session enumeration, then tscon, on the same host

index=wineventlog (EventCode=4688 OR EventCode=1)
  ((New_Process_Name="*qwinsta.exe" OR New_Process_Name="*query.exe") OR New_Process_Name="*tscon.exe")
| transaction host Account_Name maxspan=1h
| search New_Process_Name="*tscon.exe"
| table _time, host, Account_Name, New_Process_Name, CommandLine

SPL 3 — Reconnect without a matching new logon

Events 4778 (session reconnected) and 4779 (session disconnected) bracket a hijack. Pair a 4778 for one account with a 4779 for another account on the same host in the same short window, and check whether any Event 4624 Type 10 logon explains the new session owner. A reconnect with no new logon is the shape of a hijack.

index=wineventlog (EventCode=4778 OR EventCode=4779)
| table _time, host, Account_Name, EventCode
| sort _time

Triage: what to do when a hunt hits

  1. Identify both sessions. The tscon.exe command line names the hijacked session ID. Work out whose session it was, what that user could access, and which session it was moved to.
  2. Check the victim's session state. A disconnected administrator session is the classic target. Find out why it was left disconnected, how long it had been idle, and whether the victim noticed being disconnected.
  3. Read the full process tree. What ran inside the hijacked session after the takeover — administrative tools, credential-access commands, file access — defines the blast radius. Pull the surrounding process telemetry, not just the tscon.exe row.
  4. Correlate the entry point. How did the attacker reach the host in the first place? Look for the attacker's own Remote Desktop logon, a prior lateral move, or a stolen credential, and scope every other host that account touched.
  5. Assume the victim's access is burned. If an administrator's live session was taken over, treat every system that administrator could reach from that desktop as potentially accessed, and reset credentials the attacker could have used from inside the session.

Remediation and hardening

  • Restrict who can connect to another user's session: limit Remote Desktop Services permissions and RDP logon rights to a small, named admin and helpdesk group, and remove the right from service and standard user accounts.
  • Enforce consent for shadowing by Group Policy (require the user's permission for remote control of a session) so silent observation is not the default.
  • Set session time limits so disconnected sessions log off rather than lingering: idle and disconnected administrators are the hijack target, and a logged-off session cannot be taken over.
  • Alert on tscon.exe, qwinsta.exe session queries, and mstsc /shadow outside the approved helpdesk group — and baseline the legitimate users first so the alert stays actionable.
  • Do administrative work from privileged access workstations, not from shared jump hosts where other users leave disconnected sessions lying around.
  • Disable Remote Desktop entirely on hosts that do not need it, and block inbound RDP at the host firewall everywhere else.

Keep exploring.

All articles