Home > 졸업프로젝트 > UEFI DXE 바이너리 취약점 분석기 프로젝트_3

UEFI DXE 바이너리 취약점 분석기 프로젝트_3
UEFI Ghidra

Memory Map

 메모리 맵은 시스템의 RAM과 특정 영역의 분포를 나타낸 표로, OS가 메모리를 정상적으로 사용할 수 있도록 UEFI는 이 정보를 커널에 전달한다. 쉽게 생각해서
여기부터 여기까지는 중요한 부분이야!, 여기부터 여기까지는 사용해도 돼!
를 OS에게 알려주는 부분이라고 볼 수 있다.

 흔히 생각하는 버퍼 오버플로우나 Null-Pointer 역참조, 또는 지난 시간에 공부했던 Callout 공격이나 CommBuffer 공격들은 대부분 결국 엉뚱한 메모리를 건들면서 생기는 문제들이라 볼 수 있다.
제목
Windows에서 vmware를 통해 직접 EFI Shell을 실행한 뒤 memmap 명령어를 통해 메모리를 관찰한 결과다. 뭔가 정말 많이 떠있어 읽기 힘든 것을 볼 수 있다.
제목
UEFI.org에서 가져온 각 영역에 대한 설명이다. 내용들이 매우 많아보이지만 차근차근 보자.
 가장 먼저 Mnemonic 부분이다. 이 부분은 각 영역이 무엇인지에 대한 이름 정도라고 볼 수 있다.

Type 이름 설명
0 EfiReservedMemoryType 아무튼 예약된 메모리
1 EfiLoaderCode OS 로더 코드가 올라갔던 곳
2 EfiLoaderData OS 로더가 실행중에 쓴 데이터 영역
3 EfiBootServicesCode 부팅 단계에서만 필요한 드라이버들의 코드
4 EfiBootServicesData 부팅 단계에서만 필요한 드라이버들의 데이터
5 EfiRuntimeServicesCode OS 실행 중에도 불려야하는 서비스들의 코드
6 EfiRuntimeServicesData OS 실행 중에도 불려야하는 서비스들의 데이터
7 EfiConventionalMemory 여유 공간
8 EfiUnusableMemory 메모리 테스트 중 오류가 발견된 공간
9 EfiACPIReclaimMemory ACPI 테이블의 공간
10 EfiACPIMemoryNVS ACPI NVS 메모리
11 EfiMemoryMappedIO 하드웨어 장치의 레지스터와 연결된 주소
12 EfiMemoryMappedIOPortSpace I/O 포트의 번역기
13 EfiPalCode 서버용 CPU의 펌웨어 코드
14 EfiPersistentMemory 영구 메모리 구역

(출처)

오른쪽 ACPI Address Range Type 부분은 일명 OS가 이 구간은 써도 되는지에 대해 UEFI가 OS에 알려주는 부분이다.

AddressRangeReserved : UEFI가 사용하고 있는 메모리. 맘대로 수정하면 안된다
AddressRangeMemory : 부팅이 끝난 뒤 초기화되는 메모리. 마음대로 사용 가능
AddressRangeACPI : ACPI 테이블(하드웨어 정보 등에 관한 테이블). 정보를 다 가져간 뒤엔 OS 사용 가능
AddressRangeNVS : ACPI NVS 메모리(시스템 전원 관리 및 절전 모드 작동 등에 사용). 맘대로 수정 불가
AddressRangePersistentMemory : 비휘발성. 컴퓨터를 껐다 켜도 데이터가 남아있는 구역
(출처)

지난 주차에서 공부했던 내용을 생각하며 우리가 여기서 봐야 하는건
SMM 코드가 드라이버가 외부에 있는 주소를 사용하려 하는가
정도가 될 것이라 생각한다.

 지난 시간에 공부했든 SMM 코드는 SMRAM 내 코드가 아니면 실행하면 안된다. 하지만 이 SMM이 BS_Code나 RT_Code를 실행한다면?
만약 해커가 악의적으로 Ring 0 권한을 탈취 후 RT_Code의 쓰기 방지를 풀고 Payload를 심었거나, 무방비 구역인 BS_Code구역에 Payload를 심었고, 이 부분을 SMM이 Call을 한다면?
이게 바로 SMM Callouts 공격이 되는 것이다.
이 링크는 AMD의 SMM Callout에 대한 실제 CVE로, 입력 버퍼에 유효성 검사가 존재하지 않아 SMM Callout 취약점이 발생할 수도 있다는 것을 의미한다.

Save State

 지난 시간 SMM에 대해 공부했을 때 Save State에 대한 부분을 작성하지 않았던 것 같아 추가적으로 작성하기로 하였다. Save State는 SMRAM의 일부분으로, SMRAM의 어떤 부분을 덮어쓰면 위험한데? 라는 질문의 대답이 될 수 있을 것이다.
제목
(출처)
SMRAM의 구조이다. Save State는 SMI가 걸려 SMM 모드로 들어가는 순간의 레지스터 값 등을 Save State라는 곳에 저장하고, 일을 마치면 저장한 값을 다시 불러오는 데에 사용한다.

Low SMRAM Corruption

(출처)
 지난 시간 공부했던 CommBuffer 공격이 SMM이 있는 SMRAM을 침범하는 공격이라고 하였다. 물론 CommBuffer를 SMRAM에 할당받지 못하도록 방어하는 다양한 보호 기법들이 있다. SmmIsBufferOutsideSmmValid 함수가 바로 이런 보호 기법 중 하나다. SmmIsBufferOutsideSmmValid 함수는 인텔의 표준 UEFI 레퍼런스 구현체인 EDK2에 구현되어있는 함수로, CommBuffer가 SMRAM을 침범했는지 여부를 확인해주는 함수다.
 가끔 SmmIsBufferOutsideSmmValid 함수를 개발 과정에서 까먹고 넣지 않는 경우가 있거나, 또는 CommBuffer 크기를 넘겨주지 않는 경우, 또는 핸들러 자체가 너무 허술할 경우 등이 있는데, 이런 경우 공격 대상이 될 수 있다. 대표적 사례로 Low SMRAM Corruption 공격이 있다.
제목
위 함수와 같은 핸들러가 취약한 SMI 핸들러의 예시가 될 수 있는데, 빨간 박스를 보면 CommBuffer의 범위에 따른 유효성 검사 없이 그냥 채워져만 있으면 통과를 시켜준다. 또한 노란 박스를 통해 CommBuffer의 시작 주소에 64비트, 즉 8바이트를 냅다 주는 것을 알 수 있다! 이 핸들러에 Low SMRAM 공격을 할 수 있다. 간략하게 순서는 다음과 같다.

  1. CommBuffer를 SMRAM 바로 밑에 위치시킨다.(SMRAM - 1)
  2. CommBuffer의 크기를 1바이트와 같이 작은 숫자로 설정한다.
  3. 취약한 SMI 핸들러를 작동시킨다.

제목
그렇게 되면 위 그림과 같이 겉으로 보기엔 아무 이상 없는 것처럼 보이므로 SmmIsBufferOutsideSmmValid 함수도 통과하여 SMI 핸들러로 들어오게 될 것이다. 그런데 이 핸들러가 SMRAM 한 칸 밑에 있는 CommBuffer를 8바이트로 늘려버린다면?
제목
위와 같이 SMRAM을 CommBuffer가 침범하게 된다.

Nested Pointer를 통한 SMRAM 침범 공격 문제 공부중…