fortra / impacket

Impacket is a collection of Python classes for working with network protocols.
https://www.coresecurity.com
Other
13.52k stars 3.58k forks source link

SMB auth: ACCESS_DENIED on second authentication using same host with SMB signing enabled #837

Closed mpgn closed 4 years ago

mpgn commented 4 years ago

Configuration

impacket version: v0.22 Python version: 3.7/3.8 Target OS: Windows 10/2016 with SMB signing enabled

We have an issue on Crackmapexec when we try multiple connections on the same host when SMB signing is enabled (Required). All auth after the first one failed with an ACCESS_DENIED.

https://github.com/byt3bl33d3r/CrackMapExec/issues/321

Debug Output With Command String

Running two authentications on the same host failed with SMB signing enabled, PoC with the following Python code

from impacket.smbconnection import SMBConnection, SessionError

host_smb_signing_disabled = '192.168.255.135'
host_smb_signing_enabled = '192.168.255.131'

def auth(ip):
    try:
        conn.login('administrator', 'Password@123', 'GOLD.LOCAL')
        print('[+] AUTH OK', ip)
    except SessionError as e:
        error, desc = e.getErrorString()
        print("[-] AUTH NOK", ip, "with error", error)

conn = SMBConnection(host_smb_signing_enabled, host_smb_signing_enabled, None, 445)
if conn.isSigningRequired():
    print("SMB SIGNING ENABLED: SECOND AUTH FAILED")
    auth(host_smb_signing_enabled)
    auth(host_smb_signing_enabled)

print('')
conn = SMBConnection(host_smb_signing_disabled, host_smb_signing_disabled, None, 445)
if conn.isSigningRequired() == False:
    print("SMB SIGNING DISABLED: SECOND AUTH OK")
    auth(host_smb_signing_disabled)
    auth(host_smb_signing_disabled)

Result:

bonclay@kali:~/impacket$ python3 /tmp/demo.py 
SMB SIGNING ENABLED: SECOND AUTH FAILED
[+] AUTH OK 192.168.255.131
[-] AUTH NOK 192.168.255.131 with error STATUS_ACCESS_DENIED

SMB SIGNING DISABLED: SECOND AUTH OK
[+] AUTH OK 192.168.255.131
[+] AUTH OK 192.168.255.131

Additional infos

Starting point (and probably related to SMBsign function) https://github.com/SecureAuthCorp/impacket/blob/f2546a0bc54e9df11b3a7f225af069125218d359/impacket/smb.py#L3231

mpgn commented 4 years ago

Wireshark diff between auth1 and auth2

auth1 OK (sign enabled) image

auth2 NOK (sign enabled) image

Also at this line: https://github.com/SecureAuthCorp/impacket/blob/f2546a0bc54e9df11b3a7f225af069125218d359/impacket/smb.py#L2589

self._SigningChallengeResponse is empty b''

asolino commented 4 years ago

Thanks for the report @mpgn .. Is that happening only with SMB.DIALECT?

mpgn commented 4 years ago

Hello @asolino I simplify the PoC to remove the SMB.DIALECT, second auth is still failing.

mpgn commented 4 years ago

Hello @asolino

So by just logoff the user and reconnect him, the problem is gone. Maybe it was just expected maybe not, feel free to close the issue if you think it's normal behavior that the second auth failed unless logoff :)

from impacket.smbconnection import SMBConnection, SessionError

host_smb_signing_disabled = '192.168.255.136'
host_smb_signing_enabled = '192.168.255.131'

def auth(ip):
    try:
        conn.login('administrator', 'Password@123', 'GOLD.LOCAL')
        print('[+] AUTH OK', ip)
    except SessionError as e:
        error, desc = e.getErrorString()
        print("[-] AUTH NOK", ip, "with error", error)

conn = SMBConnection(host_smb_signing_enabled, host_smb_signing_enabled, None, 445)
if conn.isSigningRequired():
    print("SMB SIGNING ENABLED: SECOND OK")
    auth(host_smb_signing_enabled)
    conn.logoff()
    conn = SMBConnection(host_smb_signing_enabled, host_smb_signing_enabled, None, 445)
    auth(host_smb_signing_enabled)

print('')
conn = SMBConnection(host_smb_signing_disabled, host_smb_signing_disabled, None, 445)
if conn.isSigningRequired() == False:
    print("SMB SIGNING DISABLED: SECOND AUTH OK")
    auth(host_smb_signing_disabled)
    auth(host_smb_signing_disabled)
asolino commented 4 years ago

Thanks for the research @mpgn. Yup, logoff() clears a lot of variables that surely affect the signing process, but just for SMB2. You sure you're not experiencing the original issue anymore with SMB.DIALECT? I might be missing something here.

Reopen if problem still persists.