"CPU게이트"의 두 판 사이의 차이
(같은 사용자에 의한 21개의 중간 편집이 숨겨짐) | |||
153번째 줄: | 153번째 줄: | ||
====스펙터==== | ====스펙터==== | ||
− | |||
− | |||
− | |||
취약점의 근본 원인인 추측 실행(speculative execution)으로부터 이름을 따옴. 고치기 힘든 버그인만큼, 꽤 오랫동안 유령처럼 출몰해올 것.<ref>출처 : https://spectreattack.com/</ref> 스펙터 공격은 '경계 검사 우회(CVE-2017-5753)', '분기 타깃 주입(CVE-2017-5715)'의 두 이형으로 나눌 수 있음. | 취약점의 근본 원인인 추측 실행(speculative execution)으로부터 이름을 따옴. 고치기 힘든 버그인만큼, 꽤 오랫동안 유령처럼 출몰해올 것.<ref>출처 : https://spectreattack.com/</ref> 스펙터 공격은 '경계 검사 우회(CVE-2017-5753)', '분기 타깃 주입(CVE-2017-5715)'의 두 이형으로 나눌 수 있음. | ||
162번째 줄: | 159번째 줄: | ||
if (x < array1_size) | if (x < array1_size) | ||
y = array2[array1[x] * 4096]; | y = array2[array1[x] * 4096]; | ||
+ | |||
+ | [[파일:Spectre.png|200px|섬네일|스펙터의 로고]] | ||
+ | [[파일:SpectreCode.png|200px|섬네일|스펙터의 코드 일러스트]] | ||
+ | |||
# 위의 코드가, 신뢰되지 않은 출처로부터 unsigned integer x 값을 받는 (system call 또는 라이브러리) 함수의 일부라고 가정. 해당 코드를 실행하는 프로세스는 unsigned byte 단위 배열 array1, 그리고 1MB 크기 두 번째 byte 배열 array2에 대한 접근을 가짐. 코드는 x에 대한 경계 검사로부터 시작하는데 이는 보안에 있어 필수적임. 만약 경계 검사를 하지 않는다면, 경계 범위 바깥의 입력 x가 예외를 일으키거나, 배열의 기저 주소로부터의 오프셋 x를 전달하여 프로세서가 접근에 민감한 메모리를 접근하도록 만들 수 있을 것임. | # 위의 코드가, 신뢰되지 않은 출처로부터 unsigned integer x 값을 받는 (system call 또는 라이브러리) 함수의 일부라고 가정. 해당 코드를 실행하는 프로세스는 unsigned byte 단위 배열 array1, 그리고 1MB 크기 두 번째 byte 배열 array2에 대한 접근을 가짐. 코드는 x에 대한 경계 검사로부터 시작하는데 이는 보안에 있어 필수적임. 만약 경계 검사를 하지 않는다면, 경계 범위 바깥의 입력 x가 예외를 일으키거나, 배열의 기저 주소로부터의 오프셋 x를 전달하여 프로세서가 접근에 민감한 메모리를 접근하도록 만들 수 있을 것임. | ||
# 컴파일된 위의 코드가 실행될 때, 프로세서는 x의 악성값을 array1_size와 비교하는 것으로 시작. array1_size를 읽는 것은 캐시 미스<ref>캐시는 주 기억 장치와 CPU 사이에서 자주 접근되는 데이터나 명령어들을 저장해두는 고속 버퍼 메모리로, 요청된 데이터가 캐시에서 발견되는 경우를 캐시 히트라고 하고, 캐시 내에 없을 때는 이를 캐시 미스라고 함.</ref>를 발생시키고, 프로세서는 그것의 값이 DRAM으로부터 가용해질 때까지 상당한 지연을 겪게 됨. 특히 분기 조건 또는 분기 이전 위치의 명령어의 경우, 캐시되지 않은 인수를 기다린다면 분기 결과가 결정되기까지 많은 시간이 걸릴 것. 그동안 분기 예측기는 if 조건이 참일 것이라 가정하고, 해당 추측에 따라서 array1의 기저 주소에 x를 더한 뒤 메모리 서브시스템으로부터 결과 주소 위치의 데이터를 요청함으로써 실행 시간 효율을 높이는 데, 이것이 바로 분기 예측과 추측 실행 기술의 핵심임. 이 읽기 작업은 캐시 히트일 것이며 숨겨진 바이트 k의 값을 빠르게 반환할 것. 추측 실행 로직은 k를 이용해 array2[k * 4096] 주소를 계산할 수 있음. 다음으로 메모리로부터 해당 주소를 읽기 위한 요청을 전달함(이는 캐시 미스를 유발.) | # 컴파일된 위의 코드가 실행될 때, 프로세서는 x의 악성값을 array1_size와 비교하는 것으로 시작. array1_size를 읽는 것은 캐시 미스<ref>캐시는 주 기억 장치와 CPU 사이에서 자주 접근되는 데이터나 명령어들을 저장해두는 고속 버퍼 메모리로, 요청된 데이터가 캐시에서 발견되는 경우를 캐시 히트라고 하고, 캐시 내에 없을 때는 이를 캐시 미스라고 함.</ref>를 발생시키고, 프로세서는 그것의 값이 DRAM으로부터 가용해질 때까지 상당한 지연을 겪게 됨. 특히 분기 조건 또는 분기 이전 위치의 명령어의 경우, 캐시되지 않은 인수를 기다린다면 분기 결과가 결정되기까지 많은 시간이 걸릴 것. 그동안 분기 예측기는 if 조건이 참일 것이라 가정하고, 해당 추측에 따라서 array1의 기저 주소에 x를 더한 뒤 메모리 서브시스템으로부터 결과 주소 위치의 데이터를 요청함으로써 실행 시간 효율을 높이는 데, 이것이 바로 분기 예측과 추측 실행 기술의 핵심임. 이 읽기 작업은 캐시 히트일 것이며 숨겨진 바이트 k의 값을 빠르게 반환할 것. 추측 실행 로직은 k를 이용해 array2[k * 4096] 주소를 계산할 수 있음. 다음으로 메모리로부터 해당 주소를 읽기 위한 요청을 전달함(이는 캐시 미스를 유발.) | ||
169번째 줄: | 170번째 줄: | ||
# 스펙터의 두 번째 이형에서 공격자는 ROP<ref>반환 지향형 프로그래밍. 이 기법에서 공격자는 프로그램의 제어 흐름을 하이재킹하기 위해 호출 스택의 제어를 얻고, '가젯'이라 불리는 신중히 선택된 기계어들을 실행함. 각 가젯은 일반적으로 연결됨으로써 의미를 구현하는 몇몇 명령어들과 함께 마지막에 반환 명령어(ret)로 끝남.</ref> 공격의 활용으로서, 목표 프로세스의 주소 공간에서 가젯을 선택하고, 목표가 가젯을 추측 실행하도록 유도함. | # 스펙터의 두 번째 이형에서 공격자는 ROP<ref>반환 지향형 프로그래밍. 이 기법에서 공격자는 프로그램의 제어 흐름을 하이재킹하기 위해 호출 스택의 제어를 얻고, '가젯'이라 불리는 신중히 선택된 기계어들을 실행함. 각 가젯은 일반적으로 연결됨으로써 의미를 구현하는 몇몇 명령어들과 함께 마지막에 반환 명령어(ret)로 끝남.</ref> 공격의 활용으로서, 목표 프로세스의 주소 공간에서 가젯을 선택하고, 목표가 가젯을 추측 실행하도록 유도함. | ||
# 공격자는 자신이 선택한 위치에서 추측 실행이 진행되게 하기 위해 분기 예측기를 악성 목적지로 훈련시킴. 분기 타깃 버퍼<ref>분기 예측에 사용되는 프로세서 구성 요소로 분기 명령의 위치와 해당 명령의 타깃 주소를 담고 있음.</ref>를 훈련시키기 위해, 공격자는 목표 프로세스의 주소 공간에서 가젯의 가상 주소를 찾고, 이 주소에 대해 간접 분기<ref>다음 실행할 명령어의 주소를 직접 명시하는 대신, 주소가 위치한 곳을 명시하는 인수를 갖는 프로그램 제어 명령어 유형.</ref>를 수행. 이 훈련은 공격자의 주소 공간에서 이루어짐. 공격자의 주소 공간의 가젯 주소 위치에 무엇이 상주하는지는 문제되지 않으며, 요구되는 조건의 전부는 훈련 중 공격자의 가상 주소들이 목표의 그것들과 일치해야 한다는 점뿐임. | # 공격자는 자신이 선택한 위치에서 추측 실행이 진행되게 하기 위해 분기 예측기를 악성 목적지로 훈련시킴. 분기 타깃 버퍼<ref>분기 예측에 사용되는 프로세서 구성 요소로 분기 명령의 위치와 해당 명령의 타깃 주소를 담고 있음.</ref>를 훈련시키기 위해, 공격자는 목표 프로세스의 주소 공간에서 가젯의 가상 주소를 찾고, 이 주소에 대해 간접 분기<ref>다음 실행할 명령어의 주소를 직접 명시하는 대신, 주소가 위치한 곳을 명시하는 인수를 갖는 프로그램 제어 명령어 유형.</ref>를 수행. 이 훈련은 공격자의 주소 공간에서 이루어짐. 공격자의 주소 공간의 가젯 주소 위치에 무엇이 상주하는지는 문제되지 않으며, 요구되는 조건의 전부는 훈련 중 공격자의 가상 주소들이 목표의 그것들과 일치해야 한다는 점뿐임. | ||
− | # 공격자가 선택한 위치에서 추측 실행이 진행된다면 주목할 만한 부수 효과들을 남길 수 있을 것인데, 공격 가능한 조건 분기 예측 실패가 없는 상황에서도 목표 프로세스 메모리를 노출시킬 수 있기 때문에, 이 방법은 공격자에게 매우 강력한 수단이 | + | # 공격자가 선택한 위치에서 추측 실행이 진행된다면 주목할 만한 부수 효과들을 남길 수 있을 것인데, 공격 가능한 조건 분기 예측 실패가 없는 상황에서도 목표 프로세스 메모리를 노출시킬 수 있기 때문에, 이 방법은 공격자에게 매우 강력한 수단이 됨. |
====멜트다운==== | ====멜트다운==== | ||
187번째 줄: | 188번째 줄: | ||
[[파일:MeltdownCode.png|200px|섬네일|멜트다운의 코드 일러스트]] | [[파일:MeltdownCode.png|200px|섬네일|멜트다운의 코드 일러스트]] | ||
− | + | # RCX 레지스터에 적재된 타깃 커널 주소에 위치한 바이트 값을, AL로 나타내어지는 RAX 레지스터의 최하위 바이트로 옮김. MOV 명령어는 코어에 의해 인출되어, 마이크로 연산<ref>하나의 명령어는 여러 개의 마이크로 연산으로서 수행됨.</ref>으로 해독되고, 할당되어, 리오더 버퍼로 보내짐. 아키텍처의 영역에 속하는 레지스터들(예를 들어 RAX와 RCX)은 비순차적 명령어 처리를 가능케 하는 하위의 물리 레지스터들에 매핑됨. 파이프라인을 가능한 한 최대로 활용하기 위해, 후속 명령어들(shl ~ mov)도 함께 해독되고 마이크로 연산으로 할당됨. 마이크로 연산들은 일치하는 실행 유닛에 의해 실행되기 위해 기다리는, 명령어 대기열로 옮겨짐. 피연산자가 아직 계산되지 않았거나, 실행 유닛이 이미 해당하는 용량을 수용하고 있다면 마이크로 연산의 실행은 지연될 수 있음. 첫 mov 명령어에서 커널 주소가 도착했을 때, 이미 CPU가 후속 명령어들을 비순차적 명령어 처리의 일부로서 보냈을 가능성이 크며, 그들의 마이크로 연산들은 명령어 대기열에서 커널 주소의 내용이 도착하기를 기다리고 있을 것임. 공통 데이터 버스에 인출된 데이터가 도착하는 대로, 마이크로 연산들은 그들의 실행을 시작할 수 있음. 마이크로 연산들이 실행을 끝내면, 그들은 순서대로 완료하며, 그 결과들이 아키텍처 상태에 반영됨. 완료 과정 중에, 명령어의 실행 도중 발생한 어떠한 인터럽트나 예외들이 처리됨. 따라서, 만약 커널 주소를 로드하는 MOV 명령어가 완료한다면, 예외가 등록되고, 비순차적으로 실행된 모든 후속 명령어들의 결과들을 제거하기 위해 파이프라인이 flush될 것. 하지만, 이 예외를 일으키는 것과 공격의 진행 사이엔 경쟁 상태<ref>둘 이상의 입력 또는 조작의 타이밍이나 순서가 결과값에 영향을 줄 수 있는 상태를 말함.</ref>가 있음. | |
+ | # 앞의 단계의 비순차적으로 실행된 명령어 시퀀스는 순간적인 명령어 시퀀스가 되는 방향으로 선택되어야 함. 만약 이들 순간적인 명령어 시퀀스가 MOV 명령어가 완료하기 전에 실행된다면, 그리고 순간적인 명령어 시퀀스가 비밀 데이터를 기반으로 연산을 수행했다면, 이는 비밀을 공격자에게 전달하기 위한 수단으로 활용될 수 있을 것임. shl 명령어에서 앞의 단계의 비밀 값이 페이지 크기(예를 들어 4KB)로 곱해짐. 비밀의 곱은 배열에의 접근들이 각각 큰 공간적 거리를 둠을 보장함. 이는 하드웨어 프리패처가 캐시에 인접한 메모리 위치를 로딩하는 것을 방지. 여기서, 우리는 한 번에 하나의 바이트씩만을 읽으며, 이런 이유로 우리의 조사 배열은 4KB 페이지를 가정하여, 256 × 4096 byte 배열을 형성함. 비순차적 명령어 처리에서 우리는 레지스터 값 '0'에 대해 노이즈 편향을 가짐. 이러한 이유로, 순간적인 명령어 시퀀스에 재시도 로직을 둠. 마지막 mov 명령에서, 곱해진 비밀 값은 조사 배열의 기저 주소에 더해지고, 은닉 채널의 타깃 주소를 형성함. 이 주소는 연관된 캐시 라인을 캐시하기 위해 읽혀짐. 주소는 요청한 코어의 L1 데이터 캐시에 로드될 것이고, 포괄성으로 인해, 또한 다른 코어에 의해서도 읽히는 L3 캐시에도 존재할 것. 그 결과 순간적인 명령어 시퀀스는 앞의 단계에서 읽힌 비밀 값에 기반해 캐시에 영향을 미침. | ||
+ | # 공격자는 마이크로아키텍처 영역의 부채널 공격을 수행하여 비밀 값을 복원. 이는 캐시 상태를 아키텍처 영역의 상태로 옮기는 것. 순간적인 명령어 시퀀스가 실행될 때, 정확히 조사 배열의 한 캐시 라인이 캐시됨. 조사 배열 내의 캐시된 캐시 라인의 위치는 오직 앞에서 읽은 비밀에만 의존함. 따라서, 공격자는 조사 배열의 모든 256 페이지들을 돌며 페이지 상의 모든 첫 번째 캐시 라인에 대해 접근 시간을 측정. 캐시된 캐시 라인을 포함하는 페이지의 번호는 비밀 값과 정확히 일치함. | ||
+ | * '''시연 영상''' | ||
+ | <html> | ||
+ | <center><iframe width="480" height="320" src="https://www.youtube.com/embed/bReA1dvGJ6Y" frameborder="0" allowfullscreen> </iframe><iframe width="480" height="320" src="https://www.youtube.com/embed/RbHbFkh6eeE" frameborder="0" allowfullscreen></iframe></center> | ||
+ | </html> | ||
==="인텔" CPU게이트=== | ==="인텔" CPU게이트=== | ||
{{NetworkGraph | title="인텔"_CPU게이트.lst}} | {{NetworkGraph | title="인텔"_CPU게이트.lst}} | ||
+ | |||
+ | 스펙터와 멜트다운 취약점을 필두로 한 CPU게이트는 IT업계 전체를 뒤흔들었음. 취약점의 대상이 되는 분기 예측, 추측 실행, 비순차적 명령어 처리는 대다수의 현대 프로세서들이 사용하는 기술이기에, 개인 컴퓨터, 모바일 기기, 클라우드 등 대부분의 기기들은 공격으로부터 자유롭지 못하였음. 특히 전 세계 80% 이상의 PC와 서버에서 사용되는 인텔 CPU의 피해 가능성은, 1995년 이후의 거의 모든 인텔 프로세서들이 공격에 영향을 받는다는 공식 자료의 언급대로, 매우 높았으며 이 사태는 인텔에게 최악의 위기로 다가왔음. '인텔 CPU 게이트'라는 명칭은 이러한 인텔의 상황에서 비롯된 것임. 놀랍게도 AMD의 CPU들은 비순차적 명령어 처리 기술을 사용하면서도 멜트다운 공격에 영향 받지 않았는데, 이는 인텔과는 다른 마이크로아키텍처 설계 방식에서 비롯된 차이로, 마이크로 연산이 완료되기 전에 빠른 예외 처리를 적용하는 방식을 택하였기에 멜트다운 공격을 피할 수 있었던 것. | ||
==각주== | ==각주== |
2019년 6월 22일 (토) 11:10 기준 최신판
목차
주제
- 2018년초 발생한 최대의 하드웨어 보안 이슈인 'CPU게이트'.
기획의도
평소에 관심 있던 분야인 하드웨어 보안과 관련해 최근 가장 큰 영향을 미친 사건, CPU게이트의 전모를 세 부분으로 나누어 알아보고자 함.
- 스펙터와 멜트다운 취약점의 발견과 공개 과정.
- 하드웨어 관점에서의, 스펙터와 멜트다운 공격의 원리.
- 스펙터와 멜트다운 공격에 영향받는 제품군, 그리고 사건이 '인텔 CPU게이트'라고도 불리는 이유.
온톨로지
클래스(Class)
클래스 | 설명 | 노드 |
---|---|---|
아키텍처 | 하드웨어 제조사의 마이크로아키텍처 중, 사건에서 논의되는 아키텍처들만 모아 이 클래스에 정리하였음. | 아이비브릿지, 하스웰, 브로드웰, 스카이레이크, 카비레이크, 젠, Cortex-A57. |
하드웨어 | 프로세서 내에서 명령어 처리에 참여하는 구성 요소들, 그 중에서도 스펙터와 멜트다운 공격이 목표로 삼는 구성 요소들을 클래스로 정리하였음. | 프로세서, 캐시, 분기 예측기, 리오더 버퍼, 명령어 대기열. |
기술 | 현대 프로세서는 성능 향상을 목표로 하는 수많은 기술들의 산물임. 스펙터와 멜트다운 공격은 다음 주요 기술들의 취약점을 노림. | 분기 예측, 추측 실행, 비순차적 명령어 처리. |
공격 | CPU게이트의 중심에 있는 스펙터, 멜트다운 공격과, 공격 과정에서 부가적으로 활용되는 다른 공격 기법들을 함께 정리하였음. | 스펙터, 멜트다운, ROP, 부채널 공격. |
취약점 | 마이터 코퍼레이션이 감독하는 취약점 데이터베이스인 CVE에 등록된 스펙터와 멜트다운 취약점들을 이 클래스에 정리하였음. | CVE-2017-5753, CVE-2017-5715, CVE-2017-5754. |
문서 | 스펙터와 멜트다운 취약점 공개와 함께 배포된 문서들을 모아두었음. | Spectre Attacks: Exploiting Speculative Execution, Meltdown: Reading Kernel Memory from User Space. |
인물 | 스펙터와 멜트다운 취약점에 직간접적으로 관련되는 인물들을 모아두었음. | Jann Horn, Robert Tomasulo. |
조직 | 인물이 속한 조직, 그리고 사태에 영향받는 하드웨어 제조사들을 이 클래스에 정리하였음. | 구글 프로젝트 제로, 인텔, AMD, ARM. |
관계성(Relation)
- 는 -를 적용한다
- 설명: 마이크로아키텍처가 적용하는 프로세서 기술을 나타낸다.
- 해당노드:
- 아이비브릿지 → 분기 예측
- 하스웰 → 분기 예측
- 브로드웰 → 분기 예측
- 스카이레이크 → 분기 예측
- 카비레이크 → 분기 예측
- 젠 → 분기 예측
- Cortex-A57 → 분기 예측
- 아이비브릿지 → 추측 실행
- 하스웰 → 추측 실행
- 브로드웰 → 추측 실행
- 스카이레이크 → 추측 실행
- 카비레이크 → 추측 실행
- 젠 → 추측 실행
- Cortex-A57 → 추측 실행
- 아이비브릿지 → 비순차적 명령어 처리
- 하스웰 → 비순차적 명령어 처리
- 브로드웰 → 비순차적 명령어 처리
- 스카이레이크 → 비순차적 명령어 처리
- 카비레이크 → 비순차적 명령어 처리
- 젠 → 비순차적 명령어 처리
- Cortex-A57 → 비순차적 명령어 처리
- 는 -가 개발했다
- 설명: 마이크로아키텍처를 개발한 하드웨어 제조사를 나타낸다.
- 해당노드:
- 아이비브릿지 → 인텔
- 하스웰 → 인텔
- 브로드웰 → 인텔
- 스카이레이크 → 인텔
- 카비레이크 → 인텔
- 젠 → AMD
- Cortex-A57 → ARM
- 는 -의 구현이다
- 설명: 하드웨어 구성 요소가 구현하는 프로세서 기술을 나타낸다.
- 해당노드:
- 분기 예측기 → 분기 예측
- 리오더 버퍼 → 비순차적 명령어 처리
- 명령어 대기열 → 비순차적 명령어 처리
- 는 -의 일부이다
- 설명: 하드웨어 구성 요소가 속하는 하드웨어를 나타낸다.
- 해당노드:
- 캐시 → 프로세서
- 분기 예측기 → 프로세서
- 리오더 버퍼 → 프로세서
- 명령어 대기열 → 프로세서
- 는 -를 공격한다
- 설명: 공격이 목표로 삼는 취약점, 그리고 하드웨어 구성 요소를 나타낸다.
- 해당노드:
- 스펙터 → CVE-2017-5753
- 스펙터 → CVE-2017-5715
- 멜트다운 → CVE-2017-5754
- 부채널 공격 → 캐시
- 는 -의 취약점이다
- 설명: 취약점을 내포하는 하드웨어 기술을 나타낸다.
- 해당노드:
- CVE-2017-5753 → 분기 예측
- CVE-2017-5753 → 추측 실행
- CVE-2017-5715 → 분기 예측
- CVE-2017-5715 → 추측 실행
- CVE-2017-5754 → 비순차적 명령어 처리
- 는 -를 활용한다
- 설명: 취약점의 노출에 부가적으로 활용되는 공격을 나타낸다.
- 해당노드:
- CVE-2017-5753 → 부채널 공격
- CVE-2017-5715 → 부채널 공격
- CVE-2017-5715 → ROP
- CVE-2017-5754 → 부채널 공격
- 는 -가 최초 발견했다
- 설명: 취약점을 최초로 발견한 인물을 나타낸다.
- 해당노드:
- CVE-2017-5753 → Jann Horn
- CVE-2017-5715 → Jann Horn
- CVE-2017-5754 → Jann Horn
- 는 -가 작성했다
- 설명: 문서의 작성자를 나타낸다.
- 해당노드:
- Spectre Attacks: Exploiting Speculative Execution → Jann Horn
- Spectre Attacks: Exploiting Speculative Execution → 구글 프로젝트 제로
- Meltdown: Reading Kernel Memory from User Space → Jann Horn
- Meltdown: Reading Kernel Memory from User Space → 구글 프로젝트 제로
- 는 -를 기술한다
- 설명: 문서가 기술하는 대상을 나타낸다.
- 해당노드:
- Spectre Attacks: Exploiting Speculative Execution → 스펙터
- Meltdown: Reading Kernel Memory from User Space → 멜트다운
- 는 -의 소속이다
- 설명: 조직에 소속된 구성원을 나타낸다.
- 해당노드:
- 구글 프로젝트 제로 → Jann Horn
- 는 -가 도입했다
- 설명: 하드웨어 기술을 도입한 인물을 나타낸다.
- 해당노드:
- 비순차적 명령어 처리 → Robert Tomasulo
- 는 -에게 무력하다
- 설명: 공격이 무력한 마이크로아키텍처를 나타낸다..
- 해당노드:
- 멜트다운 → 젠
스토리
스펙터와 멜트다운의 발견
구글의 보안 조직, 프로젝트 제로에 소속된 연구원 Jann Horn은 2017년 4월부터 프로세서 칩셋들의 메뉴얼들을 읽기 시작했음. 원래의 목적은 그가 만든 수치 처리 코드를 컴퓨터 하드웨어가 처리할 수 있는지 확인하기 위한 것이었으나, 어느 순간 칩이 추측 실행을 처리하는 방식과 요구된 데이터를 가져오는 것에 주의를 기울이게 된 Horn은, 그들이 작업하던 코드 패턴이 잠재적으로 숨겨진 데이터를 유출할 수도 있다는 것을 알게 되었고 취약점으로 이어지는 추가적인 조사가 필요할 것이라 생각함. 그라츠 공대의 팀을 포함해 취리히의 구글 연구진들과 단계적인 절차를 논의했는데, 이들은 이후 Horn과 취약점을 기술하는 문서를 공동 집필하게 됨. 인텔, ARM, AMD 등 주요 하드웨어 제조사들과의 물밑 접촉은 6월부터 시작되었으나 제대로 된 대책이 마련되기까지 작업을 비밀리에 진행할 수밖에 없었고, 이러한 이유로 실제 취약점의 공개는 엠바고가 풀린 다음 해인 2018년 1월에 이루어졌음. 취약점의 공개는 다음의 과정들을 포함하였음.
- 보고서 공개
- CVE ID 발행
- 스펙터 : CVE-2017-5753, CVE-2017-5715
- 멜트다운 : CVE-2017-5754
- 웹사이트 개설
공격 원리 파헤치기
스펙터
취약점의 근본 원인인 추측 실행(speculative execution)으로부터 이름을 따옴. 고치기 힘든 버그인만큼, 꽤 오랫동안 유령처럼 출몰해올 것.[1] 스펙터 공격은 '경계 검사 우회(CVE-2017-5753)', '분기 타깃 주입(CVE-2017-5715)'의 두 이형으로 나눌 수 있음.
- 경계 검사 우회(CVE-2017-5753)
if (x < array1_size) y = array2[array1[x] * 4096];
- 위의 코드가, 신뢰되지 않은 출처로부터 unsigned integer x 값을 받는 (system call 또는 라이브러리) 함수의 일부라고 가정. 해당 코드를 실행하는 프로세스는 unsigned byte 단위 배열 array1, 그리고 1MB 크기 두 번째 byte 배열 array2에 대한 접근을 가짐. 코드는 x에 대한 경계 검사로부터 시작하는데 이는 보안에 있어 필수적임. 만약 경계 검사를 하지 않는다면, 경계 범위 바깥의 입력 x가 예외를 일으키거나, 배열의 기저 주소로부터의 오프셋 x를 전달하여 프로세서가 접근에 민감한 메모리를 접근하도록 만들 수 있을 것임.
- 컴파일된 위의 코드가 실행될 때, 프로세서는 x의 악성값을 array1_size와 비교하는 것으로 시작. array1_size를 읽는 것은 캐시 미스[2]를 발생시키고, 프로세서는 그것의 값이 DRAM으로부터 가용해질 때까지 상당한 지연을 겪게 됨. 특히 분기 조건 또는 분기 이전 위치의 명령어의 경우, 캐시되지 않은 인수를 기다린다면 분기 결과가 결정되기까지 많은 시간이 걸릴 것. 그동안 분기 예측기는 if 조건이 참일 것이라 가정하고, 해당 추측에 따라서 array1의 기저 주소에 x를 더한 뒤 메모리 서브시스템으로부터 결과 주소 위치의 데이터를 요청함으로써 실행 시간 효율을 높이는 데, 이것이 바로 분기 예측과 추측 실행 기술의 핵심임. 이 읽기 작업은 캐시 히트일 것이며 숨겨진 바이트 k의 값을 빠르게 반환할 것. 추측 실행 로직은 k를 이용해 array2[k * 4096] 주소를 계산할 수 있음. 다음으로 메모리로부터 해당 주소를 읽기 위한 요청을 전달함(이는 캐시 미스를 유발.)
- array2로부터 읽기가 진행 중인 동안, 분기 결과가 최종적으로 결정될 수 있음. 프로세서는 추측이 잘못되었음을 깨닫게 될 것이며 추측 실행으로 변경된 레지스터 상태들을 모두 되돌릴 것임. 하지만, array2로부터 추측 읽기는 주소 특정적인 방식으로 k에 기반하는 주소에 따라 캐시 상태에 영향을 미치며, 이 결과는 추측 실행 복귀에 의해 되돌려지지 않음. 공격을 완성하기 위해, 공격자는 array2가 캐시의 어느 위치로 옮겨졌는지 측정함. 이때 캐시에 대한 부채널 공격[3] Flush+Reload, 또는 Prime+Probe 등이 사용될 수 있음. 추측 실행 시에 array2[k * 4096]을 캐시했기에, 결국 k 값을 밝혀낼 수 있음.
- 분기 타깃 주입(CVE-2017-5715)
- 스펙터의 두 번째 이형에서 공격자는 ROP[4] 공격의 활용으로서, 목표 프로세스의 주소 공간에서 가젯을 선택하고, 목표가 가젯을 추측 실행하도록 유도함.
- 공격자는 자신이 선택한 위치에서 추측 실행이 진행되게 하기 위해 분기 예측기를 악성 목적지로 훈련시킴. 분기 타깃 버퍼[5]를 훈련시키기 위해, 공격자는 목표 프로세스의 주소 공간에서 가젯의 가상 주소를 찾고, 이 주소에 대해 간접 분기[6]를 수행. 이 훈련은 공격자의 주소 공간에서 이루어짐. 공격자의 주소 공간의 가젯 주소 위치에 무엇이 상주하는지는 문제되지 않으며, 요구되는 조건의 전부는 훈련 중 공격자의 가상 주소들이 목표의 그것들과 일치해야 한다는 점뿐임.
- 공격자가 선택한 위치에서 추측 실행이 진행된다면 주목할 만한 부수 효과들을 남길 수 있을 것인데, 공격 가능한 조건 분기 예측 실패가 없는 상황에서도 목표 프로세스 메모리를 노출시킬 수 있기 때문에, 이 방법은 공격자에게 매우 강력한 수단이 됨.
멜트다운
취약점은 근본적으로 하드웨어에 의해 강제되는 보안 경계들을 '녹여버림.'[7] 멜트다운 공격은 '불량 데이터 캐시 적재(CVE-2017-5754)'를 기반으로 수행됨.
- 불량 데이터 캐시 적재(CVE-2017-5754)
; rcx = kernel address, rbx = probe array xor rax, rax retry : mov al, byte [rcx] shl rax, 0xc jz retry mov rbx, qword [rbx + rax]
- RCX 레지스터에 적재된 타깃 커널 주소에 위치한 바이트 값을, AL로 나타내어지는 RAX 레지스터의 최하위 바이트로 옮김. MOV 명령어는 코어에 의해 인출되어, 마이크로 연산[8]으로 해독되고, 할당되어, 리오더 버퍼로 보내짐. 아키텍처의 영역에 속하는 레지스터들(예를 들어 RAX와 RCX)은 비순차적 명령어 처리를 가능케 하는 하위의 물리 레지스터들에 매핑됨. 파이프라인을 가능한 한 최대로 활용하기 위해, 후속 명령어들(shl ~ mov)도 함께 해독되고 마이크로 연산으로 할당됨. 마이크로 연산들은 일치하는 실행 유닛에 의해 실행되기 위해 기다리는, 명령어 대기열로 옮겨짐. 피연산자가 아직 계산되지 않았거나, 실행 유닛이 이미 해당하는 용량을 수용하고 있다면 마이크로 연산의 실행은 지연될 수 있음. 첫 mov 명령어에서 커널 주소가 도착했을 때, 이미 CPU가 후속 명령어들을 비순차적 명령어 처리의 일부로서 보냈을 가능성이 크며, 그들의 마이크로 연산들은 명령어 대기열에서 커널 주소의 내용이 도착하기를 기다리고 있을 것임. 공통 데이터 버스에 인출된 데이터가 도착하는 대로, 마이크로 연산들은 그들의 실행을 시작할 수 있음. 마이크로 연산들이 실행을 끝내면, 그들은 순서대로 완료하며, 그 결과들이 아키텍처 상태에 반영됨. 완료 과정 중에, 명령어의 실행 도중 발생한 어떠한 인터럽트나 예외들이 처리됨. 따라서, 만약 커널 주소를 로드하는 MOV 명령어가 완료한다면, 예외가 등록되고, 비순차적으로 실행된 모든 후속 명령어들의 결과들을 제거하기 위해 파이프라인이 flush될 것. 하지만, 이 예외를 일으키는 것과 공격의 진행 사이엔 경쟁 상태[9]가 있음.
- 앞의 단계의 비순차적으로 실행된 명령어 시퀀스는 순간적인 명령어 시퀀스가 되는 방향으로 선택되어야 함. 만약 이들 순간적인 명령어 시퀀스가 MOV 명령어가 완료하기 전에 실행된다면, 그리고 순간적인 명령어 시퀀스가 비밀 데이터를 기반으로 연산을 수행했다면, 이는 비밀을 공격자에게 전달하기 위한 수단으로 활용될 수 있을 것임. shl 명령어에서 앞의 단계의 비밀 값이 페이지 크기(예를 들어 4KB)로 곱해짐. 비밀의 곱은 배열에의 접근들이 각각 큰 공간적 거리를 둠을 보장함. 이는 하드웨어 프리패처가 캐시에 인접한 메모리 위치를 로딩하는 것을 방지. 여기서, 우리는 한 번에 하나의 바이트씩만을 읽으며, 이런 이유로 우리의 조사 배열은 4KB 페이지를 가정하여, 256 × 4096 byte 배열을 형성함. 비순차적 명령어 처리에서 우리는 레지스터 값 '0'에 대해 노이즈 편향을 가짐. 이러한 이유로, 순간적인 명령어 시퀀스에 재시도 로직을 둠. 마지막 mov 명령에서, 곱해진 비밀 값은 조사 배열의 기저 주소에 더해지고, 은닉 채널의 타깃 주소를 형성함. 이 주소는 연관된 캐시 라인을 캐시하기 위해 읽혀짐. 주소는 요청한 코어의 L1 데이터 캐시에 로드될 것이고, 포괄성으로 인해, 또한 다른 코어에 의해서도 읽히는 L3 캐시에도 존재할 것. 그 결과 순간적인 명령어 시퀀스는 앞의 단계에서 읽힌 비밀 값에 기반해 캐시에 영향을 미침.
- 공격자는 마이크로아키텍처 영역의 부채널 공격을 수행하여 비밀 값을 복원. 이는 캐시 상태를 아키텍처 영역의 상태로 옮기는 것. 순간적인 명령어 시퀀스가 실행될 때, 정확히 조사 배열의 한 캐시 라인이 캐시됨. 조사 배열 내의 캐시된 캐시 라인의 위치는 오직 앞에서 읽은 비밀에만 의존함. 따라서, 공격자는 조사 배열의 모든 256 페이지들을 돌며 페이지 상의 모든 첫 번째 캐시 라인에 대해 접근 시간을 측정. 캐시된 캐시 라인을 포함하는 페이지의 번호는 비밀 값과 정확히 일치함.
- 시연 영상
"인텔" CPU게이트
스펙터와 멜트다운 취약점을 필두로 한 CPU게이트는 IT업계 전체를 뒤흔들었음. 취약점의 대상이 되는 분기 예측, 추측 실행, 비순차적 명령어 처리는 대다수의 현대 프로세서들이 사용하는 기술이기에, 개인 컴퓨터, 모바일 기기, 클라우드 등 대부분의 기기들은 공격으로부터 자유롭지 못하였음. 특히 전 세계 80% 이상의 PC와 서버에서 사용되는 인텔 CPU의 피해 가능성은, 1995년 이후의 거의 모든 인텔 프로세서들이 공격에 영향을 받는다는 공식 자료의 언급대로, 매우 높았으며 이 사태는 인텔에게 최악의 위기로 다가왔음. '인텔 CPU 게이트'라는 명칭은 이러한 인텔의 상황에서 비롯된 것임. 놀랍게도 AMD의 CPU들은 비순차적 명령어 처리 기술을 사용하면서도 멜트다운 공격에 영향 받지 않았는데, 이는 인텔과는 다른 마이크로아키텍처 설계 방식에서 비롯된 차이로, 마이크로 연산이 완료되기 전에 빠른 예외 처리를 적용하는 방식을 택하였기에 멜트다운 공격을 피할 수 있었던 것.
각주
- ↑ 출처 : https://spectreattack.com/
- ↑ 캐시는 주 기억 장치와 CPU 사이에서 자주 접근되는 데이터나 명령어들을 저장해두는 고속 버퍼 메모리로, 요청된 데이터가 캐시에서 발견되는 경우를 캐시 히트라고 하고, 캐시 내에 없을 때는 이를 캐시 미스라고 함.
- ↑ 암호 체계나 시스템의 물리적인 구현 과정의 정보를 기반으로 하는 공격 방법으로, 캐시에 사용되는 소요 시간 분석의 경우 다양한 계산을 하는 데 소요되는 시간을 측정하는 것을 기반으로 함.
- ↑ 반환 지향형 프로그래밍. 이 기법에서 공격자는 프로그램의 제어 흐름을 하이재킹하기 위해 호출 스택의 제어를 얻고, '가젯'이라 불리는 신중히 선택된 기계어들을 실행함. 각 가젯은 일반적으로 연결됨으로써 의미를 구현하는 몇몇 명령어들과 함께 마지막에 반환 명령어(ret)로 끝남.
- ↑ 분기 예측에 사용되는 프로세서 구성 요소로 분기 명령의 위치와 해당 명령의 타깃 주소를 담고 있음.
- ↑ 다음 실행할 명령어의 주소를 직접 명시하는 대신, 주소가 위치한 곳을 명시하는 인수를 갖는 프로그램 제어 명령어 유형.
- ↑ 출처 : https://meltdownattack.com/
- ↑ 하나의 명령어는 여러 개의 마이크로 연산으로서 수행됨.
- ↑ 둘 이상의 입력 또는 조작의 타이밍이나 순서가 결과값에 영향을 줄 수 있는 상태를 말함.