iOS Kernel Heap Armageddon
iOS Kernel Heap Armageddon
de
Who am I?
Stefan Esser
from Cologne / Germany in information security since 1998 PHP core developer since 2001 Month of PHP Bugs and Suhosin recently focused on iPhone security (ASLR, jailbreak) Head of Research and Development at SektionEins GmbH
Recap...
public iOS kernel heap research can be summarized as there is a kernel heap zone allocator it comes with heap meta data which can be exploited here is one possible way
zone allocator recap other kernel heap managers / wrappers recent changes in the allocators cross zone attacks kernel level application data overwrite attacks generic heap massage technique
Part I
Zone Allocator Recap
0x1000
head of freelist
head of freelist
head of freelist
attacker data
head of freelist
Part II
Other Heap Managers and Wrappers
not necessary a complete overview Stefan Esser iOS Kernel Heap Armageddon April 2012 ! 14
kalloc()
kalloc() is a wrapper around zalloc() and kmem_alloc() it adds no additional heap meta data caller needs to keep track of allocated size
for small requests zalloc() is used for bigger requests kmem_alloc() is used kalloc() registers several zones with names like kalloc.*
kfree()
kfree() is a bit special protection against double frees keeps track of largest allocated memory block attempt to kfree() a larger block is a NOP
_MALLOC()
_MALLOC() is a wrapper around kalloc() it adds the blocksize as additional heap meta data so the caller does not need to keep track of allocated size it refuses to allocate 0 byte sizes
size + 4
& M_NOWAIT) { (void *)kalloc_noblock(memsize); (void *)kalloc(memsize); struct _mhead { size_t mlen; char dat[0]; }
= memsize;
(hdr->dat);
return
(hdr->dat);
changing the size of a memory block freeing the block will put it in the wrong freelist
smaller sizes will leak some memory bigger sizes will result in buffer overows
size + 4
kern_os_malloc()
kern_os_malloc() is very similar to _MALLOC() it also adds the blocksize as additional heap meta data it also refuses to allocate 0 byte sizes new and new[] simply wrap around it special case: new[0] will allocate 1 byte
size + 4
kernel_memory_allocate
master entry point for allocating kernel memory allocates memory in a specic map allocates always whole pages requests for more than 1 GB fail immediately keeps a bunch of heap meta data inside a separate kernel zone no inbound meta data
Part III
Cross Zone or Cross Memory Allocator Attacks?
what is the relative position of kernel zones to each other? what is the relative position of pages inside the same kernel zone? is it possible to overow from one kernel zone into another?
we allocated about 48MB of kernel memory through single page zones all returned memory is between 0x80000000 and 0x8FFFFFFF we visualize the pages returned by the kernel zone allocator
you will observe a different result when looking at allocations > 1 PAGE
Stefan Esser iOS Kernel Heap Armageddon April 2012 ! 31
zone page allocator seems to be random but several clusters in the beginning of the address space and end but that was only one run so lets do an average across 25 reboots
accross 25 reboots there was a single common page among all the allocations the 26th reboot made it go away because of the randomness adjacent memory pages are very unlikely it is not possible to say anything about the relative position of pages overowing out of a page will most likely crash
most of the allocation functions deeply down use the zone allocator if allocation functions share the same zone then cross attacks are possible everything based on kalloc() is affected
Part IV
Kernel Heap Application Data Overwrites
(a kernel c++ object case study)
iOS kernels libkern supports a subset of C++ allows kernel drivers to be C++ and indeed only used by kernel drivers - mostly IOKit brings C++ vulnerability classes to the iOS kernel libkern C++ runtime comes with a set of base object
802A1570 ; `vtable for'OSObject 802A1570 __ZTV8OSObject 802A1570 DCD 0 802A1574 DCD 0 802A1578 DCD sub_801E7C0C+1 802A157C DCD __ZN8OSObjectD0Ev+1 802A1580 DCD __ZNK8OSObject7releaseEi+1 802A1584 DCD __ZNK8OSObject14getRetainCountEv+1 802A1588 DCD __ZNK8OSObject6retainEv+1 802A158C DCD __ZNK8OSObject7releaseEv+1 802A1590 DCD __ZNK8OSObject9serializeEP11OSSerialize+1 802A1594 DCD __ZNK8OSObject12getMetaClassEv+1 802A1598 DCD __ZNK15OSMetaClassBase9isEqualToEPKS_+1 802A159C DCD __ZNK8OSObject12taggedRetainEPKv+1 802A15A0 DCD __ZNK8OSObject13taggedReleaseEPKv+1 802A15A4 DCD __ZNK8OSObject13taggedReleaseEPKvi+1 802A15A8 DCD __ZN8OSObject4initEv+1 802A15AC DCD __ZN8OSObject4freeEv+1
reference counter for objects 32 bit eld - but only lower 16 bit are the reference counter upper 16 bit used as collection reference counter reference counting stops at 65534 -> memory leak
overwriting or corrupting the vtable ptr everything the kernel will do with the object will trigger code exec
0x00 0x04
overwriting the retain count might allow freeing the object early
0x08
allows kernel heap information leaks on free arbitrary pointer ends up in kalloc zone
Part V
Generic Technique to control the iOS Kernel Heap
Heap Spraying
ll up kernel heap with arbitrary data
Heap Feng Shui or Heap Massage or Heap Setup or Heap Layout Control
bring the kernel heap into a known state by carefully crafted allocations and deallocations
public iOS kernel exploits use vulnerability specic (de-)allocations we want a more generic solution
Heap Spraying
allocate repeatedly allocate attacker controlled data allocate large quantities of data in a row usually ll memory with specic pattern
allocate repeatedly (to close all memory holes) allocate arbitrary sized memory blocks poke allocation holes in specic positions control the memory layout ll memory with interesting meta / application data
OSUnserializeXML()
deserialization of iOS kernel base objects used to pass objects from user space to kernel space (IOKit API) data in XML .plist format numbers, booleans, strings, data, dictionaries, arrays, sets and references
0 "> . 1 " = n o i s r e v t s <pli <dict> > y> g e n k i / r < t e s r / e < h ? T l s l I a > y m e <k le the u r o t e u q i n h c e <string>one t y> <key>Answer</ke <true /> ey> k / < e c n e i d g> u n A i > r y t e s / <k < ) ( L M X e z riali e s n U S O t e e m > g n <stri </dict> </plist>
dictionaries are starting with the <dict> tag parser repeatedly reads key and value objects until closing </dict> tag
1 . 0 "> " = n o i s r e v t s i l <p <dict> ey> ng> <key>IsThere</k nique to rule them all?</stri h <string>one tec > y <key>Answer</ke <true /> key> <key>Audience</ serializeXML()</string> Un <string>meet OS </dict> </plist>
// next in collection // for freelist // inner elements // for dictionary // for data // for string & symbol // for number
key parser object is then converted to an internal OSString object new operator will allocate 20 bytes for OSString object via kalloc() OSString contructor will create a copy of the string with kalloc() string in parser key object will be freed with kern_os_free()
0x00 0x04 0x08 0x0C 0x10 0x14 vtable ptr + 8 retainCount ags length string ptr kalloc()ed memory
// Key kern_os_alloc(7+1) = kalloc(7+1+4) kern_os_alloc(44) = kalloc(44+4) kalloc(20) kalloc(7+1) kern_os_free(x, 7+1) = kfree(x, 7+1+4)
Allocations so far: // Dict kern_os_alloc(44) // Key kern_os_alloc(7+1) kern_os_alloc(44) kalloc(20) kalloc(7+1) kern_os_free(x, 7+1) = kalloc(44+4) = kalloc(7+1+4) = kalloc(44+4) = kfree(x, 7+1+4)
// Value kern_os_alloc(31+1) = kalloc(31+1+4) kern_os_alloc(44) = kalloc(44+4) kalloc(20) kalloc(31+1) kern_os_free(x, 31+1) = kfree(x, 31+1+4)
// Value kern_os_alloc(31+1) = kalloc(31+1+4) kern_os_alloc(44) = kalloc(44+4) kalloc(20) kalloc(31+1) kern_os_free(x, 31+1) = kfree(x, 31+1+4) // Key Answer kern_os_alloc(6+1) kern_os_alloc(44) kalloc(20) kalloc(6+1) kern_os_free(x, 6+1) = kalloc(6+1+4) = kalloc(44+4) = kfree(x, 6+1+4)
// String Value kern_os_alloc(23+1) = kalloc(23+1+4) kern_os_alloc(44) = kalloc(44+4) kalloc(20) kalloc(23+1) kern_os_free(x, 23+1) = kfree(x, 23+1+4) // The Dict kalloc(36) kalloc(3*8)
allocate repeatedly allocate attacker controlled data allocate large quantities of data in a row usually ll memory with specic pattern
Allocate Repeatedly
there is no possibility to loop in a plist but we can make as many allocations as we want with e.g. arrays
<plist version="1.0"> <dict> <key>ThisIsOurArray</key> <array> <string>again and</string> <string>again and</string> <string>again and</string> <string>again and</string> <string>again and</string> <string>again and</string> <string>...</string> </array> </dict> </plist>
Heap Spraying
allocate repeatedly ! allocate attacker controlled data allocate large quantities of data in a row ! usually ll memory with specic pattern
<plist version="1.0"> <dict> <key>ThisIsOurData</key> <array> <data>VGhpcyBJcyBPdXIgRGF0YSB3aXRoIGEgTlVMPgA8+ADw=</data> <data format="hex">00112233445566778899aabbccddeeff</data> <data>...</data> </array> </dict> </plist>
Heap Spraying
allocate repeatedly ! allocate attacker controlled data ! allocate large quantities of data in a row ! usually ll memory with specic pattern !
allocate repeatedly ! allocate arbitrary sized memory blocks / poke allocation holes in specic positions control the memory layout ll memory with interesting meta / application data
allocate repeatedly ! allocate arbitrary sized memory blocks ! poke allocation holes in specic positions control the memory layout ll memory with interesting meta / application data !
allocate repeatedly ! allocate arbitrary sized memory blocks ! poke allocation holes in specic positions ! control the memory layout ! ll memory with interesting meta / application data !
Questions
?
Stefan Esser iOS Kernel Heap Armageddon April 2012 ! 95