카테고리 없음

분기 예측 관련 공격

whffu0123 2026. 7. 1. 20:43

분기 예측을 노리는 공격들 — Spectre부터 ret2spec까지

컴퓨터 구조(파이프라인·투기 실행)와 시스템 해킹(메모리 누출)이 만나는 지점, 마이크로아키텍처 취약점 정리. 분기 예측·투기 실행을 악용하는 대표 공격들을 다룬다.

배경 — 왜 분기 예측이 공격 대상이 되는가

CPU는 파이프라인을 놀게하지 않으려고, 분기(if, 함수 호출, ret) 결과가 확정되기 전에 ㅇ마 이쪽으로 갈 것이라 예측하고 그 방향 명령어를 미리 실행한다. 이것이 투기 실행(speculative execution) 이다. 예측이 틀리면 그 결과를 되돌린다(rollback).

문제는 되돌림이 불완전하다는 데 있다.

  • 되돌려지는 것: 레지스터·연산 결과 등 구조적 상태(architectural state)
  • 되돌려지지 않는 것: 투기 실행 중 캐시에 올라간 데이터

이 지우다 만 흔적이 핵심이다. 투기 실행이 비밀 값에 접근해 그 값에 따라 특정 메모리를 캐시에 올렸다면, 예측이 틀려 되돌려져도 캐시 흔적은 남는다. 공격자는 그 흔적을 캐시 접근 시간 측정(side channel) 으로 읽어내 비밀을 복원한다.

투기 실행으로 비밀에 접근 → 캐시에 흔적을 남김 → 되돌림 후에도 남은 흔적을 시간으로 추론. 

분기 예측기는 한 종류가 아니다

CPU 안에는 예측 대상별로 여러 장치가 있다. 공격 분류의 기준이 된다.

조건 분기 예측기 if가 참인지 거짓인지 Spectre v1
간접 분기 예측기 (BTB) 함수 포인터·가상 함수의 점프 목적지 Spectre v2
반환 스택 버퍼 (RSB) ret의 리턴 주소 ret2spec

1. Spectre v1 — Bounds Check Bypass (CVE-2017-5753)

노리는 것: 조건 분기 예측기

가장 기본적인 형태. 경계 검사 분기를 악용한다.

if (x < array1_size)              // ← 이 분기를 길들인다
    y = array2[array1[x] * 256];  // 투기 실행되는 가젯

공격 흐름

  1. 길들이기 — x에 정상 값을 여러 번 넣어, 예측기가 "이 if는 항상 참"이라고 학습하게 만든다.
  2. 경계 밖 호출 — x에 배열 범위를 벗어난 값을 넣는다. 정상이라면 if에서 걸러져야 한다.
  3. 투기 실행 — 예측기가 "참"이라 학습돼 있어, 검사가 확정되기 전에 if 안쪽을 투기 실행한다. 여기서 경계 밖 비밀 값 array1[x]를 읽는다.
  4. 흔적 남기기 — 그 비밀 값을 인덱스로 array2에 접근 → array2[secret * 256]가 캐시에 올라간다.
  5. 누출 — 예측이 틀렸음이 밝혀져 되돌려지지만, 캐시 흔적은 남는다. 공격자가 array2의 각 원소 접근 시간을 재서 캐시에 올라간 원소를 찾고, 거꾸로 secret을 복원한다.

이름은 "경계 검사 우회"지만 사용자 입력에만 국한되지 않는다.


2. Spectre v2 — Branch Target Injection / BTI (CVE-2017-5715)

노리는 것: 간접 분기 예측기 (BTB)

v1보다 강력하다. 간접 분기(목적지가 변수인 점프 — 함수 포인터, 가상 함수 호출)의 목적지 예측을 조작한다.

왜 더 위험한가

v1은 "경계 밖을 읽게" 하는 정도지만, v2는 공격자가 투기 실행의 점프 목적지를 원하는 곳으로 유도할 수 있다. 공격자는 BTB(Branch Target Buffer)를 오염시켜, 피해자의 간접 분기가 공격자가 고른 가젯 코드로 투기적으로 튀게 만든다.

공격 흐름

  1. 공격자가 자신의 주소 공간에서 간접 분기를 반복해, 피해자 주소 공간의 특정 주소(가젯 위치)로 BTB를 오염시킨다.
  2. 피해자가 간접 분기를 실행할 때, 오염된 예측으로 그 가젯이 투기 실행된다.
  3. 가젯이 비밀을 읽어 캐시에 흔적을 남긴다. → 이후는 v1과 동일(사이드 채널로 복원).

ROP가 기존 코드 가젯을 재활용하듯ㅇ, Spectre v2는 기존 코드 가젯을 투기적으로 실행시킨다는 점에서 발상이 닮았다. 차이는 실제 실행이 아니라 되돌려질 투기 실행이라는 것.


3. Meltdown — 대비용 사촌 (CVE-2017-5754)

노리는 것: 분기 예측이 아님 (비순차 실행 + 예외 타이밍)

Spectre와 자주 함께 언급되지만 메커니즘이 다르다. 분기 예측을 쓰지 않는다.

차이의 핵심

  • Spectre: 분기 예측을 길들여 프로그램 자신의 코드가 잘못된 걸 투기 실행하게 함. 예외 없음.
  • Meltdown: 커널 메모리를 직접 읽으려 시도한다. 권한 위반이라 예외가 발생하지만, CPU가 예외를 처리하기 전의 짧은 비순차 실행 창에서 이미 그 값을 읽어 캐시에 흔적을 남긴다.

Meltdown은 유저 프로세스가 커널 메모리를 읽는 격리 붕괴라 충격이 컸고, KPTI(커널/유저 페이지 테이블 분리)로 대응됐다. 분기 예측 공격은 아니지만, "투기/비순차 실행의 되돌림이 캐시엔 안 남는다"는 같은 토대 위에 있어 대비용으로 넣는다.


4. ret2spec / Spectre-RSB — ret을 노리는 변종

노리는 것: 반환 스택 버퍼 (RSB)

배경

CPU는 ret의 목적지(리턴 주소)도 예측한다. call이 일어날 때마다 리턴 주소를 RSB(Return Stack Buffer) 라는 작은 하드웨어 스택에 밀어넣고, ret 때 거기서 꺼내 목적지를 예측한다. (실제 메모리 스택과 별개인 예측 전용 버퍼)

공격 발상

공격자가 이 RSB를 오염시켜, ret이 공격자가 고른 주소로 투기적으로 점프하게 만든다. 그 주소의 가젯이 투기 실행되어 비밀을 캐시에 남긴다.

BOF의 ret 조작과 무엇이 다른가

고전 BOF / ROP ret2spec

조작 대상 메모리 스택의 실제 리턴 주소 RSB(예측 전용 버퍼)
실행 성격 실제 실행 (아키텍처 상태 변경) 투기 실행 (되돌려짐)
결과 실행 흐름 탈취 캐시 사이드 채널로 정보 누출

발상은 같다 — "ret의 목적지를 조작한다." 하지만 하나는 실제 스택을, 하나는 예측기를 건드린다. 컴퓨터 구조에서 배운 ret·리턴 주소가 마이크로아키텍처 예측 층에서 다시 등장하는 셈이다.


정리 — 계보 한눈에

투기 실행 = 성능 최적화 (버그 아님)
   │  되돌림이 캐시엔 안 남는다는 틈
   ▼
┌──────────────────────────────────────────────┐
│ Spectre v1  → 조건 분기 예측기 (경계 검사 우회) │
│ Spectre v2  → 간접 분기 예측기 (BTB, 목적지 조작)│
│ ret2spec    → 반환 스택 버퍼 (ret 목적지 조작)  │
└──────────────────────────────────────────────┘
   Meltdown → 분기 예측 아님 (비순차 실행 + 예외 타이밍)

공통 마무리: 캐시에 남은 흔적을 접근 시간 측정으로 복원 (side channel)

왜 끝나지 않는가

하나의 완화책으로 모든 변종을 막을 수 없고, 대응은 프로세서마다 다르다. 그래서 2018년 이후로도 Retbleed, Inception(SRSO), BHI/Spectre-BHB, Indirector, iLeakage 등 변종과 패치가 계속 반복되고 있다. 투기 실행이라는 성능 최적화를 포기하지 않는 한 근본 해결이 어려운, 전형적인 성능↔보안 트레이드오프다.