Anon777 / google-security-research

Automatically exported from code.google.com/p/google-security-research
0 stars 0 forks source link

Lack of bounds checking in gst_configure leads to kernel buffer overflow due to toctou (plus kernel memory disclosure) #596

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
The external method 0x206 of IGAccelGLContext is gst_configure. This method 
takes an arbitrary sized input structure
(passed in rsi) but doesn't check the size of that structure (passed in rcx.)

__text:000000000002A366 
__ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:000000000002A366                                         ; DATA XREF: 
__const:000000000005BF88o
__text:000000000002A366                 push    rbp
__text:000000000002A367                 mov     rbp, rsp
__text:000000000002A36A                 push    r15
__text:000000000002A36C                 push    r14
__text:000000000002A36E                 push    r12
__text:000000000002A370                 push    rbx
__text:000000000002A371                 mov     rax, rdx
__text:000000000002A374                 mov     r15, rsi         ; <-- r15 
points to controlled mach message data
__text:000000000002A377                 mov     r14, rdi
__text:000000000002A37A                 mov     edx, [r15+800h]  ; <-- size 
never checked -> oob read
__text:000000000002A381                 cmp     edx, 200h
__text:000000000002A387                 jbe     short loc_2A3AD
__text:000000000002A389                 lea     rdi, aIgaccelglcon_0 ; 
"IGAccelGLContext::%s Error: Number of e"...
__text:000000000002A390                 lea     rsi, aGst_configure ; 
"gst_configure"
__text:000000000002A397                 mov     ecx, 200h
__text:000000000002A39C                 xor     eax, eax
__text:000000000002A39E                 call    _IOLog

here we can see that the method is reading a dword at offset 0x800 of the input 
struct and comparing that value to 0x200.
This method is reached via MIG and if we call userspace IOConnectCallMethod 
with a small input struct then the mach
message is actually packed such that only the input struct size we send 
actually gets sent; therefore this is an OOB read.

The first interesting conseqeuence of this is that if the value read is > 0x200 
then it gets logged to /var/log/system.log
which we can read from userspace allowing us to disclose some kernel memory.

However, we can do more:

r15 is passed to IntelAccelerator::gstqConfigure:

mov     rsi, r15
call    __ZN16IntelAccelerator13gstqConfigureEP19GstConfigurationRec

where we reach the following code:

__text:000000000001DC29                 mov     edx, [rsi+800h]
__text:000000000001DC2F                 shl     rdx, 2          ; size_t
__text:000000000001DC33                 lea     rdi, 
_gstCustomCounterConfigPair ; void *
__text:000000000001DC3A                 call    _memcpy

here the value at +0x800 is read again and used as the size for a memcpy 
assuming that it has already been verified, but
since it's outside the bounds of the allocation this is actually a toctou bug 
since with some heap manipulation we can
change that value to be > 0x200 allowing us to overflow the 
_gstCustomCounterConfigPair buffer.

Since the struct input comes from a mach message this heap grooming shouldn't 
be that difficult.

clang -o ig_gl_gst_oob_read ig_gl_gst_oob_read.c -framework IOKit

repro: while true; ./ig_gl_gst_oob_read; done

Tested on OS X ElCapitan 10.11.1 (15b42) on MacBookAir5,2

Original issue reported on code.google.com by ianb...@google.com on 26 Oct 2015 at 4:56

Attachments:

GoogleCodeExporter commented 8 years ago

Original comment by ianb...@google.com on 26 Oct 2015 at 4:58

GoogleCodeExporter commented 8 years ago
Apple advisory: https://support.apple.com/en-gb/HT205637

Original comment by ianb...@google.com on 20 Dec 2015 at 8:50

GoogleCodeExporter commented 8 years ago

Original comment by ianb...@google.com on 27 Jan 2016 at 5:14