翻译:macOS10.12.2 local_privilage_Escalation

来源:互联网 发布:美国人聊天软件下载 编辑:程序博客网 时间:2024/06/03 22:08

本地权限提升

内核堆溢出

mach_vouncher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recip_arg *args){    ipc_voucher_t vouncher = IV_NULL;    kern_return_t kr = KERN_SUCCESS;    mach_msg_type_number_t sz = 0;    if(copyin(args->recipe_size,(void *)&sz,sizeof(sz)))        return KERN_MEMORY_ERROR;

//这段代码,args->recipe_size 是用户态的整数指针。

uint8_t *krecipe = kalloc((vm_size_t)sz);if(!krecipe){    kr = KERN_RESOURCE_SHORTAGE;    goto done;}if (copyin(args->recipe,(void *)krecipe,args->recipe_size){    kfree(kercipe,(vm_size_t)sz);    kr = KERN_MEMORY_ERROR;    goto done;}

//函数里用sz的值分配了一块内核空间。但是,args->recipe_size 是用户模式指针。并利用它作为大小copyin()进内核。
/*用户态指针是可以大于sz的值的,所以就造成了内核缓存溢出
注意,如果我们在之前的地址分配一块地址,我们也许并不能控制用户态指针。这并不是问题,copyin()函数在遇到为分配的地址会自动停止。
所以,我们可以在高地址分配一块内存,然后释放剩余的块控制溢出数据
*/
这里写图片描述

利用端口的堆风水

在 ios10 和 macOS 10.12,苹果增加了一种新的缓解机制检查释放到错误区域的攻击,以至于不能在利用经典的vm_map_copy(changing vm_map_size)技术来实现本技术。此外,苹果增加了freelist randomizationn mechanism 在iOS9.2和macOS10.11,我们不能在轻松的预测再分配内存块的位置。为了解决如此窘境,我们需要一种新的风水技巧。在Yalu 10.2, qwertyoruiop 利用 OOL_PORTS获取内核任务端口,进一步获得任意内核读写权限。这个技巧绕过了XUN堆缓解技术。在剩余部分,我们会讨论这种技术。

Mach msg是经常被利用XUN IPC机制技术,很多复杂的消息是被这种繁杂的消息传送的。通过这种结构(MACH_MSG_OOL_PORTS_DESCRIPTOR msg_type),我们就可以传输 out-of-line ports 到内核。例如,我们发送32 为 MACH_PORT_DEAD ool ports(32*8 btyes=0x100 bytes)to the kalloc.256 zone of kernel.
这里写图片描述

保存在mach msg的 ool port是ipc_object 指针,这个指针指向用户态地址。因此,我们利用mach_vouncher漏洞就可以溢出这些指针,并且修改一个ipc_object pointer 指向伪造的用户态ipc_object。我们也可以为伪造端口创建的伪造任务模式 。
这里写图片描述

为了确保溢出到正确的ipc_obejct 指针,我们需要一些堆风水。首先,我们向内核发送很多ool port messages,保证我们新分配的内存块继续运行。然后,我们收到消息的途中进行dig some slots。我们接着发送消息,确保缓存指针在slots中间。最后,我们利用mach_vouncher 在缓存指针上触发堆溢出。
这里写图片描述
溢出之后,我们就可以就收剩余的mach message ,继而找到到崩溃端口(not MAHC_PORT_DEAD port).
这里写图片描述

2任意内核读写

首先,我们设置ipc_obeject的io_bits到IKOT_CLOCK.我们可以利用 clock_sleep_trap()z转换内核得到内核时钟任务地址。这个地址可以帮助我们找到内核text base.

接着设置伪造ipc_object 的io_bits到IKOT_TASK和击溃伪造端口的伪造任务。通过在faketask+0x380(in arm64,it’s 0x360)设置值,就可以借用pid_for_task()读任意32为内核内存。奇妙的是,函数并没有检测r任务的有效性,仅仅返回值(faketask+0x380)0x10).这样就可以不用任何导向编程实现任意内核读。
这里写图片描述
这里写图片描述
利用泄漏的时钟时钟任务地址,就可以搜索内核 image的magic number,继而找到内核跳转指令。
这里写图片描述
在得到内核base后,我们可以转变左右进程找到内核ipc_object和内核任务。我们就可以取出之前伪造的ipc_object和伪造任务信息。通过task_get_special_port()访问伪造ipc_object 和任务,可以得到内核任务端口。注意,内核任务端口非常强大。他就是用来通过mach_vm_read()和 mach_vm_write()任意读写内核。
这里写图片描述

3获取root

身份信息,posix_cred结构,每个进程的的这些信息都包含在内核中。首先我们要找到我们进程的信息(内核base+allproc),随后找到攻击进程posiz_cred结构。接着,利用mach_vm_write()通过kernel_task_port设置 cr_ruid(really user id)为0,现在就可以使用/bin/bash 获取root shell

原创粉丝点击