コンテンツにスキップ

SMB / NetBIOS

技術目次へ戻る

Impacket の SMB は「パケットを組み立てるライブラリ」と「セッション実装」の 両方です。CLI のほとんどは SMBConnection だけを使い、dialect 差は内側に 閉じます。

モジュール役割
nmb.pyNetBIOS 名前解決とセッションフレーミング
smb.pySMB1 (NT LM 0.12)、\xffSMB
smb3.py + smb3structs.pySMB2 および SMB3、\xfeSMB / 暗号時 \xfdSMB
smbconnection.pydialect 透過のクライアント facade
smbserver.py検証用サーバ (SMBSERVER / SimpleSMBServer)

関連コマンド: smbclient、smbserver、DumpNTLMInfo、psexec、ntlmrelayx

445 でも NetBIOS session message (type 0x00) で包みます。139 だけ SESSION REQUEST (0x81) が先行し、*SMBSERVER は NBSTAT で実名を取ります。

ポート定数: SMB_SESSION_PORT=445、NETBIOS_SESSION_PORT=139、 NETBIOS_NS_PORT=137。

SMBConnection.negotiateSession() は preferred dialect が無いとき、 SMB1 SMB_COM_NEGOTIATE に次を載せます。

NT LM 0.12 / SMB 2.002 / SMB 2.???

139 では SMB 2.??? を省略します。応答先頭が \xfe なら SMB2/3、 それ以外は SMB1 に固定します。

smb3.SMB3.negotiateSession() は [MS-SMB2] の Connection 状態を持ちます。

  • 提示 dialect: 指定が無ければ 0x0202 / 0x0210 / 0x0300 / 0x0302 / 0x0311
  • 3.1.1 がある場合: Preauth Integrity (SHA-512) と Encryption (AES-128-GCM、AES-128-CCM) の negotiate context
  • サーバが SIGNING_REQUIRED、または dialect が 3.1.1 なら RequireSigning
  • dialect ≥ 3.0 でパケットクラスを SMB3Packet へ切替 (Status が request では ChannelSequence になる)

3.1.1 では AES-128-GCM を優先し、AES-128-CCM も提示します。 3.0 / 3.0.2 は暗号方式のネゴシエーションがなく、AES-128-CCM を使います。 圧縮は扱いません。

どちらも SPNEGO の中に NTLM または Kerberos AP-REQ を載せます。

経路入口要点
NTLMlogin()Type1 → Type2 → Type3。exportedSessionKey が署名・暗号の起点
KerberoskerberosLogin()cifs/<ServerName> の TGS。KDC_ERR_ETYPE_NOSUPP では NT hash に落として再試行
SMB1 旧式login_standard()extended security が無いときの DES(challenge, LM/NT hash)

SMB1 の extended login 中は一時的に Unicode を落とします。 ntlmFallback は SMB1 だけで、NativeLanMan が Windows 2000 / Samba のときに NTLMv1 へ下がります。

signSMB():

SecurityFeatures = LE64(seq)
MD5(SigningSessionKey || SigningChallengeResponse || packet)[:8]
seq += 2

NTLMv2 の exported key では challenge-response 部分は空です。

dialect署名
2.0.2 / 2.1HMAC-SHA256(SessionKey, packet)[:16]
3.xAES_CMAC(SigningKey, packet) (crypto.AES_CMAC)

3.x の鍵導出は crypto.KDF_CounterMode (HMAC-SHA256、128 bit) です。

鍵3.0 / 3.0.23.1.1
SigningKeyLabel SMB2AESCMAC\0, Context SmbSign\0Label SMBSigningKey\0, Context = PreauthHash
ApplicationKeySMB2APP\0 / SmbRpc\0SMBAppKey\0 / PreauthHash
EncryptionKey (C2S)SMB2AESCCM\0 / ServerIn \0SMBC2SCipherKey\0
DecryptionKey (S2C)SMB2AESCCM\0 / ServerOut\0SMBS2CCipherKey\0

dialect ≥ 3.0 かつサーバが GLOBAL_CAP_ENCRYPTION を出し、guest/anonymous でなければ、クライアント側で SMB2_SESSION_FLAG_ENCRYPT_DATA を強制します。 暗号化 PDU は \xfdSMB の SMB2_TRANSFORM_HEADER と、 ネゴシエーションで選んだ AES-128-GCM または AES-128-CCM です。

RPC over SMB3 は getSessionKey() が返す ApplicationKey を使います。 生の NTLM session key ではありません。

connectTree() は \\host\SHARE を作り、TreeID を保持します。 DCERPC の典型経路は次です。

  1. connectTree('IPC$')
  2. 必要なら waitNamedPipe (SMB1 TRANS_WAIT_NMPIPE または FSCTL_PIPE_WAIT)
  3. create / nt_create_andx で \pipe\<name> を開く
  4. transactNamedPipe (TRANS_TRANSACT_NMPIPE=0x26) または FSCTL_PIPE_TRANSCEIVE=0x0011C017

共有一覧 listShares() は SMB1 LANMAN ではなく、同じセッション上の srvsvc RPC(NetrShareEnum info level 1)です。listSharesWithPrivs() は info level 502 で共有の privilege 欄を返し、管理者権限が必要です。 SMB3 クライアントの list_shared は未実装です。

SimpleSMBServer / SMBSERVER:

  • SMB1 は NT LM 0.12。extended security では NTLMSSP を提示
  • SMB2/3 応答 dialect は 2.0.2、2.1、3.1.1。3.1.1 では preauth hash と AES-128-GCM / AES-128-CCM の暗号化に対応
  • 資格情報ストアが空なら SMB1 標準セキュリティは成功扱いになる経路がある
  • registerNamedPipe で in-process DCERPC (srvsvc / wkssvc) を載せられる
  • hook (hookSmbCommand / hookSmb2Command) は karmaSMB などが使う

SMB 3.0 / 3.0.2 とマルチチャネルなど、実装範囲外の機能は個別に確認してください。

  • Oplock break とマルチチャネル bind は未実装。compound request の一部は処理するが、全パターンの対応を前提にしない
  • transform 復号では GCM / CCM の認証 tag を検証する
  • クライアントの暗号化 nonce は AES-CCM で 11 文字、AES-GCM で 12 文字の ASCII 文字列を random.choice で作り、CSPRNG を使っていない
  • negoex は SMB login に繋がっていない
  • dialect 分岐を SMBConnection の外へ漏らさない
  • 署名シーケンス、preauth hash、Tree ごとの EncryptData を壊さない
  • 新しい create option / info class は SMB1 と SMB2 の両方の定数を確認する
  • 関連テスト: tests/SMB_RPC/