- CVE-2019-2525과 CVE-2019-2548을 이용한 VM exploit.
Background
3D Acceleration
- VirtaulBox는 3D Acceleration를 제공한다.
- 보통 VM에서 3D기능을 사용하면 속도가 느려지는데
- 3D Acceleration는 호스트(실제 컴퓨터의)의 3D 하드웨어를 사용하게 한다.
- (가상머신 -> 실제 하드웨어 접근)
Chromium
- 3D Acceleration은 Chromium 라이브러리를 기반으로 만들어졌다.
- Chromium은 OpenGL기반으로 3D Graphic을 ‘remote rendering’ 할 수 있는 라이브러리다.
- Client/Server 구조
- VBox는 Chromium에 새로운 프로토콜을 추가했다.
- VBoxHGCM
- HGCM : Host/Guest Communication Manager
- 이 프로토콜을 사용하면, GuestOS에서 실행 중인 Chromium Client가 Host OS 실행 중인 Chromium 서버와 통신이 가능하다.
- Linux에서는 /dev/vboxuser, /dev/vboxguest로 IOCTL 통신하는데,
- 이를 쉽게 사용할 수 있도록 구현한 Chromium python library가 존재한다. (3dpwn)
3dpwn (VBoxHGCM wrapper) library
- Client의 역할은 connect, disconnect, send chromium message이다.
- CRMessage Structure
1 | typedef union { |
1 | typedef struct { |
1 | typedef struct CRMessageOpcodes { |
- Client가 보내야할 Message의 구조는 위와 같이 Opcode + data의 형태이다.
- 통신에 필요한 주요 함수
- hgcm_connect
- hgcm_disconnect
- hgcm_call(conn_id,function,params)
- function
- SHCRGL_GUEST_FN_WRITE_BUFFER
- SHCRGL_GUEST_FN_WRITE_READ_BUFFERED
- 3dpwn에서는 crmsg함수를 통해 통신한다.
Flow
1 | def alloc_buf(client, sz, msg='a'): |
- crmsg함수는 위에 CRMessage 형태의 msg를 인자로 받으며, alloc_buf를 호출한다.
- alloc_buf에서는 SHCRGL_GUEST_FN_WRITE_BUFFER를 인자로 hgcm_call을 하게 된다.
- 이 때, 세번째 인자는 [0,sz,0,msg] 이다.
1 | case SHCRGL_GUEST_FN_WRITE_BUFFER: |
- parameter의 개수와 타입 검사를 한 후 세 번째 인자인 [0,sz,0,msg]를 알맞게 파싱해준다. ([bufID, bufSZ,offset,msg])
- bufID와, msg의 크기를 인자로 svcGetBuffer함수를 호출하는데 이때 반환 값은 CRVBOXSVCBUFFER_t 구조체이다.
1 | typedef struct _CRVBOXSVCBUFFER_t { |
- CRVBOXSVCBUFFER_t 구조는 위와 같다.
1 | static CRVBOXSVCBUFFER_t* svcGetBuffer(uint32_t iBuffer, uint32_t cbBufferSize) |
- svcGetBuffer함수는 인자로 받은 bufID,Size에 맞는 버퍼가 서버에 존재한다면 해당 주소를 반환한다.
1 | else /*allocate new buffer*/ |
- 그렇지 않다면 새로 버퍼를 할당하고, 할당한 주소를 반환한다.
1 | memcpy((void*)((uintptr_t)pSvcBuffer->pData+ui32Offset), pBuffer, cbBuffer); |
- 이 후 할당받은 CRVBOXSVCBUFFER_t 구조체 버퍼의 pdata에 인자로 주었던 offset만큼 더한 위치에 msg를 복사한다.
- 그림으로 정리하면 아래와 같다.
- hgcm_call(client, SHCRGL_GUEST_FN_WRITE_BUFFER, [id, sz, offset, msg])에서 msg를 pdata+offset에 저장.
- alloc_buf호출 이 후 SHCRGL_GUEST_FN_WRITE_READ_BUFFERED를 인자로 다시 한 번 hgcm_call를 호출한다.
- 이 때, 세번째 인자는 [buf, “A”*bufsz, 1337] 이다.
1 | case SHCRGL_GUEST_FN_WRITE_READ_BUFFERED: |
- parameter의 개수와 타입 검사를 한 후 세 번째 인자인 [buf, “A”bufsz, 1337] 를 알맞게 파싱해준다.
- 그리고 다시 bufID와, 0을 인자로 svcGetBuffer함수를 호출한다.
- 반환된 pSvcBuffer를 통해 변수 pBuffer, cbBuffer를 설정하고 crVBoxServerClientWrite함수를 호출한다.
1 | int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer) |
- pClient 변수에 인자 정보를 저장하고 crVBoxServerInternalClientWriteRead 함수를 호출한다.
1 | static void crVBoxServerInternalClientWriteRead(CRClient *pClient) |
- crServerServiceClients 함수를 호출한다.
1 | void |
- crServerServiceClient 함수를 호출한다.
1 | static ClientStatus |
- crServerDispatchMessage 함수를 호출한다.
1 | static void |
- 해당 함수는 msg를 CRMessageOpcodes로 캐스팅 후 crUnpack함수를 호출한다.
- 여기서 data_ptr에는 Opcode+data에서 Opcode를 제외한 data의 주소가 들어간다.
- crUnpack 함수에서 Opcode값에 따른 로직을 처리하게 된다.
- crVBoxServerClientWrite 함수 호출 이 후, svcFreeBuffer 함수를 호출하여 할당한 버퍼를 Free 시킨다.
따라서 alloc_buf에서 할당한 메모리는 crmsg가 호출되기 전까지 Free되지 않으므로 Heap Spray가 가능하다.
Next Posting
- CVE-2019-2525 : crUnpackExtendGetAttribLocation
- CVE-2019-2548 : crServerDispatchReadPixels
- 각각 함수에서 취약점이 발견되었으며 이 두개를 활용하여 VM Exploit이 가능하다.
Reference
- Virtualization Bug #1 Singi (멘토님 강의자료)
- https://github.com/niklasb/3dpwn
- https://labs.f-secure.com/assets/BlogFiles/offensivecon-2019-3d-accelerated-exploitation-jason-matthyser.pdf
- https://wogh8732.tistory.com/273?category=804777
- https://cosyp.tistory.com/247
- https://1993-constant.tistory.com/590?category=927096