# 소개
멜트다운(Meltdown, "붕괴")은 인텔 x86 마이크로프로세서, IBM 파워 마이크로프로세서 및 일부 ARM 기반 마이크로프로세서에 영향을 주는 하드웨어 취약점이다. 멜트다운 버그는 마이크로프로세서가 컴퓨터의 메모리의 전체를 볼수있도록 프로그램의 접속을 허용하며, 이로 인해서 전체 컴퓨터의 내용에 접근할 수 있다.
- 위키백과
CPU의 성능을 향상시키기 위해 도입된 기술로 인하여
일반 유저 권한의 프로세스가
접근이 보호되어진 커널 영역의
메모리를 읽을 수 있는 취약점
# 배경지식
1. 예측실행
CPU가 한줄의 명령어를 처리하기위해 걸리는 시간은 명령어마다 상이하다
만약 순차적으로 하나씩 처리한다면 정직하게 일을 할 것이다
하지만 최신 프로세서들은 현재 처리중인 명령어 다음에 존재하는 명령어에 필요한
데이터들을 미리 캐시에 로드함으로써 다음 명령어 처리속도를 증대시킨다
이 때 명령2 데이터를 미리 로드해두었지만 명령2가 실행되지 않더라도
해당 데이터의 적합성을 판단하지않고 캐시에 그대로 남겨둔다
2. 커널모드
커널(kernel)은 컴퓨터의 운영 체제의 핵심이 되는 컴퓨터 프로그램의 하나로, 시스템의 모든 것을 완전히 통제한다. 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다. 핵심(核心)이라고도 한다.
컴퓨터의 자원은 CPU, 메모리, 디스크 드라이브 등과 같이 사용될 수 있는 모든 것을 말하며
커널은 이러한 자원들을 효율적으로 관리하는 기능을 수행한다
때문에 커널모드에서는 모든 자원에 접근 및 명령 수행이 가능하다
다만 항상 모든 자원에 접근이 가능하다면
다른 프로세스에서 주요자원에 접근이 가능해지기 때문에
OS(Operating System)와 같은 자원에는 함부로 접근할 수 없도록
유저영역과 커널영역을 분리하였다
또한 커널영역의 자원이 유저영역에서도 필요할 수 있기 때문에
필요에 따라서 커널모드로 진입하여 유저모드에게 자원을 제공해준다
예) 유저모드에서 system call을 요청하면, 커널모드에서 system call을 호출한다
# 취약점 동작 원리
intel에서 제공하는 CPU는 예측 실행 기술을 사용하고 있는데
캐시에 데이터를 미리 로드해둔다는 부분에서 취약점이 발생하게 된다
위 예시를 통해 설명해보면 CPU가 명령을 처리하는 과정에서
명령2를 실행함과 동시에 다음에 존재하는
커널메모리유출 명령에 대한 데이터를 미리 캐시에 로드할 것이다
이후 해당 명령을 처리할 때 커널영역의 메모리는 보호되어있기 때문에
실질적으로는 해당 명령이 실행되지 않는다
그러나 미리 로드해둔 데이터에 대한 적합성은 판정하지 않기때문에
여전히 캐시에 남아있게된다
때문에 캐시에 있는 데이터를 꺼내올 수 있게된다면
커널메모리 영역의 데이터를 얻어낼 수 있다
정리하자면
잘못된 명령어를 미리 실행하여 결과까지 저장한 다음에야
이 실행이 잘못된 것을 인지하기 때문에 발생한 것이고
결과적으로는
커널 메모리 정보를 얻음으로써 권한 상승 취약점 공격까지 가능해진다
# 이해하기 위한 자료
컴퓨터는 모든 것을 숫자로 처리한다. 가령 ASCII코드를 전제할 때 컴퓨터는 ‘a’라는 문자를 97로 이해하고 ‘b’라는 문자를 98로 이해한다. 우리가 키보드로 ‘a’를 칠 때, 컴퓨터는 메모리의 100번째 방에 숫자 ’97’을 적어 넣는다고 치자. 원칙적으로는 OS의 핵심부분인 커널 이외에는 메모리의 100번 방에 무슨 내용이 들어가 있는지 아무도 알 수 없다.[16] 해커는 이 100번째 방의 내용을 노리고자 ‘메모리의 100번째 방을 읽어서 나에게 보내라’고 CPU에게 명령을 내리지만, CPU는 명령을 거부한다. 이게 정상이다. 만약 CPU가 아무에게나 100번째 방의 내용을 보내준다면 가능하다면 비밀번호 등 우리가 키보드로 친 내용들이 유출될 것이다. 그러나 멜트다운 버그를 이용하면 이 100번째 방의 내용을 알 수 있다.
100번째 방의 내용을 읽어 내기 위해 해커는 두 개의 명령을 CPU에게 연속해서 전달한다. 첫 번째는 ‘메모리의 100번 방에 있는 내용을 레지스터 rax로 복사해라’ 이며 두 번째는 ‘1000+rax을 계산한 다음 RAM에서 그 방에 있는 숫자를 가져다 줘’이다. 즉 100번 방의 내용 → rbx → 1000+rax을 통해 해커는 100번 방의 내용을 알아내려고 하는 것이다. 만약 1000+rax이 1097이라면, ‘a’가 97인 점을 이용하여 해커는 키보드에서 ‘a’가 입력되었다는 것을 알아낼 수 있다. 1000+rax이 1098이라면 해커는 ‘b’가 입력되었다는 것을 알 수 있다.
즉, 해커가 시킨 일을 하기 위해 CPU는 다음의 일을 해야 한다.
① 100번 방에서 숫자를 꺼낸다.
② 100번 방에서 꺼낸 숫자를 레지스터 rax에 임시로 저장한다.
③ rax에 저장된 숫자와 1000을 더한다. (여기에서는 1097로 가정하자)
④ ‘③’에서 더한 결과에 해당하는 RAM의 숫자를 꺼낸다. (즉, 1097번 방 자료 꺼낸다.)
⑤ 꺼낸 숫자를 해커에게 전달한다.
그런데 애당초 100번 방에 있는 숫자를 해커가 꺼내라고 한 1번부터 잘못되어 있다. 숫자를 꺼낸 것 자체가 잘못인데, ②, ③, ④, ⑤번을 할 수가 없다. CPU는 메모리의 100번 방에 있는 내용을 rax로 복사 하지도, 1000+rax을 계산해서 RAM의 방 번호를 찾아 내용을 가져다 주지도 않는다.
문제는 CPU의 파이프라인 구조에 있다. 해커가 100번방의 숫자를 꺼내라고 했을 때, CPU는 실제로는 100번 방의 숫자를 꺼낸다. 그리고 RAM의 1097번 방의 숫자도 꺼낸다. 즉, 실제로 CPU는 해커가 시킨 일을 다 한다. 단지 보여주지 않을 뿐이다. 예전까지는 해커한테 보여주지만 않으면 괜찮다고 생각했다. CPU가 일을 다 하고 보여주지만 않으니, CPU가 일한 흔적을 찾아 ‘100번 방의 숫자를 알아내자’라는 것이 멜트다운 버그의 핵심 아이디어이다.
해커는 앞서 간단히 언급한 캐시를 이용한다(캐시는 램보다 속도가 훨씬 빠른 메모리이다). CPU가 RAM의 1097번 방에 있는 정보를 꺼낼 때, 1097번 방의 정보는 자동으로 캐시에 기록된다. RAM에 있는 정보를 캐시로 베껴 써 두면 나중에 다시 볼 때 이를 빠르게 볼 수 있기 때문이다. CPU는 해커에게 RAM에서 일껏 1097번 방의 자료를 꺼내 오고는 해커에게 보여주지는 않는다. 하지만 어쨌든 1097번 방의 자료를 꺼내 왔기에 1097번 방의 정보는 캐시에 들어가 있다. CPU가 RAM을 읽으면 무조건 이 정보는 캐시에 기록되기 때문이다.
이제 해커는 RAM의 1000번 방부터 하나씩 방을 검색하기 시작한다. 1000번 이후의 모든 방들은 캐시에 없기 때문에, 램에서 읽어와야 하므로 읽는 데 시간이 꽤 오래 걸린다. 하지만 1097번 방은 캐시에 있기 때문에, 읽는 데 시간이 적게 걸린다. 해커는 RAM의 1000번 방 이후의 방을 읽을 때마다 읽는 데 걸린 시간을 측정한다. 1097번 방을 읽을 때 시간이 적게 걸리는 것을 잡아내면, 해커는 CPU가 나에게 보여주지는 않았지만, 실제로는 1097번 방을 읽었다는 것을 알게 된다. 이를 근거로 rax에 원래는 97이 들어가야 했다는 것을 알 수 있고 우리가 키보드로 ‘a’를 쳤다는 것을 알 수 있다.
출처 : https://namu.wiki/w/CPU%20%EA%B2%8C%EC%9D%B4%ED%8A%B8?from=CPU%EA%B2%8C%EC%9D%B4%ED%8A%B8
'System Hacking > Study Notes' 카테고리의 다른 글
Unsorted bin attack (0) | 2020.09.18 |
---|---|
[ Kernel ] KAISER와 KPTI, and Exploit (2) | 2020.08.17 |
어셈블리어 구구단 만들기 (3) | 2020.07.01 |
개인 서버 만들기 (with. GCP) (0) | 2020.06.16 |
Large bin attack (0) | 2020.05.04 |