Mac OS X local privilege escalation (IOBluetoothFamily)
Source:?http://joystick.artificialstudios.org/2014/10/mac-os-x-local-privilege-escalation.html
Vulnerability overview
In a nutshell, the bug lies in the?IOBluetoothHCIUserClient::SimpleDispatchWL()?function. The function eventually takes a user-supplied 32-bit signed integer value and uses it to index a global array of structures containing a function pointer. The chosen function pointer is finally called. As the reader can easily imagine,?SimpleDispatchWL()?fails at properly sanitizing the user-supplied index, thus bad things may happen if a malicious user is able to control the chosen function pointer.
More in detail, the vulnerable part of the function is summarized in the pseudocode below. At line 14, the user-supplied 32-bit integer is casted to a 64-bit value. Then, the "if" statement at line 16 returns an error if the casted (signed) value is greater than the number of methods available in the global_sRoutines?array; obviously, due to the signed comparison, any negative value for the?method_index?variable will pass this test. At line 20method_index?is used to access the?_sRoutines?array, and the retrieved callback is finally called at line 23.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | typedef struct { void (*function_pointer)(); uint64 num_arguments; } BluetoothMethod; BluetoothMethod _sRoutines[] = { ... }; uint64 _sRoutineCount = sizeof(_sRoutines)/sizeof(BluetoothMethod); IOReturn IOBluetoothHCIUserClient::SimpleDispatchWL(IOBluetoothHCIDispatchParams *params) { // Here "user_param" is a signed 32-bit integer parameter int64 method_index = (int64) user_param; if (method_index >= _sRoutineCount) { return kIOReturnUnsupported; } BluetoothMethod method = _sRoutines[method_index]; ... if (method.num_arguments < 8) { method.function_pointer(...); } ... } |
Exploitation details
Exploitation of this vulnerability is just a matter of supplying the proper negative integer value in order to make?IOBluetoothFamily?index the global_sRoutines?structure out of its bounds, and to fetch an attacker-controlled structure. The supplied value must be negative to index outside the_sRoutines?structure while still satisfying the check at line 16.
As a foreword, consider that for our "proof-of-concept" we disabled both SMEP/SMAP and KASLR, so some additional voodoo tricks are required to get a fully weaponized exploit. Thus, our approach was actually very simple: we computed a value for the user-supplied parameter that allowed us to index aBluetoothMethod?structure such that?BluetoothMethod.function_ptr?is a valid user-space address (where we placed our shellcode), whileBluetoothMethod.num_arguments?is an integer value less than 8 (to satisfy the check performed by?SimpleDispatchWL()?at line 22).
As shown in the C code fragment above, the user-supplied 32-bit value (user_param) is first casted to a 64-bit signed value, and then used as an index in_sRoutines. Each entry of the global?_sRoutines?array is 16-byte wide (two 8-byte values). These operations are implemented by the following assembly code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ; r12+70h points to the user-supplied index value mov ecx, [r12+70h] mov r13d, kIOReturnUnsupported lea rdx, _sRoutineCount cmp ecx, [rdx] jge fail ; Go on and fetch _sRoutine[method_index] ... movsxd rax, ecx ; Sign extension to 64-bit value shl rax, 4 ; method_index *= sizeof(BluetoothMethod) lea rdx, _sRoutines mov esi, [rdx+rax+8] ; esi = _sRoutines[method_index].num_arguments cmp esi, 7 ; Check method.num_arguments < 8 ja loc_289BA ... |
Where?ext()?is the sign-extension operation (implemented by the?movsxd?instruction in the assembly code snipped above).
By solving this formula for?user_param?and searching inside the kernel address space, we found several candidate addresses that matched our criteria (i.e., a valid user-space pointer followed by an integer value < 8). The rest of the exploit is just a matter of?mmap()‘ing the shellcode at the proper user-space address, connecting to the?IOBluetoothHCIController?service and invoking the vulnerable method.
The source code for a (very rough) proof-of-concept implementation of the aforementioned exploit is available?here, while the following figure shows the exploit "in action".
Execution of our "proof-of-concept" exploit |
?
Patching
We verified the security issue both on OS X Mavericks 10.9.4 and 10.9.5 (MD5 hash values for the?IOBluetoothFamily?KEXT bundle on these two OS versions are?2a55b7dac51e3b546455113505b25e75?and?b7411f9d80bfeab47f3eaff3c36e128f, respectively). After the release of OS X Yosemite (10.10), we noticed the vulnerability has been silently patched by Apple, with no mention about it in the?security change log.
A side-by-side comparison between versions 10.9.x and 10.10 of?IOBluetoothFamily?confirms Apple has patched the device driver by rejecting negative values for the user-supplied index. In the figure below, the user-supplied index value is compared against?_sRoutineCount?(orange basic block). Yosemite adds an additional check to ensure the (signed) index value is non-negative (green basic block, on the right).
Comparison of the vulnerable OS X driver (Mavericks, on the left) and patched version (Yosemite, on the right) |
Conclusions
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。