이 내용은 부채널 공격(Side-Channel Attack)의 대가인 Daniel Gruss의 졸업 논문인 Software-based Side-Channel Attacks and Defenses in Restricted Environments의 내용을 발췌한 것입니다. ^^;;; 저도 그동안 부채널 공격을 관심있게 보지 않아서 대략적인 내용만 알고 있었는데, 이번에 Black Hat Asia의 리뷰보드(Review Board)가 되면서 관심있게 살펴보게 되었습니다.

사실 최근 부채널 공격의 트렌드는 하드웨어 중심이던 예전과 달리 소프트웨어만으로 공격을 한다는 점인 것 같습니다. Daniel Gruss도 이야기하긴 했지만, 예전에는 암호 연산용 칩이 있을 때 암호 연산을 수행하는 알고리즘의 경로에 따라 전력 소모가 달라진다는 점을 이용해서 전력 측정(Power Measurement) 기법을 사용했습니다. 이러한 공격 기법은 현재 대부분 대비가 되어 있는 상태라 새로운 공격 기법이 등장했는데요, 그게 바로 소프트웨어 기반 마이크로아키텍처 공격(Software-based Microarchitectural Attack) 입니다. 주로 캐시(Cache)와 TLB(Translate Look-aside Buffer)를 이용하는데요, 캐시와 TLB에 대해서는 제가 요약한 캐시 및 TLB 부채널 공격(Cache and TLB Side-Channel Attack) 기법을 참고하시길 바랍니다. ^^;;;

소프트웨어 기반 마이크로아키텍터 공격(Software-based Microarchitectural Attack)

1. 캐시 공격(Cache Attack)

캐시 공격 기법은 연산중에 캐시에 남은 정보를 추출해내는 기법인데요, Evit+Time, Prime+Probe, Flush+Reload, Flush+Flush, Evict+Reload 공격 기법이 대표적으로 최근에 활용된 TLB 공격 기법도 있습니다. 이 부분들은 내용이 많아서 제가 따로 정리한 캐시 및 TLB 부채널 공격(Cache and TLB Side-Channel Attack) 기법를 참고하면 좋을 것 같습니다.

2. 예측자 공격(Attacks on Predictors)

CPU에는 성능을 높이기 위해 다양한 예측자(Predictors)가 들어있는데요, Branch Predictors, Prefetchers, Memory-aliasing Predictors가 있습니다.

  • Branch Predictors: 프로그램을 작성하다보면 루프를 사용하게 되는데요, 루프는 일정한 횟수동안 반복해서 도는 특징이 있습니다. 이러한 루프를 만나면 CPU가 루프의 비교문을 만났을 때 다음에도 루프 안쪽을 실행할 것이라고 예측하고 미리 파이프라인에 명령어를 밀어넣는데, Branch Predictors의 예측을 빗나가게 해서 정보를 추출하는 공격 기법이 Branch Predictor Attack입니다.
  • Prefechers: 코드를 실행하다보면 현재 실행중인 명령어의 다음 명령어가 실행될 것이라 예측하고 성능향상을 위해 명령어와 데이터를 미리 채워놓습니다. Prefecher는 캐시 부채널 공격을 수행할 때 원치 않는 잡음(Noise)를 생성하는 원인이 되기도 하는데요, Prefecher Attack은 직접 이를 이용해서 공격을 수행하기 보다는 잡음을 줄이는 방법으로 활용되곤 한답니다.
  • Memory-aliasing Predictors: 최근 CPU는 실행 능력을 향상시키기 위해 다양한 버퍼(Buffer)를 활용하는데요, Memory-aliasing Predictor는 CPU 내부에 있는 저장 버퍼(Store Buffer)의 값을 캐시에 저장하기 전에 읽어야할 때 이를 읽기 버퍼(Load Buffer)로 옮기는 일을 담당합니다. 저장 버퍼의 값이 읽기 버퍼로 옮겨갈 때 접근 권한(Access Right)가 제대로 검사되지 않으면 정보가 유출될 수 있는데 이것이 바로 Memory-aliasing Predictor Attack입니다. 실제로 Store-to-Leak Forwarding Attack이 이를 이용했습니다.

3. DRAM 공격(DRAM Attack)

DRAM 모듈에 저장된 정보는 Row Buffer를 거쳐서 CPU에게 전달되는데, Row Buffer에 저장된 데이터는 다시 읽었을 때 Row Buffer에 없는 데이터보다 빨리 접근되는 특징이 있습니다. 이러한 공격이 실존하고 이를 이용한 공격이 DRAMA Attack 입니다.

DRAMA 공격 기법 - 출처: Software-based Side-Channel Attacks and Defenses in Restricted Environments

4. 임시 실행 공격(Transient-Execution Attack)

최근 가장 핫한 공격이 바로 임시 실행 공격(Transient-Execution Attack) 인데요, 많이들 알고 계시는 멜트다운(Meltdown), 스펙터(Spectre) 공격 기법이 바로 이 카테고리에 속합니다. 임시 실행 공격은 마이크로아키텍처 공격의 한 종류인데요, 현대 CPU의 비순차실행(Out-of-order Execution)과 예측적 실행(Speculative Execution)을 이용해서 데이터를 유출하는 공격 기법입니다. Daniel Gruss의 전공이기도 하지요.

4.1. 스펙터(Spectre)

스펙터는 임시 실행 공격의 한 종류인데요, 실행 흐름 예측 오류(Control-flow misprediction)과 데이터 흐름 예측 오류(Data-flow misprediction)을 이용합니다. 사실 말보다는 그림으로 보면 더 이해하기가 쉬운데요, 아래는 논문에 있는 스펙터 공격의 흐름입니다.

스펙터(Spectre) 공격 기법 - 출처: Software-based Side-Channel Attacks and Defenses in Restricted Environments

  • 위의 그림에서 보는 것처럼 if문 안의 Index가 0~3일 경우는 참이되어 왼쪽의 Then 부분에 코드가 실행됩니다. 따라서 index의 값으로 data 영역을 접근하고 그 값이 공유 메모리 영역인 shm의 index가 되어 최종적으로 값이 읽혀집니다.
  • 이때, index의 값을 계속 if문이 True가 되도록 실행을 하면 Branch Predictor가 앞으로도 계속 참이 될 것이라고 예측하고 index의 값이 4보다 커도 Then 영역을 미리 실행(Out-of-Execution)합니다. 즉 예측이 실패하는 것이지요.
  • index는 data 영역에서 해당 위치만큼 떨어진 영역을 가리키게 되는데요, 이 index를 주요 정보가 있는 영역, 예를 들어 커널에 저장된 Key가 존재하는 영역이라고 가정한다면 해당 키의 정보가 shm의 Index로 사용되어 캐시에 저장됩니다.
  • 마지막으로 공격자는 shm에서 Index만큼 떨어진 영역이 캐시에 저장되었는지를 확인하는 방식으로 주요 정보에 접근할 수 있습니다.

4.2. 멜트다운(Meltdown)

멜트다운은 임시 실행 공격의 한 종류인데요, 예외(Exception)가 발생했을 때 비순차실행(Out-of-order)의 결과로 데이터가 유출되는 것을 노리는 기법입니다. 역시 그림으로 보는 것이 더 이해가 쉬우니 논문의 그림을 인용하겠습니다.

멜트다운(Meltdown) 공격 기법 - 출처: Software-based Side-Channel Attacks and Defenses in Restricted Environments

  • 위의 그림에서 kernel 부분의 메모리는 접근이 불가능하기 때문에 오류(Exception)이 발생합니다.

  • 이때, 비순차실행 때문에 value가 공유 메모리 영역인 shm의 index로 사용됩니다.

  • 공격자는 스펙터의 공격기법과 같이 shm에서 Index만큼 떨어진 영역이 캐시에 저장되었는지를 확인하는 방식으로 주요 정보에 접근할 수 있습니다.

    지금까지 부채널 공격에 대해서 정리해봤는데요, 최근 부채널 공격은 소프트웨어만 이용해서 공격이 가능한 만큼 파급력이 큽니다. 하지만 다행히도 방어법 또한 마련되어 있는데요, 다음에는 방어법에 대해서 정리해보겠습니다.

    그럼 좋은 밤 되세요 ^^)/

작년에부터 Black Hat Asia의 리뷰보드로 활동하면서 제출된 발표자료를 살펴볼 일이 생겼습니다. 그중에서도 독보적이었던 것이 캐시와 TLB(Translation Look-aside Buffer)를 이용한 부채널 공격(Cache Side-Channel Attack)과 관련된 발표자료였는데요, IEEE Security and Privacy(S&P)와 ACM Conference on Computer and Communications Security(CCS) 등을 거쳐와서 내용 자체는 더할나위가 없는 수준이었습니다. 다만... 제가 부채널 공격을 전혀 모르고 있는 상태였기 때문에, 이 기회에 주요 공격 기법을 정리해봤습니다.

캐시를 이용한 부채널 공격 기법

캐시(Cache)를 이용한 부채널 공격의 요점은 캐시에 데이터가 존재하면 해당 데이터를 DRAM에서 읽어오는 것보다 빠르기 때문에 해상도(Resolution)이 아주 좋은 카운터가 있으면 데이터 접근 시간(Data Access Time)을 측정함으로써 이를 확인할 수 있다는 겁니다. 최근까지 사용된 캐시 부채널 공격 기법은 아래와 같습니다.

Evict + Time 기법

Evict + Time 기법은 공격자가 공격 대상이 접근하는 메모리 영역을 확인하기 위해 시도하는 기법입니다. Evict에서 추측할 수 있는 것처럼 공격 대상이 접근하는 메모리 영역을 모두 캐시에서 제거하고, 공격 대상을 실행해서 특정 동작, 예를 들면 암호 연산(Cryptographic Algorithm)을 수행하고 그에 걸린 시간을 측정하는 것이지요. 만일 Evict된 캐시에 접근한다면 캐시에 존재하는 데이터에 접근하는 것보다 실행 시간이 더 길어지니 이로써 실제로 수행되는 함수나 실제로 접근하는 데이터를 알 수 있습니다. 실제로 OpenSSL AES 알고리즘을 공격하는데 사용되었습니다.

Prime + Probe 기법

Prime + Probe 기법 역시 암호 연산을 공격하는데 사용되었는데요, 시나리오는 아래와 같습니다.

  • 먼저 공격자가 캐시를 기준값(Prime)으로 채워두고,
  • 공격자가 공격 대상을 실행합니다. 이때, 공격대상이 어떤 데이터를 읽었다면 그 데이터가 캐시에 없기 때문에 메모리에서 읽고 공격자가 채워넣은 기준값(Prime)을 Evict한 후에 해당 데이터를 채워 놓습니다.
  • 공격 대상의 실행이 완료된 후에, 공격자가 다시 캐시의 정보를 순차적으로 읽습니다. 이때, 특정 위치에서 시간이 많이 걸린다면, 해당 데이터는 공격 대상에 의해 Evict 되었기 때문입니다. 이를 바탕으로 해당 캐시의 위치를 파악하여 공격 대상이 접근한 메모리의 위치를 확인할 수 있습니다.

Prime + Probe는 공유 메모리가 필요치 않기 때문에, Intel SGX와 같이 고립된 환경도 공격이 가능한 장점이 있습니다. 부채널 공격으로 유명한 Michael Schwarz의 논문에 보면 아래와 같이 표현되어 있습니다.

Prime + Probe Attack - 출처: Software-based Side-Channel Attacks and Defenses in Restricted Environments

Flush + Reload 기법

Flush + Reload 기법은 x86 명령어 중에 clflush를 이용하는 공격 기법인데요, clflush가 논리적 주소(Logical Address)를 기반으로 해당 영역만 캐시에서 Flush할 수 있는 특성을 이용합니다. 공격 시나리오는 아래와 같습니다.

  • 암호 알고리즘이 들어있는 공유 라이브러리(Shared Library)를 clflush로 캐시에서 제거하고,
  • 공격 대상을 실행하여 암호 연산을 실행합니다.
  • 공격자가 공유 라이브러리가 있는 영역에 순차적으로 접근합니다. 이때, 공격 대상이 해당 영역에 접근한 경우, 이미 캐시에 존재하므로 그렇지 않은 영역과 접근 시간의 차이가 발생합니다. 이를 이용하면 접근 시간의 차이를 이용하여 암호 알고리즘이 수행된 실행 흐름이나 접근된 데이터를 확인할 수 있습니다.

Flush + Reload 기법은 물리 주소(Physical Address)를 알 필요가 없는 장점이 있습니다. 아래 그림은 Michal Schwarz의 논문에서 가져온 Flush + Reload 기법과 관련된 그림입니다.

Flush + Reload - 출처: Software-based Side-Channel Attacks and Defenses in Restricted Environments

Flush + Flush 기법

Flush + Flush 기법 역시 clflush를 이용한 기법입니다. Flush + Reload 기법과 차이점은 공격 대상을 실행한 뒤에 캐시에 순차적으로 접근하여 접근 시간을 보는 것이 아니라 순차적으로 clflush를 다시 수행해서 flush 시간을 측정하는 겁니다. 캐시에 데이터가 존재하면 clflush에 걸리는 시간이 길고, 캐시에 데이터가 존재하지 않으면 clflush에 걸리는 시간이 짧은 특성을 이용한 것입니다.

Evict + Reload 기법

Evict + Reload 기법은 clflush가 없는 경우, 캐시에서 알아내길 원하는 정보를 모두 제거하는 Evict를 사용하는 Flush + Evict 기법의 변형입니다. clflush를 직접 쓸 수 없는 Javascript나 clflush 명령어가 없는 ARM 프로세서 등에서 사용할 목적으로 변형된 것이지요.

TLB(Translation Look-aside Buffer)를 이용한 공격 기법

TLB를 이용한 공격 기법 역시 캐시를 이용한 공격 기법과 비슷한데요, 캐시 대신에 TLB를 이용하는 점이 차이점이고 역시나 TLB에 해당 영역의 (논리적 주소->물리적 주소) 맵핑 정보가 저장되어 있으면 접근 시간이 짧다는 특성을 이용합니다. Michal Schwarz가 쓴 Store-to-Leak Forwarding: Leaking Data on Meltdown-resistant CPUs논문에서 Store-to-Load Forwarding과 TLB를 이용하여 주요 정보를 유출하는 예를 보여줬습니다.

Microarchitecture가 그동안 많이 숨겨져 있었고 성능 최적화에 중점을 두고 발전하다보니 보안적인 문제가 다소 있는 것 같군요.

그럼 좋은 하루 되세요. ^^

+ Recent posts