コンテンツにスキップ

技術目次へ戻る

Kerberos では、クライアントが KDC から TGT とサービスチケットを順に受け取り、 そのチケットでサービスに認証します。このページは、Impacket がその交換を どう組み立て、どの鍵で各メッセージを処理するかをコードから追います。 AD での認証全体と SPN の扱いはKerberos 認証の解説を参照してください。

impacket/krb5/ は RFC 4120 に [MS-KILE] / [MS-PAC] / [MS-SFU] を足した クライアント実装です。ASN.1 は pyasn1、暗号は RFC 3961/3962/4757 です。

モジュール責務
constants.pyメッセージ番号、PA-DATA、KDC option、enctype
asn1.pyAS/TGS/AP、PA-DATA、KRB-CRED、S4U、dMSA
types.pyPrincipal、Ticket、KerberosTime
crypto.pystring-to-key、encrypt/decrypt、checksum、Key
kerberosv5.pygetKerberosTGT / getKerberosTGS / GSS Type1/Type3
pac.pyPAC buffer と sign_pac
ccache.pyMIT ccache と kirbi (KRB-CRED)
gssapi.pyAP-REQ checksum、WRAP/MIC
keytab.pyMIT keytab
kpasswd.pyRFC 3244、TCP 464

関連コマンド: getTGT、getST、 GetUserSPNs、GetNPUsers、 ticketer、describeTicket

KDC 通信は sendReceive() です。TCP、先頭 4 byte が big-endian 長です。 KRB_ERROR のうち KDC_ERR_PREAUTH_REQUIRED (25) だけを通常応答として返し、 それ以外は KerberosError になります。

getKerberosTGT(clientName, password, domain, lmhash, nthash, aesKey='',
kdcHost=None, requestPAC=True, serverName=None,
kerberoast_no_preauth=False, timeout=None)
→ (tgt_bytes, cipher, client_key, sessionKey)

最初の AS-REQ は未認証で、PA_PAC_REQUEST だけを付けます。 sname は既定 krbtgt/DOMAIN。serverName を渡すと AS-REQ で別 SPN を 要求できます (kpasswd の kadmin/changepw、no-preauth roast)。

etype 選択:

入力最初に出す etype
NT hash ありRC4 (23) のみ
AES key 32 byteAES256 (18)
AES key 16 byteAES128 (17)
password のみAES256。KDC_ERR_ETYPE_NOSUPP なら RC4

KDC が METHOD_DATA を返すと PA_ETYPE_INFO2 (なければ PA_ETYPE_INFO) から etype → salt を取り、cipher.string_to_key(password, salt) で 長期鍵を作ります。2 回目の AS-REQ に PA_ENC_TIMESTAMP (key usage 1) を 付けます。

UF_DONT_REQUIRE_PREAUTH のとき、最初の応答がそのまま AS-REP になります。 enc-part は依然としてクライアント長期鍵 (usage 3) です。復号に失敗し kerberoast_no_preauth=True なら、session key 無しで生 AS-REP を返します (AS-REP roasting)。

password だけの経路で 2 回目が KDC_ERR_ETYPE_NOSUPP なら、LM/NT hash を 計算して再帰します (RC4 fallback)。

getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey,
renew=False, etypes=None, timeout=None)

tgt は AS-REP でも TGS-REP でも構いません (referral 追従)。

  1. TGT を入れた AP-REQ。Authenticator は TGS session key、usage 7
  2. それを PA_TGS_REQ として TGS-REQ に載せる
  3. option: forwardable | renewable | renewable_ok | canonicalize (renew=True なら renew も)
  4. etype: 既定では RC4、AES256、AES128、DES3、DES-MD5。 etypes を渡すと提示順と種類を指定できる
  5. TGS-REP enc-part を usage 8 で復号 → 新しい session key
  6. 返った sname が要求と違えば referral として再帰

S4U と U2U はこの関数にはありません。 examples/getST.py と getPac.py / ticketer.py が ASN.1 を直接組みます。

crypto.py の公開 API: Key、string_to_key、encrypt、decrypt、 make_checksum、verify_checksum、cf2、generate_kerberos_keys。

クラスetype鍵長string-to-key
_DESCBC38MIT DES + salt
_DES3CBC1624n-fold(password+salt)
_AES128CTS1716PBKDF2-HMAC-SHA1、既定 4096 回、derive(..., b'kerberos')
_AES256CTS1832同上、32 byte seed
_RC42316salt 無視。MD4(UTF-16LE(password)) = NT hash

AES/DES3 は RFC 3961 簡略プロファイルです。Ke は usage || 0xAA、 Ki は usage || 0x55。暗号文は confounder + HMAC-SHA1 切り詰め 12 byte。 RC4 (RFC 4757) は usage 3→8、23→13 に読み替えます。

よく使う key usage:

Usage場所
1AS-REQ PA_ENC_TIMESTAMP
2Ticket enc-part (サービス長期鍵)。getST の force-forwardable
3AS-REP enc-part
7TGS-REQ Authenticator
8TGS-REP enc-part
11AP-REQ Authenticator
12AP-REP enc-part
13KRB-PRIV (kpasswd)
17S4U PA_FOR_USER HMAC-MD5

AD の典型 salt: ユーザは DOMAIN.COMuser、コンピュータは DOMAIN.COMhost + 小文字 sam。getST -force-forwardable が password から AES を出すときは DOMAIN.upper()+user をハードコードします。コンピュータ アカウントでは一致しないことがあります。

cf2() (FAST) は実装されていますが getKerberosTGT には繋がっていません。

PAC は ticket authorization-data の AD_IF_RELEVANT / AD_WIN2K_PAC です。 構造は NDR と Structure の混在です。

定数値内容
PAC_LOGON_INFO1KERB_VALIDATION_INFO (RID、group、UAC、ExtraSids)
PAC_CREDENTIALS_INFO2資格情報
PAC_SERVER_CHECKSUM6サービス鍵による署名
PAC_PRIVSVR_CHECKSUM7KDC 鍵による署名 (server checksum の上)
PAC_CLIENT_INFO_TYPE10クライアント名と時刻
PAC_DELEGATION_INFO11S4U2proxy 経由サービス
PAC_UPN_DNS_INFO12UPN / DNS。S flag で SAM+SID
PAC_CLIENT_CLAIMS_INFO_TYPE13クライアントの claims
PAC_DEVICE_INFO_TYPE14デバイス情報
PAC_DEVICE_CLAIMS_INFO_TYPE15デバイスの claims
PAC_ATTRIBUTES_INFO17PAC 属性
PAC_REQUESTOR_INFO18要求者 SID

sign_pac() は両方の checksum をゼロ埋めしてからシリアライズし、 server checksum を PAC 全体、KDC checksum を server 署名だけに取ります。 checksum type は KERB_NON_KERB_CKSUM_SALT (17)。AES か HMAC-MD5 かは SignatureType または AES 鍵長から決めます。

実装の中心は GETST.doS4U です。

S4U2self

  1. 呼び出し元 TGT の PA_TGS_REQ
  2. 追加 PA-DATA:
    • 既定: PA_FOR_USER。S4UByteArray = LE32(NT_PRINCIPAL) || user || realm || 'Kerberos' を session key、usage 17、HMAC-MD5 で署名
    • -dmsa: PA_S4U_X509_USER。TGS-REP の encrypted_pa_data に KERB_DMSA_KEY_PACKAGE が付くことがある
  3. sname は呼び出し元自身 (自分宛ての ticket)
  4. -self ならここで止まる

U2U (-u2u): enc_tkt_in_skey を立て、呼び出し元 TGT を additional-tickets に入れる。ticket enc-part が TGT session key で 暗号化されるため、サービス鍵無しで PAC を読める (getPac)。

S4U2proxy

  • option: cname_in_addl_tkt | canonicalize | forwardable | renewable
  • PA_PAC_OPTIONS に resource_based_constrained_delegation
  • additional-tickets = S4U2self (または -additional-ticket) の ST
  • sname = 最終 SPN

-force-forwardable は S4U2self ticket をサービス長期鍵 (usage 2) で復号し、 forwardable を立てて再暗号化します。サービス鍵が本当に手元にあることが 前提です。

形式実体
ccacheMIT FILE:。version 3/4 (0x0503 / 0x0504)。v1/v2 は未実装
kirbiMimikatz の KRB-CRED (msg-type 22)。enc-part.etype=0 で
EncKrbCredPart を平文格納

CCache.fromTGT / fromTGS が enc-part を復号して credential を埋めます。 Credential.toTGT / toTGS はダミー enc-part 付きの偽 AS-REP/TGS-REP を 作り、getKerberosTGS が ticket + session key を再利用できるようにします。

CCache.parseFile(domain, user, target) は KRB5CCNAME を読み、 対象 SPN の TGS を優先、無ければ krbtgt/DOMAIN@DOMAIN を返します。

相互変換は ticketConverter。 Impacket が保持するフィールド範囲では second ticket / address は使いません。

getKerberosType1 は host/<target> の TGS を取り、SPNEGO NegTokenInit に AP-REQ を載せます。Authenticator checksum type は 0x8003 (CheckSumField: Lgth=16、Bnd[16]、Flags)。 DCERPC では GSS_C_CONF|INTEG|SEQUENCE|REPLAY|MUTUAL|DCE_STYLE。 LDAP の LDAPS では Bnd に TLS CBT の MD5 を入れます。

WRAP: RC4 は RFC 4757 (TOK_ID 0x0102)、AES は RFC 4121 (0x0504、 RRC=28、usage 24/22)。LDAP signing は GSS_Wrap_LDAP で MechIndepToken (OID 1.2.840.113554.1.2.2) に包みます。

KDC から得た ticket と、手元の長期鍵で作る ticket は別経路です。

経路必要な鍵実装
Goldenkrbtgt の AES または NT hashticketer が PAC を組み立て sign_pac
Silver対象サービスの長期鍵同上。sname をサービスに合わせる
Sapphire / U2U PAC呼び出し元 TGT session keyS4U2self + U2U で本物 PAC を取得し改変
MS14-068署名検証の欠落goldenPac。改変 PAC を含む TGS
Key ListRODC krbtgt_XXXXX の AESkeylistattack、KERB_KEY_LIST_REQ (PA 161)

ticketer は KERB_VALIDATION_INFO の RID、group、ExtraSids (SIDHistory)、 UAC を埋め、server/KDC checksum を対応する鍵で署名します。 raiseChild は child の krbtgt から forest 側の信頼経路を辿り、 SIDHistory を含む ticket を作ります。

これらは getKerberosTGT の出力を「編集する」処理ではありません。 PAC の buffer 順、checksum の入れ子、ticket flag、crealm/sname が サービス側の検証と一致する必要があります。

  • kpasswd: TCP 464、protocol 0xFF80、TGT SPN kadmin/changepw。 AP-REQ (usage 11、乱数 subkey) + KRB_PRIV (usage 13) に ChangePasswdData。changePassword は本人変更、setPassword は管理者 reset。
  • keytab: MIT v0x0502。getKey は AES256 → AES128 → RC4 の順。 loadKeysFromKeytab は CLI の -aesKey または -hashes へ展開します。
  • etype リストと fallback 順を変えると、後続 TGS が落ちることがある
  • PAC 署名は server → KDC の順。片方だけ直さない
  • S4U の PA-DATA と additional-tickets を getKerberosTGS に無理に混ぜない
  • clock skew、salt 不一致、KDC_ERR_ETYPE_NOSUPP を一般例外へ畳み込まない
  • 関連テスト: tests/misc/test_ccache.py、test_krb5_crypto.py、test_krb5_gssapi.py