[하루한줄] CVE-2021-2145: Oracle VirtualBox의 권한 상승 취약점
URL
GSOh No! Hunting for Vulnerabilities in VirtualBox Network Offloads
Target
- Oracle VirtualBox
Explain
Oracle사의 가상화 프로그램 VirtualBox에서 세 취약점이 발견되었습니다. heap buffer overflow로 트리거되는 권한 상승 취약점 둘과 Out-of-Bounds로 인한 정보 유출 취약점입니다.
취약점들은 게스트 머신에서 외부 네트워크로 패킷을 보내는 데 사용되는 NAT의 반가상화 GSO 구현 코드에서 발견되었습니다.
GSO(Generic Segmentation Offload) : 패킷을 외부로 전송 시 분할하는 과정을 CPU가 아닌 NIC가 처리하는 오프로딩(연산 중 일부를 프로세서가 아닌 다른 장치에서 처리) 방법
CVE-2021-2145 – Oracle VirtualBox NAT Integer Underflow Privilege Escalation Vulnerability
NAT 코드는 GSO 프레임을 수신하면 전체 이더넷 패킷을 가져와 새 mbuf
메시지 버퍼를 할당하고 패킷을 mbuf
에 복사합니다. mbuf
는 TCP/IP 에뮬레이션용 라이브러리인 Slirp 라이브러리에 전달됩니다.
아래의 함수는 size
를 MCLBYTES
로 초기화해 초기값 0x800
을 가지며, 이후에 if~else if
루틴에서 cbMin
이 이보다 크면 MJUM9BYTES(0x2400)
, MJUM16BYTES(0x4000)
으로 size
를 설정해 할당 크기를 결정하고 cbMin
크기의 데이터를 복사합니다.
struct mbuf *slirp_ext_m_get(PNATState pData, size_t cbMin, void **ppvBuf, size_t *pcbBuf)
{
struct mbuf *m;
int size = MCLBYTES; // 0x800 bytes
LogFlowFunc(("ENTER: cbMin:%d, ppvBuf:%p, pcbBuf:%p\n", cbMin, ppvBuf, pcbBuf));
if (cbMin < MCLBYTES)
size = MCLBYTES; // 0x800 bytes
else if (cbMin < MJUM9BYTES)
size = MJUM9BYTES; // 0x2400 bytes
else if (cbMin < MJUM16BYTES)
size = MJUM16BYTES; // 0x4000 bytes
else
AssertMsgFailed(("Unsupported size"));
m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
...
문제는 size
가 MJUM16BYTES(0x4000)
보다 클때 발생합니다. size
가 MJUM16BYTES
보다 크면 AssertMsgFailed
함수를 호출해 예외를 발생시킵니다. 그러나 AssertMsgFailed
는 디버그 모드에서만 작동하는 Assert 문으로 릴리즈 모드에서는 작동하지 않습니다. 따라서 릴리즈 모드에서는 아래 코드만 실행됩니다.
if (cbMin < MCLBYTES)
size = MCLBYTES; // 0x800 bytes
else if (cbMin < MJUM9BYTES)
size = MJUM9BYTES; // 0x2400 bytes
else if (cbMin < MJUM16BYTES)
size = MJUM16BYTES; // 0x4000 bytes
m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
만약 cbMin
이 0x4000
을 넘는다면 위 조건문들을 모두 통과하게 되고 size
의 초기값인 0x800
만큼할당합니다. 따라서 0x800
크기로 할당된 힙에 0x4000
크기의 데이터가 복사되면서 heap buffer overflow가 트리거되며 권한 상승으로 이어질 수 있습니다.
CVE-2021-2310 - Oracle VirtualBox NAT Heap-based Buffer Overflow Privilege Escalation Vulnerability
게스트가 제공한 GSO 매개변수가 유효한지 확인하는 PDMNetGsoIsValid
함수에서 Assert 함수가 존재합니다.
DECLINLINE(uint32_t) PDMNetGsoCalcSegmentCount(PCPDMNETWORKGSO pGso, size_t cbFrame)
{
size_t cbPayload;
Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame));
cbPayload = cbFrame - pGso->cbHdrsSeg;
return (uint32_t)((cbPayload + pGso->cbMaxSeg - 1) / pGso->cbMaxSeg);
}
릴리즈 빌드에서 컴파일되지 않는 Assert로 인해 GSO 매개변수가 유효한지 확인하는 PDMNetGsoIsValid
함수가 호출되지 않고, 그 결과로 유효하지 않은 GSO 매개변수가 허용되며 이후 이 매개변수는 memcpy
의 인자로 사용됩니다. 따라서 할당된 크기보다 더 많은 데이터를 복사하도록 매개변수를 전달해 heap buffer overflow를 통한 권한 상승이 가능합니다.
CVE-2021-2442 - Oracle VirtualBox NAT UDP Header Out-of-Bounds
VirtualBox는 TCP와 UDP에 대해 체크섬 오프로딩을 지원하는데, 체크섬 오프로딩 수행 과정에서 호출되는 RTNetUDPChecksum
함수에 취약점이 존재합니다.
RTDECL(uint16_t) RTNetUDPChecksum(uint32_t u32Sum, PCRTNETUDP pUdpHdr)
{
bool fOdd;
u32Sum = rtNetIPv4AddUDPChecksum(pUdpHdr, u32Sum);
fOdd = false;
u32Sum = rtNetIPv4AddDataChecksum(pUdpHdr + 1, RT_BE2H_U16(pUdpHdr->uh_ulen) - sizeof(*pUdpHdr), u32Sum, &fOdd);
return rtNetIPv4FinalizeChecksum(u32Sum);
}
pUdpHdr→uh_ulen
의 범위 검사가 없어 sizeof(*pUdpHdr)
보다 작은 경우 연산 과정에서 integer underflow가 발생하고 이로 인해 OOB Access로 인한 정보 유출이 가능합니다.
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.