Why RDP Lateral Movement Is Still a Core Detection Problem

Remote Desktop Protocol has been around since Windows NT 4.0. It’s also the lateral movement technique defenders encounter most often in ransomware intrusions, nation-state operations, and red team engagements. MITRE ATT&CK catalogs it as T1021.001 and for good reason: RDP is built into every Windows installation, it provides full interactive GUI access, it blends with legitimate admin traffic on most enterprise networks, and it’s almost never completely disabled.

The challenge for detection engineers isn’t identifying that RDP exists — it’s distinguishing malicious lateral movement from the hundreds of legitimate helpdesk, IT admin, and remote work connections that fire every day. This guide focuses on the telemetry that separates those cases and the rules that catch the malicious ones.

How Attackers Use RDP for Lateral Movement

Standard RDP lateral movement means an attacker with valid credentials on a compromised host opens an RDP session to another host in the network — typically moving from a workstation or DMZ server toward domain controllers, file servers, or backup infrastructure.

Several techniques augment basic credential use:

Restricted Admin Mode (Pass-the-Hash RDP): Windows supports an RDP mode where the session authenticates using NTLM hash rather than a password. An attacker who has dumped hashes but not cracked them can use mstsc.exe /restrictedAdmin to authenticate. This is effective against unpatched systems or systems where Credential Guard isn’t enforced. The key characteristic: logon type 10 without network credentials being forwarded to the remote host.

RDP over Port Forwarding: Attackers who can’t reach a target directly often tunnel RDP through an existing compromised host using tools like Chisel, Ligolo-ng, or native SSH port forwarding. The RDP traffic itself is identical — what changes is the routing path.

SharpRDP and FreeRDP: Tooling like SharpRDP executes commands on remote hosts via the MSRDP ActiveX control without spawning a visible desktop, making it useful for non-interactive remote execution under the radar of endpoint tools that flag mstsc.exe.

Key Telemetry Sources

Windows Security Event Log

These event IDs are the foundation of RDP detection:

Event ID 4624 — Logon Success

  • Logon Type 10 = RemoteInteractive (RDP with session creation)
  • Logon Type 3 = Network (RDP reconnect or NLA pre-authentication)
  • Pay attention to: source IP (IpAddress field), account name, and workstation name

Event ID 4625 — Logon Failure

  • Repeated failures from unexpected source IPs suggest credential spraying over RDP
  • Logon Type 10 failures are particularly interesting

Event ID 4648 — Explicit Credential Logon

  • Fires when runas or an application explicitly supplies credentials
  • Relevant when an attacker uses a different account to initiate the RDP session

Event ID 4778 / 4779 — Session Connect / Disconnect

  • Tracks RDP session lifecycle on the target host
  • Useful for reconstructing attacker dwell time

Sysmon

Event ID 1 (Process Create): mstsc.exe spawning from unusual parent processes (e.g., cmd.exe, powershell.exe, a web shell process) is a strong signal. Legitimate use: explorer.exe, Citrix receiver processes.

Event ID 3 (Network Connection): Outbound connections on port 3389 from non-management hosts. Any workstation initiating RDP to another workstation is suspicious in most enterprise environments.

Windows System Event Log

Event ID 21, 24, 25 (TerminalServices-LocalSessionManager): Session logon, disconnect, and reconnect events. These fire on the target host and are useful for correlating with Security log events.

Sigma Rules

Outbound RDP from Non-Admin Hosts

title: Outbound RDP Connection from Workstation
id: a4b1c2d3-e4f5-6789-abcd-ef0123456789
status: experimental
description: Detects RDP connections initiated from workstation-class hosts, which is unusual in most environments
author: SOC Analyst Hub
date: 2026/07/07
logsource:
  product: windows
  category: network_connection
detection:
  selection:
    EventID: 3
    DestinationPort: 3389
    Initiated: 'true'
  filter_servers:
    Image|contains:
      - '\mstsc.exe'
  condition: selection and not filter_servers
  filter_admin:
    SourceHostname|contains:
      - 'JUMP'
      - 'MGMT'
      - 'ADMIN'
  condition: selection and not (filter_admin)
falsepositives:
  - Jump server management tools
  - Legitimate admin RDP workflows
level: medium
tags:
  - attack.lateral_movement
  - attack.t1021.001

RDP Login from New Source IP

title: RDP Logon from Unusual Source
id: b5c2d3e4-f5a6-789b-cdef-012345678901
status: experimental
description: Detects successful RDP logons (type 10) from source IPs with no prior authentication history
author: SOC Analyst Hub
date: 2026/07/07
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4624
    LogonType: 10
  filter_local:
    IpAddress:
      - '127.0.0.1'
      - '-'
      - '::1'
  condition: selection and not filter_local
falsepositives:
  - New admin workstations
  - VPN IP pool changes
level: medium
tags:
  - attack.lateral_movement
  - attack.t1021.001

Restricted Admin RDP (Pass-the-Hash via RDP)

title: RDP Restricted Admin Mode Usage
id: c6d3e4f5-a6b7-890c-def0-123456789012
status: experimental
description: Detects use of RDP Restricted Admin mode, which allows pass-the-hash authentication
author: SOC Analyst Hub
date: 2026/07/07
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4624
    LogonType: 10
    LogonProcessName: 'NtLmSsp'
    AuthenticationPackageName: 'NTLM'
  filter_legitimate:
    SubjectUserName|endswith: '$'
  condition: selection and not filter_legitimate
falsepositives:
  - Older systems where NLA is not enforced
level: high
tags:
  - attack.lateral_movement
  - attack.t1021.001
  - attack.credential_access
  - attack.t1550.002

Anomalous mstsc.exe Parent Process

title: mstsc.exe Spawned from Suspicious Parent
id: d7e4f5a6-b7c8-901d-ef01-234567890123
status: experimental
description: Detects mstsc.exe launched from unusual parent processes indicating potential attacker-initiated RDP
author: SOC Analyst Hub
date: 2026/07/07
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    Image|endswith: '\mstsc.exe'
  filter_normal:
    ParentImage|endswith:
      - '\explorer.exe'
      - '\taskmgr.exe'
      - '\ctfmon.exe'
  condition: selection and not filter_normal
falsepositives:
  - Automation frameworks
  - IT management tooling
level: medium
tags:
  - attack.lateral_movement
  - attack.t1021.001

KQL Detection Rules (Microsoft Sentinel)

Successful RDP Logon Outside Business Hours

SecurityEvent
| where EventID == 4624
| where LogonType == 10
| where TimeGenerated between (todatetime("00:00") .. todatetime("06:00"))
    or TimeGenerated between (todatetime("20:00") .. todatetime("23:59"))
| where IpAddress !in ("127.0.0.1", "-", "::1")
| where AccountType == "User"
| project TimeGenerated, Account, IpAddress, WorkstationName, Computer
| order by TimeGenerated desc

RDP Lateral Movement Chain (Multiple Hops)

let rdp_logons = SecurityEvent
    | where EventID == 4624 and LogonType == 10
    | where IpAddress !in ("127.0.0.1", "-", "::1")
    | project LogonTime=TimeGenerated, TargetHost=Computer, 
              SourceIP=IpAddress, Account=Account;
// Find hosts that appeared as both source and target within a sliding window
rdp_logons
| join kind=inner (rdp_logons) on $left.TargetHost == $right.SourceIP
| where $right.LogonTime > LogonTime and $right.LogonTime < LogonTime + 2h
| project FirstHop=TargetHost, SecondHop=$right.TargetHost, Account, 
          FirstLogon=LogonTime, SecondLogon=$right.LogonTime
| order by FirstLogon desc

RDP Brute Force Detection

SecurityEvent
| where EventID == 4625 and LogonType == 10
| where TimeGenerated > ago(1h)
| summarize FailureCount = count(), Accounts = make_set(TargetUserName) 
  by IpAddress, bin(TimeGenerated, 5m)
| where FailureCount > 10
| order by FailureCount desc

High-Value Target RDP Access

let high_value = datatable(Host:string) ["DC01", "DC02", "BACKUP01", "FILESERVER01"];
SecurityEvent
| where EventID == 4624 and LogonType == 10
| where Computer has_any (high_value)
| where IpAddress !in ("10.0.1.5", "10.0.1.6")  // Adjust for your jump server IPs
| project TimeGenerated, Account, IpAddress, Computer
| order by TimeGenerated desc

Baseline and Tuning Guidance

These rules will generate significant false positives without baselining:

Jump servers: Build an allowlist of your legitimate RDP management hosts. Any detection rule that doesn’t filter on jump server source IPs will fire constantly in environments with a managed jump host infrastructure.

IT admin accounts: Service accounts used by endpoint management tools (SCCM, Intune MDM, etc.) may initiate RDP connections programmatically. Identify these and add them to filter lists.

VPN IP ranges: If your VPN assigns user IPs from a known range, those shouldn’t trigger RDP-from-unknown-IP alerts. If it’s dynamic, consider flagging connections where the source IP changes significantly within a short window for the same account.

Time-of-day baselines: In environments where legitimate after-hours administration is common (global organisations, 24/7 ops teams), time-based rules need adjustment or suppression for specific account groups.

Correlation with Known Attacker TTPs

RDP lateral movement rarely appears in isolation. Correlate RDP detections with:

  • Credential dumping preceding the logon — if LSASS access events (Sysmon Event ID 10 on the source host) preceded the RDP connection, that’s a high-confidence chain
  • New account creation following the RDP logon — attackers establishing persistence after achieving RDP access
  • Ransomware deployment toolsrclone.exe, wevtutil.exe (log clearing), vssadmin delete shadows occurring in the same session window as the RDP logon

T1021.001 combined with T1003 (credential dumping), T1136 (account creation), or T1490 (inhibit system recovery) represents a high-confidence ransomware pre-deployment pattern.