Old Kit, New Kit Part 10: Remote Access, evil-winrm vs psexec and Manual RDP

Same target, same credential, three different ways in. target-win2022 on the lab range has had a weak local Administrator password since the Sn1per re-verify work confirmed it with a NetExec Pwn3d!, and it’s shown up again in Part 7 and Part 9 of this series. This time the question isn’t whether the credential works. It’s what happens once you actually use it to get a shell, split three ways: psexec (the SMB service-exec classic), a manual RDP login, and evil-winrm.

A quick port check before starting:

$ nmap -Pn -p 445,3389,5985 10.10.10.50
PORT     STATE SERVICE
445/tcp  open  microsoft-ds
3389/tcp open  ms-wbt-server
5985/tcp open  wsman

All three doors are open. What happened behind each one turned out to be the most varied result set this series has produced.

psexec: caught before it could report back

$ time impacket-psexec 'Administrator:Summer2026!@10.10.10.50' whoami
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] Requesting shares on 10.10.10.50.....
[*] Found writable share ADMIN$
[*] Uploading file TModyEfq.exe
[*] Opening SVCManager on 10.10.10.50.....
[*] Creating service tUGm on 10.10.10.50.....
[*] Starting service tUGm.....
[*] Opening SVCManager on 10.10.10.50.....
[-] Error performing the uninstallation, cleaning up
real    103.87s

No whoami output anywhere in that run, and the cleanup step failed. Both are the same story: the box killed the binary before it could do anything useful. The Windows System log confirms it in order.

Rule: 92650 (level 12) -> 'New Windows Service Created to start from windows root path. Suspicious event as the binary may have been dropped using Windows Admin Shares.'
Service Name:  tUGm
Service File Name:  %systemroot%\TModyEfq.exe

That’s Wazuh’s own rule firing on the raw 7045 service-install event, independent of anything Defender does, at level 12, the loudest single alert this series has produced for any tool pair so far. It’s not keying off a signature match. It’s keying off the shape of the thing: a service created to run a randomly-named binary out of %systemroot%, exactly the pattern every SMB-admin-share lateral movement tool from psexec.exe to wmiexec.py to Impacket’s own psexec.py produces. Wazuh doesn’t need to know what TModyEfq.exe is to flag it.

Defender caught it too, and named it:

Rule: 1116 -> Microsoft Defender Antivirus has detected malware or other potentially unwanted software.
Name: VirTool:Win32/RemoteExec!pz
Path: file:_C:\Windows\TModyEfq.exe
Action: Quarantine

VirTool:Win32/RemoteExec!pz is a signature family for exactly this class of tool, not a generic heuristic. The timeline makes the failure obvious in hindsight: the service was installed, Defender’s real-time protection caught the dropped binary and quarantined it within about a second, and there was never a running service left for psexec’s client to talk to. No output came back because there was nothing left to produce it, and the uninstall step errored because the file it was trying to delete was already gone.

This is the opposite of Part 9’s finding, where Defender caught chisel but Wazuh’s own alert stream never saw it, because the Windows Defender operational log wasn’t being forwarded. Here, Wazuh didn’t need Defender’s forwarding at all. Its own Windows Security Event Log ruleset already has a purpose-built rule for “service dropped from an admin share,” and it fired the instant the service was created, before Defender even finished its scan.

Manual RDP: a false negative, then a real session

The plan was to time RDP the same way as the other two: connect, authenticate, confirm, disconnect. xfreerdp’s +auth-only flag looked like the right tool for that, a diagnostic mode that authenticates and exits without opening a full session.

$ time xfreerdp /v:10.10.10.50 /u:Administrator /p:'Summer2026!' /cert:ignore +auth-only
[ERROR][com.winpr.sspi.Kerberos] - kerberos_AcquireCredentialsHandleA: krb5_parse_name
  (Configuration file does not specify default realm)
[ERROR][com.freerdp.core] - freerdp_connect_begin: Authentication only, exit status 1
real    1.32s

That reads like a hard authentication failure, and it took me a few rounds of flag changes to prove it wasn’t one. /auth-pkg-list:ntlm didn’t change the error. Explicitly excluding Kerberos (/auth-pkg-list:ntlm,!kerberos) didn’t either. Giving it a domain hint changed the error’s wording, from “configuration file does not specify default realm” to “cannot find KDC for realm,” but not the outcome. Every variant died in FreeRDP’s own Kerberos credential-handle setup, on the Kali side, before NTLM was ever tried.

The real tell came from checking the target while all of this was supposedly failing. Every single one of those +auth-only attempts shows up on target-win2022 as a clean success:

Id 1149 -> Remote Desktop Services: User authentication succeeded:
           User: Administrator
           Source Network Address: 10.10.10.5

The server-side NLA handshake was completing over NTLM every time. FreeRDP’s +auth-only mode was reporting a local failure that had nothing to do with whether the credential actually worked, because it treats any error in its own Kerberos probe as fatal and never falls through to report the NTLM result underneath it. On a workgroup target with no reachable KDC, that makes +auth-only worthless as a pass/fail signal, not because the auth failed, but because the diagnostic mode itself can’t get out of its own way.

A full connection (dropping +auth-only) needed a real display before it would even try the network, which a headless Kali terminal doesn’t have:

[ERROR][com.freerdp.client.x11] - xf_setup_x11: failed to open display

Xvfb fixed that cheaply:

$ Xvfb :99 -screen 0 1280x1024x24 &
$ export DISPLAY=:99
$ time timeout 10 xfreerdp /v:10.10.10.50 /u:Administrator /p:'Summer2026!' /cert:ignore /sec:nla

Same Kerberos errors logged, this time non-fatal, and the connection carried on. FreeRDP printed Logon Error Info LOGON_FAILED_OTHER, which sounds like a second failure but isn’t one. It’s a mislabeled info callback, not an actual result. The real answer is on the target:

Id 1149 -> User authentication succeeded
Id 41/42 -> Begin/End session arbitration
Id 21 -> Session logon succeeded
Id 22 -> Shell start notification received
Id 24/40 -> Session disconnected, reason code 0

The desktop shell genuinely started. The disconnect at the end is our own timeout 10 closing the client, cleanly, not a failure. A logon that took about three seconds from authentication to a running shell.

That took real digging to prove, and it’s worth being honest about where the friction actually sat. It wasn’t the target. It was our own headless testing setup, no display and no krb5 config, that made +auth-only lie to us and a full connection need a virtual framebuffer to even attempt the handshake. A pentester sitting at their own Kali desktop with a real X session would never have hit either problem. This isn’t the deployment-cost story Part 9’s socat found on the target side. It’s a lesson about trusting a diagnostic flag’s exit code over what the target’s own logs actually say.

Once it actually connects, Wazuh’s read on it is the most precise of the three tools in this post:

Rule: 92653 (level 3) -> 'User: WORKGROUP\Administrator logged using Remote Desktop Connection (RDP) from ip:10.10.10.5.'
Logon Type: 10

Logon Type 10, RemoteInteractive, is RDP’s own fingerprint, and Wazuh’s rule for it says exactly what happened, correctly, every time. Low severity (level 3), but accurate.

evil-winrm: fast, clean, and generically labeled

$ time evil-winrm -i 10.10.10.50 -u Administrator -p 'Summer2026!'
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
target-win2022\administrator
*Evil-WinRM* PS C:\Users\Administrator\Documents> exit
real    21.15s

No drama. Connects, authenticates, runs the command, returns the answer, exits clean. Every evil-winrm session in this test showed the same Windows Security Event Log pattern already established in Part 7: Logon Type 3, NTLM, and Wazuh’s generic pass-the-hash heuristic:

Rule: 92652 (level 6) -> 'Successful Remote Logon Detected... possible pass-the-hash attack.'

One of the two sessions in this test got a variant of that rule with an extra line appended: “Possible RDP connection. Verify that kali1 is allowed to perform RDP connections.” This was a WinRM session, not RDP, on port 5985 the whole way. Part 7 flagged this exact labeling quirk on SMB traffic; here it’s the same canned RDP-verification line firing on a completely different protocol. The structured logonType field says 3 both times. The prose is the part that isn’t trustworthy.

What actually distinguishes these three

MethodReal timeResultWazuh ruleLevelLogon TypeLabel accuracy
psexec103.87sFailed (Defender quarantine)92650 (service-install pattern)12n/a (never completed)Correct, and doesn’t need Defender
Manual RDP~3s to shell (once fixed)Succeeded92653310Correct
evil-winrm21.15sSucceeded92652 / 9265763Generic, sometimes mislabeled

Three tools, three completely different detection stories, and none of them line up with “modern is quieter.” psexec is the loudest thing in this whole series so far, caught twice over by two independent mechanisms that don’t even need to talk to each other. RDP is the quietest by severity level, but the one alert it does generate is the most precisely worded of the three. evil-winrm sits in the middle: it worked cleanly and fast, but the alert it trips is a generic NTLM heuristic that can’t actually distinguish it from SMB traffic, and occasionally attaches a wrong protocol guess to its own message text.

The honest overall picture for this pair is that WinRM has now proven itself the most reliable execution channel in this lab three times over (this post, the Wazuh agent’s own MSI install, and Part 9’s sshd enablement), while carrying the least specific detection signature of the three. Whether that’s a real advantage or a coincidence of this one lab’s default audit policy is exactly the kind of question this series keeps landing on, and exactly why it’s worth checking rather than assuming.