Skip to content

SMB3.kerberosLogin(mutualAuth=True) uses the full AP-REP subkey as Session.SessionKey instead of its first 16 bytes (breaks AES-256 encrypted sessions) #2257

Description

@0xRyuzak1

SMB3.kerberosLogin(mutualAuth=True) uses the full AP-REP subkey as Session.SessionKey instead of its first 16 bytes (breaks AES-256 encrypted sessions)

Description

In impacket/smb3.py, SMB3.kerberosLogin() with mutualAuth=True sets Session.SessionKey to the entire AP-REP sub-session key returned by the server. Per [MS-SMB2] §3.2.5.3, Session.SessionKey MUST be the first 16 bytes of the key obtained from the GSS context. The sibling (non-mutual) branch a few lines below already does this correctly with [:16].

For an AES-256 service ticket the sub-session key is 32 bytes, so Session.SessionKey becomes 32 bytes instead of 16. All SMB3 signing/encryption keys are then derived (KDF_CounterMode) from the wrong input, and against a server that requires SMB signing/encryption the session fails immediately after login (the server rejects/resets the first protected request). AES-128 tickets happen to work only because the key is already 16 bytes.

Affected code

impacket/smb3.py, SMB3.kerberosLogin() (line numbers as of master @ 8ea54feb; identical in the 0.13.1 release):

880:                 apCipher = _enctype_table[int(encAPRepPart['subkey']['keytype'])]()
881:                 apSessionKey = Key(apCipher.enctype, encAPRepPart['subkey']['keyvalue'].asOctets())
882:
883:                 sequenceNumber = int(encAPRepPart['seq-number'])
884:                 self._Session['SessionKey'] = apSessionKey.contents        # <-- full key (32 B for AES-256)
885:
886:             else:
887:                 self._Session['SessionKey']  = sessionKey.contents[:16]    # <-- correct: first 16 bytes

Note the inconsistency between line 884 (mutual-auth branch, full key) and line 887 (non-mutual branch, [:16]).

Steps to reproduce

Against a DC/server that issues AES-256 tickets and requires SMB signing or encryption:

from impacket.smbconnection import SMBConnection

c = SMBConnection(dc_host, dc_host)
c._SMBConnection.kerberosLogin(user, '', domain, kdcHost=kdc_ip,
                               useCache=True, mutualAuth=True)
c.connectTree('IPC$')   # first protected op -> server resets / rejects the session

With an AES-128 ticket the same flow works, which isolates the cause to the key length.

Expected behavior

Session.SessionKey is the first 16 bytes of the AP-REP sub-session key ([MS-SMB2] §3.2.5.3), so the derived signing/encryption keys match the server and the mutual-auth session works for all supported enctypes (including AES-256).

Actual behavior

The mutual-auth session negotiates successfully but the first signed/encrypted request fails; typical symptom is a connection reset ([Errno 104]) or an SMB error immediately after kerberosLogin, only when the ticket enctype is AES-256.

Suggested fix

Truncate to 16 bytes, matching the non-mutual branch and the spec:

                 sequenceNumber = int(encAPRepPart['seq-number'])
-                self._Session['SessionKey'] = apSessionKey.contents
+                # [MS-SMB2] 3.2.5.3: Session.SessionKey is the first 16 bytes of the GSS key.
+                self._Session['SessionKey'] = apSessionKey.contents[:16]

Environment

  • Impacket: confirmed present in the latest release 0.13.1 (tag impacket_0_13_1, 2026-05-15) and on master (8ea54feb).
  • Python: 3.12
  • File: impacket/smb3.py
  • Reference: [MS-SMB2] §3.2.5.3 (Session.SessionKey = first 16 bytes of the GSS key).

Metadata

Metadata

Labels

in reviewThis issue or pull request is being analyzed

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions