CVE-2023-45230: UEFI DHCPv6 드라이버 힙 오버플로우
CVE-2023-45230
- NVD: https://nvd.nist.gov/vuln/detail/cve-2023-45230
- 유형: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
- 프로그램이 메모리 버퍼의 경계를 넘어서는 위치에서 데이터를 읽거나 쓰는 취약점
- 버퍼의 끝을 넘어가는 것뿐만 아니라, 버퍼의 앞부분을 침범하는 경우까지 포함하는 포괄적인 개념이며, 버퍼 오버플로우 또는 메모리 경계 위반 취약점의 상위 개념으로 통용
- CVSS: 8.3 (High)
개요
PixieFail로 알려진 UEFI 네트워크 스택 취약점 중 하나이며, EDK2의 Dhcp6Dxe (DHCPv6 클라이언트 드라이버) 내 Dhcp6SendRequestMsg 함수에서 발견됨
공격자가 조작한 패킷을 보낼 경우, 드라이버가 메모리 할당 크기를 잘못 계산하여 힙 버퍼 오버플로우를 일으키는 취약점이다.
배경지식: DHCPv6 Handshake 절차
DHCPv6는 IP를 할당받기 위해 다음과 같은 4-Way Handshake 절차를 수행한다.
- Solicit (요청): 클라이언트가 "DHCP 서버 있나요?"라고 브로드캐스트
- Advertise (제안): 서버가 "여기 있습니다. 제 Server ID는 이것입니다."라고 응답
- Request (수락 요청): 클라이언트가 해당 서버에게 IP 할당을 공식 요청
- Reply (응답): 서버가 IP 할당 확정 및 완료
취약점 발생 지점: 문제는 2단계(Advertise)에서 3단계(Request)로 넘어가는 과정에서 발생한다. 클라이언트는 3단계 패킷을 만들 때, 2단계에서 서버가 보내준 Server ID를 그대로 복사해서 사용하는데, 바로 이때 공격자가 악의적으로 매우 긴 Server ID를 보내면 클라이언트는 3단계에서 검증 없이 복사하려다 힙 오버플로우를 일으키게 된다.
분석
핵심은 패킷 생성을 위한 메모리 할당 크기와 실제 기록되는 데이터의 크기가 일치하지 않는 데 있다.
1. 메모리 할당 크기 계산 오류
EFI_STATUS
Dhcp6SendRequestMsg (
IN DHCP6_INSTANCE *Instance
)
[...]
//
// Calculate the added length of customized option list.
//
UserLen = 0;
for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
[1] UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
}
//
// Create the Dhcp6 packet and initialize common fields.
//
[2] Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
if (Packet == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
[...]
- [1]번: UserLen 변수에 패킷에 포함될 옵션들의 길이를 합산하고 있다. 여기에는 CLIENT_ARCH_TYPE 등 일반적인 옵션(Instance->Config->OptionList)만 포함
- [2]번: AllocateZeroPool 함수를 통해 DHCP6_BASE_PACKET_SIZE (1024바이트)에 UserLen을 더한 크기만큼 메모리를 할당
정작 패킷에 필수적으로 포함되어야 할 Server ID 옵션의 길이가 누락되어 있다. 즉 Server ID를 넣을 공간을 고려하지 않고 메모리를 할당한 상태
2. 외부 입력값(Server ID)
[...]
//
// Get the server Id from the selected advertisement message.
//
Option = Dhcp6SeekOption (
Instance->AdSelect->Dhcp6.Option,
Instance->AdSelect->Length - 4,
Dhcp6OptServerId
);
if (Option == NULL) {
return EFI_DEVICE_ERROR;
}
ServerId = (EFI_DHCP6_DUID *)(Option + 2);
[...]
위 코드는 서버가 보낸 Advertise 패킷에서 Server ID를 찾아온다. ServerId 데이터는 외부(공격자)가 보낸 값이므로, 길이나 내용이 조작되었을 가능성이 있다. 하지만 코드는 아직 이 데이터의 안전성을 검증하지 않았다.
3. 데이터 복사 및 버퍼 오버플로우 발생
[...]
//
// Assembly Dhcp6 options for request message.
//
Cursor = Packet->Dhcp6.Option;
Length = HTONS (ClientId->Length);
Cursor = Dhcp6AppendOption (
Cursor,
HTONS (Dhcp6OptClientId),
Length,
ClientId->Duid
);
Cursor = Dhcp6AppendETOption (
Cursor,
Instance,
&Elapsed
);
// 취약점 발생 지점!
Cursor = Dhcp6AppendOption (
Cursor,
HTONS (Dhcp6OptServerId),
ServerId->Length,
ServerId->Duid
);
Dhcp6AppendOption 함수를 호출하여 버퍼에 Server ID를 복사한다. 이때 ServerId->Length가 남은 버퍼 공간보다 작은지 확인하는 절차가 전혀 없다.
Step 1에서 Server ID를 위한 공간을 할당하지 않았으므로, 공격자가 긴 Server ID를 보냈다면 힙 메모리 영역의 끝을 넘어가게 된다.
즉 공격자가 제어하는 데이터(ServerId->Duid)가 인접한 힙 메모리를 덮어쓰는 힙 버퍼 오버플로우가 발생한다.
문제점
취약점은 공격자가 조작된 패킷을 보내는 것만으로 트리거할 수 있음
- RCE: 힙 버퍼 오버플로우를 통해 공격자는 덮어씌워진 메모리 영역에 악성 코드를 주입하고 실행 흐름을 조작할 수 있다.
- DXE 단계에서의 코드 실행 권한을 탈취!
- 보안 부팅 무력화: DXE 단계는 OS 부트로더를 검증하고 실행하는 단계임. 즉 이 부분이 장악당하면 공격자는 Secure Boot 검증 로직을 우회하거나, 서명되지 않은 악성 부트로더를 강제로 실행시킬 수 있음
- OS 재설치나 포맷을 해도 사라지지 않는 펌웨어 레벨의 백도어 설치가 가능
참고
https://www.cve.org/CVERecord?id=CVE-2023-45230