DPAPI / SAM / LSA / NTDS
Windows の秘密情報は、SAM や LSA、NTDS、DPAPI など保存場所と保護方法が 異なります。ここでは Impacket が材料をどこから取得し、どの実装で復号するかを 追います。端末上で資格情報がどこに残るかは Windows の資格情報の解説を参照してください。
秘密情報は「取得経路」と「復号器」が分かれています。CLI は
secretsdump がオーケストレーション、
実復号は impacket/examples/secretsdump.py
です。DPAPI 単体は dpapi.py /
dpapi_ng.py と
dpapi コマンド です。
flowchart TB
SYS["SYSTEM hive class: JD Skew1 GBG Data"] --> BK["boot key"]
BK --> SAMK["SAM hashed boot key"]
BK --> LSAK["LSA encryption key / PolEKList"]
BK --> PEK["NTDS PEK"]
SAMK --> UH["ユーザ LM/NT hash RID-DES または AES"]
LSAK --> SEC["LSA Secrets / NL$KM / cached logon"]
PEK --> NTDS["NTDS hash / Kerberos key / trust key"]
DPAPI_SYS["DPAPI_SYSTEM in LSA"] --> MK["DPAPI Master Key"]
UserKey["SID + password または NT/SHA1"] --> MK
DomainPVK["domain backup private key BKRP"] --> MK
MK --> Blob["DPAPI_BLOB / Credential / Vault"]
新しい取得方法 (VSS、WMI shadow、Key List) は decoder の中に埋め込まず、 同じ raw record 契約へ接続します。
Boot key
Section titled “Boot key”LocalOperations.getBootKey() / RemoteOperations の同等処理:
Select\CurrentからControlSet00Nを決めるControl\Lsa\{JD,Skew1,GBG,Data}の クラス名 (UTF-16 hex 16 文字) を連結- 並べ替え
[8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7]
.reg テキストにはクラス名が無いので boot key を計算できません。
secretsdump -system が binary REGF を要求するのはこのためです。
NoLmHash ポリシーは同じ ControlSet の Control\Lsa\NoLmHash です。
SAMHashes が SAM\Domains\Account を読みます。
- ドメイン鍵は
F値 (DOMAIN_ACCOUNT_F)。古い RC4 (SAM_KEY_DATA) と AES (SAM_KEY_DATA_AES) がある。RC4 経路の定数文字列は!@#$%^&*()qwerty...と0123456789012345678901234567890123456789 - ユーザは RID キー配下の
V(USER_ACCOUNT_V)。hash は RID からCryptoCommon.deriveKeyで作った 2 つの DES 鍵、または AES で保護される SamDecryptNTLMHash/transformKeyはcrypto.py([MS-SAMR] 2.2.11.1.1)
出力は domain\user:rid:lmhash:nthash::: です。history は別エントリです。
LSA secrets とキャッシュログオン
Section titled “LSA secrets とキャッシュログオン”LSASecrets は SECURITY hive を boot key で開きます。
- 古いホスト:
PolSecretEncryptionKey - 新しいホスト:
PolEKList(AES) Policy\Secrets\*\CurrVal(LSA_SECRET/LSA_SECRET_XP)。_SC_*(サービス password)、$MACHINE.ACC、DPAPI_SYSTEM、NL$KMなどがここに入る- cached logon は
CacheのNL_RECORD。NL$KMで復号。Vista 以降は DCC2 (NL$IterationCount)
regsecrets は NTDS を触らず、この SAM + LSA 経路だけを remote registry
から取ります。
NTDSHashes は 2 通りの入力を同じ論理レコードへ正規化します。
| 経路 | 材料 | 特徴 |
|---|---|---|
ESE (-ntds / VSS) | ntds.dit | ese.py でテーブルを読む |
| DRSUAPI | IDL_DRSGetNCChanges | ファイルをコピーしない。resume file で cursor を保持 |
| Key List | RODC krbtgt AES + KERB_KEY_LIST_REQ | 許可されたアカウントの長期鍵 |
PEK (Password Encryption Key) は boot key で保護されています。
pekList の先頭で世代が分かれます。
| ヘッダ | OS 目安 | 解き方 |
|---|---|---|
\x02... | 2012 R2 以前 | MD5(bootkey + KeyMaterial を 1000 回) + RC4 → PEK 列 |
\x03... | 2016 以降 | AES(bootKey, IV=KeyMaterial) → (index, 16-byte PEK)* |
各アカウントの NT/LM hash は PEK 層 (RC4。header 8–10 byte が PEK index)
を剥がしたあと、RID 由来 DES をもう一段外します。2016 以降の一部は
AES です。supplementalCredentials には Kerberos AES/DES key、WDigest、
平文 password が入ることがあります。trust は TDO の auth info から
inter-realm 鍵 (AES + RC4) を導出します (-trust-keys)。
AES 導出は FQDN salt {REALM_FQDN}krbtgt{PARTNER_FQDN} に加え、
NetBIOS/flat 名が分かるときはその flat 名で (trust account) 鍵も出します。
flat 名が無いときは DNS ラベルから推測せず、trust-account 鍵を省略します。
DRSUAPI は属性 ID 単位で来るため、欠落属性を「hash が空」と決めつけない
ことが必要です。-just-dc-user / -ldapfilter / -skip-user は取得と
出力の両方に効きます。
パスワードが直接すべての secret を守るのではなく、master key が中間に入ります。
| 構造 | ファイル / 場所 | 復号に使うもの |
|---|---|---|
MasterKeyFile / MasterKey | Protect\<SID>\GUID | SID+password、NT/SHA1、DPAPI_SYSTEM、domain PVK |
DPAPI_BLOB | Credential、Vault 属性、汎用 blob | master key の SHA1 など |
CREDHIST_FILE | CREDHIST | 過去の user key チェーン |
VAULT_VPOL / VAULT_VCRD | Policy / Credential | vpol の Vault key → vcrd 属性 |
PREFERRED_BACKUP_KEY | LSA / BKRP | domain RSA backup key |
DPAPI_SYSTEM | LSA secret | マシン / ユーザ machine key |
deriveKeysFromUser(sid, password) は 3 候補を出します。
- HMAC-SHA1(SHA1(UTF-16 password), SID+\0)
- HMAC-SHA1(MD4(UTF-16 password), SID+\0) — NT hash 経路
- Protected Users 用 PBKDF2-SHA256 2 段 + HMAC-SHA1
GUID で blob と master key を対応付けます。MAC が合わない平文候補は 成功として出しません。
Windows LAPS / DPAPI-NG は dpapi_ng.py と
GKDI (GkdiGetKey) です。流れは次です。
- LDAP の暗号化属性 →
EncryptedPasswordBlob+KeyIdentifier(root key id、L0/L1/L2) - 対象 SID の SD を付けて GKDI RPC
GroupKeyEnvelopeから KEK (FFC DH または ECDH、SP 800-108)- AES unwrap で CEK、その CEK で password を復号
GetLAPSPassword が
この境界 (LDAP → CMS → GKDI → DPAPI-NG) を跨ぎます。legacy LAPS の
ms-Mcs-AdmPwd は平文属性なので GKDI は使いません。
domain backup key は dcerpc.v5.bkrp で remote 取得できます
(dpapi.py backupkeys)。PVK / PKCS#1 への変換は
privatekeyblob_to_pkcs1 です。
取得経路 (remote)
Section titled “取得経路 (remote)”RemoteOperations が材料を集めます。
| 方法 | 何をするか | 副作用 |
|---|---|---|
| Remote Registry | hive を save | 一時ファイル |
VSS / ntdsutil | snapshot | サービス・shadow |
WMI shadow (-use-remoteSSWMI) | 遠隔 snapshot から SAM/SYSTEM/SECURITY(/NTDS) をダウンロード | snapshot |
| DRSUAPI | 複製 | DC 負荷、replication 監査 |
| Key List | RODC 番号 + AES | Kerberos 監査 |
cleanup() はサービス、一時ファイル、resume 状態を例外経路でも回収します。
変更時の確認
Section titled “変更時の確認”- boot key のクラス名読みと並べ替えを崩さない
- AES と RC4 の SAM/LSA/PEK 形式を片方の仮定で読まない
- 出力スキーマ (SAM / cached / ntds / trust) を混ぜない
- debug ログに復号済み hash / key を足さない
- 関連テスト:
tests/SMB_RPC/test_secretsdump.py

