Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Talk is Cheap, Show Me the Code

Di Shen
July 01, 2016

Talk is Cheap, Show Me the Code

Our slides for CVE-2015-1805 exploit & Samsung Knox (S6 ver.) bypassing at MOSEC2016.

Di Shen

July 01, 2016
Tweet

More Decks by Di Shen

Other Decks in Technology

Transcript

  1. Talk is Cheap, Show Me the Code James Fang (@idl3r),

    Di Shen a.k.a. Retme (@returnsme), Wen Niu (@NWMonster) Keen Lab of Tencent How we rooted 10 million phones with one exploit again
  2. About us • Part of Keen Lab • Interested in

    Android kernel security • Mostly the offensive part • Responsible for many PHAs (non-malicious rooting) • PingPong root (CVE-2015-3636) • 1st public CVE-2015-1805 PoC (Dec 2015) • Multiple device specific root
  3. Agenda • Vulnerability Analysis • How to exploit • Arbitrary

    write to code execution • Heap manipulating • Mitigation bypass • Samsung (again) • Others • Conclusion
  4. Motivation • In October,2015 • Time to prepare the next

    generation universal rooting exploit • Hunting new bugs • Reviewing public patch on upstream • CVE-2015-1805 • Introduced in 2006 • Fixed in kernel 3.18 • No patch for 3.10 or earlier • Most of Android devices ship with 3.10 by that time
  5. CVE-2015-1805 • Discovered by @solardiz last year • Exploit or

    impact unknown by that time • Not exploitable?
  6. CVE-2015-1805 • A potential iovec overrun may cause arbitrary write

    in kernel. • struct iovec { void *base; size_t len; } • Write anywhere anything in limited length J 0x1000 0x100 0x1100 0x100 0x1200 0x100 &sys_call_table[200] 0x4 BOOM
  7. Vulnerability Analysis 373 pipe_read(struct kiocb *iocb, const struct iovec *_iov,

    374 unsigned long nr_segs, loff_t pos) 375 { ... 380 struct iovec *iov = (struct iovec *)_iov; 381 size_t total_len; 382 383 total_len = iov_length(iov, nr_segs); ... 390 __pipe_lock(pipe); 391 for (;;) { 392 int bufs = pipe->nrbufs; 393 if (bufs) { 394 int curbuf = pipe->curbuf; 395 struct pipe_buffer *buf = pipe->bufs + curbuf; 396 const struct pipe_buf_operations *ops = buf->ops; 397 void *addr; 398 size_t chars = buf->len; // 4096 or less ... 401 if (chars > total_len) 402 chars = total_len; ... 411 atomic = !iov_fault_in_pages_write(iov, chars); 412 redo: 413 addr = ops->map(pipe, buf, atomic); 414 error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); 415 ops->unmap(pipe, buf, addr); 416 if (unlikely(error)) { 417 /* 418 * Just retry with the slow path if we failed. 419 */ 420 if (atomic) { 421 atomic = 0; 422 goto redo; 423 } 424 if (!ret) 425 ret = error; 426 break; 427 } 428 ret += chars; 429 buf->offset += chars; 430 buf->len -= chars; ... 446 total_len -= chars; 447 if (!total_len) 448 break; /* common path: read succeeded */ 449 } 450 if (bufs) /* More to do? */ 451 continue; ... 477 } 478 __pipe_unlock(pipe); ... 488 } Calc total_len chars = buf->len Probe each iovec for writing atomic = 1 atomic = 0 For each iov (determined by chars) is atomic? copy_to_user copy_to_user_atomic total_len -= chars Remaining buf? N Y Y N Y pipe_read error? atomic? N ERROR Y (set atomic = 0) Process base and len REDO Y N
  8. Vulnerability Analysis • A TOCTOU bug: • Time of check:

    iov_fault_in_pages_write • Time of use: pipe_iov_copy_to_user • Check & use what? • Vmmap page status • Valid during check => atomic == 1 • Invalid during use => REDO • Valid during REDO => overrun J • Race the page table as the “data” • Unconventional data racing
  9. Vulnerability Analysis chars=4096, total_len=4112 0 32 8 8*509 0 8

    4k … chars=4096, total_len=4112, atomic 0 32 8 … 0 8 4k … chars=4064, total_len=4112, copied=32 0 0 8 … 0 8 4k … chars=0, total_len=48, copied=4096 0 0 0*508 8*2 0 8 4k … chars=4096, total_len=48, atomic 0 0 0*508 0*2 0 0 4072 … Check Use (copy #1) REDO Next page chars=4096, total_len=4112, atomic 0 32 8 8*509 0 8 4k … munmap mmap n Thread A n Thread B • Each block represent 1 or more iovec • Only length matters here Calc total_len chars = buf->len Probe each iovec for writing atomic = 1 atomic = 0 For each iov (determined by chars) is atomic? copy_to_user copy_to_user_atomic total_len -= chars Remaining buf? N Y Y N Y pipe_read error? atomic? N ERROR Y (set atomic = 0) Process base and len REDO Y N
  10. Win the race atomic = !iov_fault_in_pages_write(iov, chars); redo: addr =

    ops->map(pipe, buf, atomic); error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); • Create a thread to do mmap and munmap repeatedly • The window is small, but the exploit can be repeated over and over until it win. • ops->map is “kmap”
  11. kmap VS mmap/munmap • Kmap: map the pipe buffer page

    to a kernel virtual addres • The cost of high memory handling can be quite high. • Be used when kernel cannot keep all of the available physical memory mapped at all times • In the arch arm, kernel can only map less than 1GB of physical memory. • In the arch arm64, kmap will simply covert the page struct address onto a pointer to the page contents rather than juggling mappings out. Code: https://github.com/idl3r/testcode/blob/master/test2.c
  12. How to exploit Arbitrary write to code execution Classic Trick

    1: static struct file_operations ptmx_fops; https://github.com/dosomder/iovyroot
  13. How to exploit Arbitrary write to code execution struct sock

    { struct sock_common __sk_common; ... #define sk_prot__sk_common.skc_prot ... void (*sk_destruct)(struct sock *sk); } struct sock_common { ... struct proto *skc_prot; ... } struct proto { ... int (*ioctl)(struct sock *sk, int cmd,unsigned long arg); ... } Trigger functions: int close(int fd); int ioctl(int fd, unsigned long request, ...);
  14. How to exploit Arbitrary write to code execution “xt-qtaguid” Trick:

    1.create a socket. 2.use /proc/self/net/xt_qtaguid/ctrl for Tag that socket. 3.read /proc/self/net/xt_qtaguid/ctrl
  15. • MTK • return-to-direct-mapped memory (ret2dir) • physmap (rwx) •

    Samsung • S6 5.0.2 syscall table (rwx) • Fixed location among different ROMs How to exploit Arbitrary write to code execution
  16. Heap Manipulating chars=4096, total_len=4112 0 32 8 8*509 0 8

    4k … chars=4096, total_len=4112, atomic 0 32 8 … 0 8 4k … chars=4064, total_len=4112, copied=32 0 0 8 … 0 8 4k … chars=0, total_len=48, copied=4096 0 0 0*508 8*2 0 8 4k … chars=4096, total_len=48, atomic 0 0 0*508 0*2 0 0 4072 … Check Use (copy #1) REDO Next page chars=4096, total_len=4112, atomic 0 32 8 8*509 0 8 4k … munmap mmap n Thread A n Thread B • Each block represent 1 or more iovec • Only length matters here • Blocks in blue • good iovecs • Blocks in red • malformed iovecs • Need to spray the heap • Let the iovecs overrun to red page • Arbitrary kernel memory overwritten
  17. Basics of SLUB • Organized physical pages in “kmem_cache’ •

    Each cache hold slabs of objects of the same size • common kmalloc cache: • kmalloc-64,kmalloc-128…kmalloc-4096,kmalloc-8192 • Structure specific cache: • UNIX, UDP, task_struct … • Mergeable slab caches, e.g. PING & UNIX • Objects on a slab are contiguous • Meta-data is overloaded with ‘struct page’ • Except ‘free_list’ which is at the head of object, pointed to next free object • A slab may have allocated and deallocated object
  18. Spray object in kmalloc-8192 • Kmalloc-8192 • Normally objects in

    this cache is not allocated frequently • Much easier than spraying kmalloc-512 J • Allocate a page with malformed iovecs, hope that is just after the page of good iovecs. Good iovecs allocated by readv Sprayed object Overrun Sprayed object
  19. Sendmmsg • Born for crafting kernel memory • Used to

    overwrite kernel stack (CVE-2014-3153) • Used to spray any size and content of object in kmalloc caches persistently (used lots of times in my unpublished exploits) • Used again in CVE-2015-1805 • In this case • Temporarily allocate malformed iovecs in kmalloc-8192 • iovec[] = {0,0},{kernel_addr,8},{user_addr,0x1000}… • Call sendmmsg repeatedly
  20. Failed? Does not matter • Sendmmsg must fail.. • Since

    kernel_addr isn’t a valid user address • Sprayed objects may be freed, which means the first 8 bytes of page may be overwritten as a free_list pointed to next freed object. • Free_list is a pointer to free object or null • Note that the length of first iovec is null! • pipe_iov_copy_to_user just ignore the first iovec and go on 0 0 kernel_addr 8 User_addr 0x1000 User_addr … Free_list 0 kernel_addr 8 User_addr 0x1000 User_addr …
  21. And Here Comes Samsung… • Samsung enforced Knox Active Protection

    since 5.1 ROMs • After PingPong root • Knox Active Protection is enabled before kernel boot • In boot loader • Based on Knox Warranty Void bit status • CONFIG_TIMA_RKP (TIMA Real time kernel protection) • ONLY unlocked device can have KAP disabled
  22. Knox Overview • Depends on existing Knox protection (seen on

    S5 and later devices) • Page table protection • “Protects” key kernel objects • current->cred • current->real_cred • Page table entries (section and page) • Can’t write directly on those objects, needs to call hyper-visor • Can be extended to other kernel objects
  23. Knox Overview • Inaccurate KAP architecture EXPORT rkp_call rkp_call HVC

    #0 RET ; End of function rkp_call SLUB routines Cred routines (incl. fork()) SELinux routines (cred->security) mm routines init code
  24. How to Defeat KAP? • Code reuse? Pain points: •

    Almost all ops table entries takes un-controllable pointer as input • May corrupt the object to control the pointer, but takes risk • Hard to find decent gadget controlling X0 and ends with an BR • Not BLR since we need to keep LR intact calling into a function • There is a good entry but only takes 32-bit input: • And it returns an int as well… 1517 struct file_operations { 1518 struct module *owner; ... 1538 int (*check_flags)(int); ... 1546 };
  25. Shoot Itself in the Foot… • An interesting function •

    Replaces override_creds in case of Knox • Intended for temporary credential override • Takes a pointer to pointer instead! • And no check of this pointer’s origin!!
  26. Conclusion • Stronger defense • KASLR • TIMA • YunOS

    • Root vs. Malware • Iovy root • Ghost Push
  27. Exploit, exploit never changes • Our new rooting exploit will

    be released in the not too distant future • Code-named Valkyrie • AFAIK, this is: • *************** • *************** • *************** • ***************