Exploit-DB #39368
Description: Apple Mac OSX - 'gst_configure' Kernel Buffer Overflow
Type: dos
Platform: osx
Date: 2016-01-28
Author: Google Security Research

Exploit:
/*
Source: https://code.google.com/p/google-security-research/issues/detail?id=596

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:[PII_REDACTED]02A366 __ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:[PII_REDACTED]02A366                                         ; DATA XREF: __const:[PII_REDACTED]05BF88o
__text:[PII_REDACTED]02A366                 push    rbp
__text:[PII_REDACTED]02A367                 mov     rbp, rsp
__text:[PII_REDACTED]02A36A                 push    r15
__text:[PII_REDACTED]02A36C                 push    r14
__text:[PII_REDACTED]02A36E                 push    r12
__text:[PII_REDACTED]02A370                 push    rbx
__text:[PII_REDACTED]02A371                 mov     rax, rdx
__text:[PII_REDACTED]02A374                 mov     r15, rsi         ; <-- r15 points to controlled mach message data
__text:[PII_REDACTED]02A377                 mov     r14, rdi
__text:[PII_REDACTED]02A37A                 mov     edx, [r15+800h]  ; <-- size never checked -> oob read
__text:[PII_REDACTED]02A381                 cmp     edx, 200h
__text:[PII_REDACTED]02A387                 jbe     short loc_2A3AD
__text:[PII_REDACTED]02A389                 lea     rdi, aIgaccelglcon_0 ; "IGAccelGLContext::%s Error: Number of e"...
__text:[PII_REDACTED]02A390                 lea     rsi, aGst_configure ; "gst_configure"
__text:[PII_REDACTED]02A397                 mov     ecx, 200h
__text:[PII_REDACTED]02A39C                 xor     eax, eax
__text:[PII_REDACTED]02A39E                 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:[PII_REDACTED]01DC29                 mov     edx, [rsi+800h]
__text:[PII_REDACTED]01DC2F                 shl     rdx, 2          ; size_t
__text:[PII_REDACTED]01DC33                 lea     rdi, _gstCustomCounterConfigPair ; void *
__text:[PII_REDACTED]01DC3A                 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
*/

// ianbeer
/*
Lack of bounds checking in gst_configure leads to kernel buffer overflow due to toctou (plus kernel memory disclosure)

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:[PII_REDACTED]02A366 __ZN16IGAccelGLContext13gst_configureEP19GstConfigurationRecS1_jPj proc near
__text:[PII_REDACTED]02A366                                         ; DATA XREF: __const:[PII_REDACTED]05BF88o
__text:[PII_REDACTED]02A366                 push    rbp
__text:[PII_REDACTED]02A367                 mov     rbp, rsp
__text:[PII_REDACTED]02A36A                 push    r15
__text:[PII_REDACTED]02A36C                 push    r14
__text:[PII_REDACTED]02A36E                 push    r12
__text:[PII_REDACTED]02A370                 push    rbx
__text:[PII_REDACTED]02A371                 mov     rax, rdx
__text:[PII_REDACTED]02A374                 mov     r15, rsi         ; <-- r15 points to controlled mach message data
__text:[PII_REDACTED]02A377                 mov     r14, rdi
__text:[PII_REDACTED]02A37A                 mov     edx, [r15+800h]  ; <-- size never checked -> oob read
__text:[PII_REDACTED]02A381                 cmp     edx, 200h
__text:[PII_REDACTED]02A387                 jbe     short loc_2A3AD
__text:[PII_REDACTED]02A389                 lea     rdi, aIgaccelglcon_0 ; "IGAccelGLContext::%s Error: Number of e"...
__text:[PII_REDACTED]02A390                 lea     rsi, aGst_configure ; "gst_configure"
__text:[PII_REDACTED]02A397                 mov     ecx, 200h
__text:[PII_REDACTED]02A39C                 xor     eax, eax
__text:[PII_REDACTED]02A39E                 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:[PII_REDACTED]01DC29                 mov     edx, [rsi+800h]
__text:[PII_REDACTED]01DC2F                 shl     rdx, 2          ; size_t
__text:[PII_REDACTED]01DC33