Sep 17, 2026BY Papya
TEEIntel TDXAMD SEV-SNPConfidential Computingpublic

DDRop DDR5 Write를 지워서 Intel TDX와 AMD SEV SNP를 공격하기 CCS26 논문 리뷰

ACM CCS 2026에 발표될 예정인 DDRop: Active Memory Interposer Attacks on Confidential VMs by Dropping DDR5 Writes 논문에 대해 소개한다. 스위스 ETH Computer Security Group에서 연구한 내용이다.
논문 제목 그대로 DDR5 memory에 대한 write를 drop시키는 physical memory interposer를 만들고, 이를 이용해서 Intel TDX, Intel Scalable SGX, AMD SEV-SNP의 memory protection을 공격한다.
이 논문에서 가장 흥미로운 부분은 CPU가 새로운 데이터를 DRAM에 썼다고 생각하게 만든 뒤, 실제 DRAM에는 이전 데이터가 그대로 남도록 한다.
그리고 최신 scalable TEE들의 memory encryption에는 freshness가 없다는 점을 이용한다.

[0] 요약

Intel TDX나 AMD SEV-SNP 같은 Confidential Computing 기술은 Hypervisor나 Host OS가 악성이라고 하더라도 VM의 private memory를 직접 읽거나 수정하지 못하도록 한다.
Untrusted Host / Hypervisor
        ↓
   [ 접근 차단 ]
        ↓
Confidential VM
        ↓
CPU Memory Encryption
        ↓
Encrypted DDR5 Memory
문제 의식 : Memory encryption은 이 데이터가 암호화된 올바른 데이터인지는 확인할 수 있어도, 그 데이터가 가장 최근에 쓰인 데이터인지까지 항상 확인하는 것은 아니다에서 출발
DDRop 공략 지점
CPU: "NEW를 memory에 써라"
                ↓
        DDRop Interposer
                ↓
      WRITE command DROP
                ↓
DRAM: 실제로는 OLD가 그대로 남음
                ↓
CPU가 다시 READ
                ↓
OLD ciphertext는 여전히 valid
                ↓
       OLD plaintext 복구
quote 새로운 값을 조작해서 넣는 것 X, 새로운 값이 쓰이는 것을 막아서 과거의 값을 다시 살린다.

Impact

Intel TDX, Scalable SGX, AMD SEV-SNP에 적용 특히 TDX에서는
  • Confidential VM 내부에서 stale memory를 읽게 만들기
  • victim page의 plaintext를 다른 page로 copy
  • TDX의 Secure Extended Page Table(SEPT)에 malicious entry 삽입
  • victim TD의 ciphertext access
  • victim TD를 Debug Mode로 변경
  • Debug API를 통한 victim plaintext access
  • attacker-controlled TD의 attestation measurement 변조

전체 chaining

Physical Access + Privileged Host
                    ↓
        DDR5 RDIMM Interposer
                    ↓
   Command/Address Bus Manipulation
                    ↓
   Parity Error + ALERT Suppression
                    ↓
       DDR5 WRITE disappears
                    ↓
      Old Ciphertext remains
                    ↓
          No Freshness
                    ↓
       Stale Data accepted
                    ↓
   Trusted Memory API Manipulation
          ↓                 ↓
   Page Relocation      SEPT Injection
          ↓                 ↓
   Plaintext Copy     Arbitrary Mapping
                            ↓
              ┌─────────────┴────────────┐
              ↓                          ↓
        Victim Debug Mode        Attestation Spoofing
              ↓
       Victim Plaintext
핵심 : write를 없애서 old state를 되살린다 6cb0e3ee-d2c8-46e3-baa8-1c3c6eda66a1.png 어디에 DDRop가 붙는진 확인 가능

[1] Background

Confidentiality

DRAM에 plaintext를 그대로 두지 않고 CPU 내부에서 암호화 누군가 memory bus를 probe하거나 DIMM의 내용을 읽어도 plaintext SECRET을 바로 볼 수 없음
  • Intel TDX는 TME-MK 기반 AES-XTS를 사용
  • AMD SEV-SNP는 address tweak과 per-guest key를 사용하는 AES-XEX 기반 memory encryption을 사용

Integrity

공격자가 ciphertext를 임의로 바꿨는지 확인하는 것. TDX의 optional Cryptographic Integrity mode에서는 cache line마다 ciphertext, HPA 등의 정보에 기반한 MAC을 저장한다. 따라서 공격자가 임의 ciphertext를 만들어서 넣는 것은 검출할 수 있다

Freshness

e.g., memory의 동일한 위치가 시간에 따라 아래처럼 변했다고 했을 때
t0 : A = "ADMIN=0"
t1 : A = "ADMIN=1"
각각 정상적으로 암호화되었다면 둘 다 valid ciphertext
공격자가 t1의 값을 이상하게 변조한 것이 아니라 그냥 t0의 ciphertext를 다시 가져온다면?
Expected:
t0        t1
OLD  →   NEW


Replay:
t0        t1
OLD  →   OLD
OLD 자체는 과거에 CPU가 정상적으로 생성했던 ciphertext
MAC까지 같이 과거의 정상 값이 남아 있다면 단순 integrity check만으로는 이게 정상적인 ciphertext라는 사실 은 알 수 있지만, 이게 지금 읽어야 할 최신 ciphertext인가? 를 판별할 수 없다.
freshness / replay protection의 역할이 저걸 방지해주는 건데, TDX의 optional cryptographic integrity 는 freshness를 제공하지 않는다는 것. AMD SEV-SNP 역시 cryptographic freshness가 없다.
Research Quesion
새로운 ciphertext가 DRAM까지 도착하지 못하게 하면 어떻게 될까?

[2] 기존 DDR4 공격과 다른 novelty

이전에도 DRAM과 CPU 사이에 장치를 넣어서 memory transaction을 관찰하거나 수정하는 연구가 계속 있었다.
Research방식Memory핵심
MembusterPassiveDDR4Memory bus snooping
WireTapPassiveDDR4Ciphertext side channel
TEE.failPassiveDDR5DDR5 bus observation / ciphertext side channel
BadRAMActiveDRAM metadataStatic memory alias
Battering RAMActiveDDR4Runtime dynamic alias
DDRopActiveDDR5Write suppression
d340515b-beb2-4142-b499-7a5082cfeb4e.png
그림을 보면 이해가 더 쉽다.
DDR4에서는 특정 CA(Command/Address) line을 건드려 address를 바꾸는 방식이 비교적 단순했지만, DDR5는 command가 여러 cycle에 걸쳐 encode된다. Server에서 사용하는 DDR5 RDIMM의 경우 7-bit CA bus에 걸쳐 4-cycle command encoding을 사용한다. 따라서 Battering RAM처럼 간단하게 특정 line을 grounding하면 address bit 하나만 바뀌는 것이 아니라 여러 logical bit와 command 자체가 같이 망가진다.
기존 방식의
"원래 Address A로 가는 명령을 Address B로 바꿔버리자" -> DDR5에서는 안됨
따라서 생각을 전환하여 Address를 정밀하게 바꾸기 어렵다 ↓ 그럼 command 자체를 없애면? 으로 전환. 4059502d-5dff-42cd-9cea-08d0e8e1498c.png (d) Inducing parity errors가 DDRop의 핵심

[3] DDR5의 Error Detection을 공격에 사용하기

DDR5 RDIMM에는 CPU와 실제 DRAM chip 사이에 RCD(Registering Clock Driver)가 있다. RCD는 단순 전달만 하는 것이 아니라 CA bus의 parity도 검사한다. Normal 상황
CPU
 │ WRITE command
 ▼
RCD
 │ parity OK
 ▼
DRAM
 │
 └── WRITE
parity가 잘못되면
CPU
 │ corrupted command
 ▼
RCD
 │
 ├── command reject
 │
 └── ALERT ─────────→ CPU
CPU한테 방금 command가 깨졌다라고 알리고, CPU는 command 재전송 가능 -> 이 기술을 역으로 이용

3.1 Parity Error 만들기

Interposer가 CA signal 일부를 조작해서 RCD가 command를 invalid하다고 판단하게 한다. -> 여기까지만 하면 CPU가 ALERT를 받아 다시 시도하므로 큰 의미가 없다.

3.2 ALERT도 끊기

그래서 interposer는 RCD의 ALERT signal도 CPU에 전달되지 않게 한다.
CPU
 │
 │ WRITE
 ▼
DDRop
 │
 ├── CA corruption
 │
 ▼
RCD
 │
 ├── WRITE DROP
 │
 └── ALERT ──X──> CPU
CPU 입장에서는 별일이 없는 정상적인 것으로 인지. BUT, 실제 DRAM에서는 write가 일어나지 않았다.
논문 표현 그대로 중요한 점은 parity protection을 bypass한 것이 아니라, 오히려 parity error handling을 attack primitive로 사했다는 것이다.

[4] Hardware

PCB 위의 high-frequency analog switch를 이용해 필요한 CA/CS/ALERT signal을 조작하고, Teensy 4.1 microcontroller가 이를 제어한다.
무엇보다 이전 DDR5 bus 연구와 달리 memory를 downclock하지 않는다.
연구팀은 BIOS가 선택한 기본 DDR5 frequency에서 그대로 동작시켰다. 실제 평가 장비에서는 4000, 4400, 4800 MT/s configuration을 사용했다. f282fe9c-5a06-4bc3-ae31-4fec1d3c2da9.png
Interposer PCB                  $45
Electronic parts                $30
Controller PCB                   $4
Controller parts                $40
Teensy 4.1                      $40
-----------------------------------
Total                          $159

[5] Write 사라지는 것 확인

먼저 memory page를: 0xaa 0xaa 0xaa 0xaa ... 로 채운다.
그리고 DDRop을 활성화한 상태에서: 0xbb 0xbb 0xbb 0xbb ... 를 write한다.
정상적이라면 다시 읽었을 때 전부 0xbb여야 한다. 하지만 DDRop에 의해 write가 drop된 cache line에서는 여전히: 0xaa 0xaa ... 가 나온다.
old state가 남게 됨.
그리고 TDX, SEV-SNP CVM과 Scalable SGX enclave에서도 동일한 stale-data behavior를 확인했다. 반복 실험에서도 deterministic한 결과가 나왔다.

[6] Victim을 직접 때리지 않고 Trusted API를 때리기

단순 fault injection에서 디벨롭
if, victim applicatoin 겨냥??
victim 내부 동작 파악
       ↓
정확한 physical page 찾기
       ↓
정확한 write timing 찾기
       ↓
fault
Too Application-specific
그래서 전략을 틀었음
Victim code 말고 TDX Module이나 AMD Secure Processor가 수행하는 write를 drop하면?
Intel TDX Module과 AMD Secure Processor는 malicious hypervisor 대신 CVM의 protected memory를 관리한다. 즉 hypervisor가 private plaintext를 볼 수는 없지만: "이 page를 저 physical address로 옮겨줘" 같은 요청은 trusted firmware API를 통해 할 수 있다.
이 API들은 모든 CVM에 공통적으로 존재한다.
논문은 이 standardized trusted API를 공격 대상으로 삼아서 victim-specific을 피함

[7] Page Relocation: 다른 Page의 과거를 현재로 만들기

TDX: TDH.MEM.PAGE.RELOCATE SEV-SNP: SNP_PAGE_MOVE page relocation 기능 존재
Hypervisor가 protected page를 새로운 Host Physical Address(HPA)로 옮겨 달라고 요청하면, TDX Module이나 AMD Secure Processor가 내부적으로 decrypt/re-encrypt를 처리한다.
따라서 hypervisor는 plaintext를 볼 수 없음.
e.g., GPA_A -> HPA_1 : [AAAA] 를 HPA_2로 이동한다면:
TDX Module / AMD SP

HPA_1
 [AAAA]
    │
    │ relocate
    ▼
HPA_2
 [AAAA]
여기서 Trusted component 자체가 source HPA를 반드시 지워주는 것이 아니라, 이후 정리는 untrusted host가 수행할 것으로 기대하는 구조가 있다.

7.1 DDRop과 합치기

먼저 GPA_B의 내용을 특정 HPA에 남긴다.
Target HPA
┌─────────┐
│  BBBB   │  ← valid old ciphertext
└─────────┘
그리고 GPA_A를 그 HPA로 relocate하는 순간 DDRop을 켠다.
GPA_A
  │
  │ relocation write
  ▼
DDRop
  │
  X
Target HPA
┌─────────┐
│  BBBB   │ ← 그대로 남음
└─────────┘
이제 GPA_A를 victim이 읽으면 새로 옮겨졌어야 할 AAAA가 아니라 stale contents인 BBBB를 읽게 된다.
즉 결과적으로:
GPA_B plaintext
        ↓
     [stale]
        ↓
GPA_A plaintext
와 같은 intra-VM plaintext copy primitive가 생긴다. 46b6bdb4-ccb1-494a-b4f0-d2435379f097.png
  1. GPA_B relocation → 2. Interposer Active → 3. GPA_A relocation의 세 단계가 잘 표현되어 있음.
Write Drop → victim page 사이의 plaintext copy primitive 확보함

[8] TDX SEPT Injection

Intel TDX에서는 일반 hypervisor가 guest의 GPA → HPA mapping을 마음대로 수정할 수 없다.
기존 VM
Guest Physical Address
          ↓
         EPT
          ↓
Host Physical Address
malicious hypervisor가 EPT를 조작해 protected memory를 remap할 수 있으면 TDX의 의미가 없어지기 때문이다.
그래서 TDX에서는 SEPT(Secure Extended Page Table)를 TDX Module이 관리한다. SEPT 자체 역시 TD의 key로 encrypted되어 있다.

8.1 SEPT 생성 과정

Host가 새로운 SEPT page를 추가하려면: TDH.MEM.SEPT.ADD 호출
TDX Module은 해당 page에 안전한 초기값을 write한다.
New SEPT Page

Before
┌───────────────┐
│ unknown / old │
│ unknown / old │
└───────────────┘

TDH.MEM.SEPT.ADD
        ↓

After
┌───────────────┐
│ EMPTY SEPTE   │
│ EMPTY SEPTE   │
└───────────────┘

8.2 초기화 Write를 없애면?

공격자는 먼저 자신의 TD에서 valid한 malicious SEPTE ciphertext를 target HPA에 남겨둔다. 그리고
TDH.MEM.SEPT.ADD
        ↓
TDX Module
        ↓
"EMPTY entry들을 write"
        ↓
      DDRop
        X
초기화 write가 사라진다.
그러면
Expected:
[ EMPTY SEPTE ]

Actual:
[ stale malicious SEPTE ]
이렇게 됨
TDX Module 입장에서는 새로운 SEPT page를 초기화했다고 생각하지만, 실제 DRAM에는 과거에 준비해둔 valid ciphertext가 남아 있음 421f642c-23c4-41e3-b1a0-8c9de59e7f82.png
결과적으로 attacker-controlled TD의 GPA가 공격자가 원하는 HPA를 가리키도록 만들 수 있다. 이는 곧 Secure Page Table 자체에 malicious mapping 삽입을 의미

[9] Case study 종류

Case Study 1: Victim Memory Replay Case Study 2: Victim TD를 Debug Mode로 만들기 Case Study 3: Attestation 자체를 속이기 자세한 내용은 논문을 추가로 참고해주길

[10] 추가 discussion 내용

공격자 가정

1. Server에 physical access
2. DDR5 interposer 설치
3. Host OS / Hypervisor의 privileged access

Limitations

TDX와 SEV-SNP end-to-end 공격은 주로 dual-socket server에서 수행했다. 또 현재 interposer는:
WRITE인지
READ인지
어느 address인지
를 실시간으로 완전히 decode해서 선택적으로 조작하지 않는다.
그래서 read까지 drop하면 system crash가 발생한다. 논문은 FPGA 기반의 더 복잡한 interposer라면 command type/address별 selective fault도 가능할 수 있지만 비용과 복잡도가 크게 증가한다고 설명한다

소감

TEE, CC에 대한 내용들이 점차 논문으로 나오고 있는 추세같다. 재밌는 주제들이 더 많을 듯 하다

Comments (0)

Loading comments...

Please log in to leave a comment.

Log In