Hidden Gamespy code leads to vulnerabilities in diffused games (BF1942, Halo, Dredd and more)
#######################################################################
Luigi Auriemma
Application: Gamespy SDK used for online cd-keys validation in third
party code (hidden "security through obscurity" code)
Games/ver: Battlefield 1942 <= 1.6.19 and 1.6rc1
___________________________http://www.battlefield1942.com
Contract Jack <= 1.1
___________________________________http://nolf.sierra.com
Gore <= 1.48 (1.49)
_________________________________http://gore.cryogame.com
Haegemonia <= 1.0.7
________________________________http://www.haegemonia.com
Halo <= 1.031
_____________________http://www.microsoft.com/games/halo/
Hidden & Dangerous 2 <= 1.04
______________________http://www.hidden-and-dangerous.com
IGI 2: Covert Strike <= 1.3
_________________________________http://www.igi2-game.com
Judge Dredd: Dredd vs. Death <= 1.01
______________________________http://www.dreddvsdeath.com
Need For Speed Hot Pursuit 2 <= 242
______________http://www.eagames.com/pccd/nfshp2/home.jsp
Terminator 3: War of the Machines 1.0
_____________________________________http://www.t3war.com
TRON 2.0 <= 1.042
____________________________________http://www.tron20.com
probably also other games
Platforms: Windows, Linux and MacOS
Bugs: A] crash of games'servers
B] privacy problems
Risk: A] high
B] very low
Exploitation: remote
Date: 24 Feb 2004
Author: Luigi Auriemma
e-mail: aluigi@xxxxxxxxxxxxxx
web: http://aluigi.altervista.org
#######################################################################
1) Introduction
2) Bugs
3) Analysis of the hidden code
4) The Code
5) Fix
6) Conclusion
#######################################################################
===============
1) Introduction
===============
First I want to premise that these bugs have been discovered during a
bug research on a specific game and I knew about the implication of
Gamespy only some minutes later.
Yes Gamespy, the people who say to "welcome any and all help" and then
send me an useless Cease&Desist and DEFAME me and moreover my hobby,
the same people who say to "protect gamers rights and provide security"
and then leave RogerWilco and Gamespy3d vulnerables to highly critical
and pubblic old bugs (still now), the same "trusted people" who claim
"Gamers trust us" and at the same time insert hidden functions in third
party games.
http://aluigi.altervista.org/papers/castleoflies.txt
The code now object of this research is just the SDK that Gamespy
gives/sells to games developers to implement the online management and
validation of games cd-keys.
The worst thing of this SDK is that it uses simples "security through
obscurity" methods to hide informations to the same users who use these
vulnerable games (any existent type of demo, retail and dedicated
server) so this advisory will also clarify these shameful methods
avoiding that these users like me continue to be joked.
The bugs I want to analyze are essentially the following:
A] security bug/programming error: crash in the games servers
B] security through obscurity bug: possible privacy problems
Fortunally the developers have the source code of the bugged SDK so all
the people I have personally contacted a lot of weeks ago have had the
possibility to fix the first bug without problems.
Then some weeks ago Gamespy has also released a patched SDK to the
developers of the vulnerable games, in fact they have been contacted
just by one of the developers I have talked with... in fact as
everybody knows for me is impossible to directly contact Gamespy
because they are incapable to understand and manage my bugs
signalations.
However I have also provided some unofficial fixes for the games that
have no official patches at the moment or that are no more supported.
#######################################################################
=======
2) Bugs
=======
-------------------------
A] crash of games'servers
-------------------------
The problem is located in the instructions that copy the portion of the
received query packet delimited by backslashes (as \query\) into a new
buffer.
The vulnerable instructions are similar to the following:
int size = strchr(buff + 1, '\\') - buff;
if(size > 32) return;
strncpy(querybuff, buff + 1, size);
"buff" is the decoded packet (look at next section) containing one of
the hidden Gamespy commands, "size" is a signed integer number that
contains the amount of bytes to copy and "querybuff" is the buffer that
will contain the query for comparison with the hidden commands.
In this code we can find 2 programming errors:
- the return value of strchr() is not checked so if it fails the
Gamespy code continues to think that the address of the string
returned is valid also if it is 0 (failed).
- "size" is managed as a signed integer (+/- sign) so when strchr()
fails the function does a "0 - buff" operation (difference between
the end and the beginning of the query) that results in a negative 32
bit number.
The problem happens when the function checks if "size" is major than
32 because naturally this is a signed comparison and "size" has a
negative sign.
The effect of the bug is an exception in the strncpy() function that
interrupts the server immediately.
-------------------
B] privacy problems
-------------------
As already said, the Gamespy code implements security through obscurity
techniques to avoid that the servers'administrators see or understand
the queries sent and received to their own systems (why? I don't know,
ask to Gamespy).
These queries however are nothing of "special" but can cause some
privacy problems to games servers and clients.
The following is the command that gives problems:
ison: used to know if in the target game server is playing an user with
a specific cd-key
For example this command can be used to track a specific user if we
know his cd-key or its MD5 hash (hash sent to any game server where the
client joins).
#######################################################################
==============================
3) Analysis of the hidden code
==============================
The Gamespy cd-key SDK is a partially hidden function activated when
the game server receives a packet with a specific byte in it or must
validate a client's cd-key.
I'm just one of the users of some of the vulnerable games and I don't
accept that someone inserts hidden code in the games I buy or
administer (moreover if they are not the developers and I don't trust
in them) so this analysis will finally light on a part of this code,
the part that directly affects users.
The hidden function used to manage the "undocumented" queries is
activated when a packet starting with the char ';' (byte 0x3b) reaches
the query port of the game server of any user online.
The query port is just the same UDP port used to receive the
information queries as "basic", "info", "status", "rules" and all the
others.
The char ';' in reality is the char backslash (the same used at the
beginning of any normal query) "XORed" with the char 'g' of the string
"gamespy", in fact the packet that reaches the game server is simply
encoded using the XOR operator.
The following is an optimized C function that explains how works the
encoding/deconding operation:
void gamespyxor(u_char *string, int len) {
u_char gamespy[] = "gamespy",
*gs;
for(gs = gamespy; len; len--, gs++, string++) {
if(!*gs) gs = gamespy;
*string ^= *gs;
}
}
After having decoded the data the hidden Gamespy function assembles the
supported 4 commands in memory for comparison with that received in the
packet. The method used for this operation is very simple and its only
purpose is to hide the available commands to who tries to open the game
executable with a disassembler or a hex editor.
The following is a real example showing how the 4 commands used in the
function are assembled:
:004422B7 B175 mov cl, 75
:004422B9 B06F mov al, 6F
:004422BB 56 push esi
:004422BC 8BF2 mov esi, edx
:004422BE B26E mov dl, 6E
:004422C0 884C240C mov byte[esp+0C], cl
:004422C4 884C2410 mov byte[esp+10], cl
:004422C8 884C2420 mov byte[esp+20], cl
:004422CC 884C2423 mov byte[esp+23], cl
:004422D0 33C9 xor ecx, ecx
:004422D2 85F6 test esi, esi
:004422D4 8844240D mov byte[esp+0D], al
:004422D8 88442412 mov byte[esp+12], al
:004422DC 8844241A mov byte[esp+1A], al
:004422E0 88442422 mov byte[esp+22], al
:004422E4 C644240E6B mov byte[esp+0E], 6B
:004422E9 C644240F00 mov byte[esp+0F], 00
:004422EE 88542411 mov byte[esp+11], dl
:004422F2 C64424136B mov byte[esp+13], 6B
:004422F7 C644241400 mov byte[esp+14], 00
:004422FC C644241869 mov byte[esp+18], 69
:00442301 C644241973 mov byte[esp+19], 73
:00442306 8854241B mov byte[esp+1B], dl
:0044230A C644241C00 mov byte[esp+1C], 00
:0044230F C644242163 mov byte[esp+21], 63
:00442314 88542424 mov byte[esp+24], dl
:00442318 C644242574 mov byte[esp+25], 74
:0044231D C644242600 mov byte[esp+26], 00
The portion of code comes directly from the file BF1942_w32ded.exe of
Battlefield 1942 Win32 dedicated server 1.6.19 but this "hiding
technique" is the same used in all the other vulnerable games and
moreover also in all the Gamespy products (..."Gamers trust us"...).
The generated commands are exactly: "uok", "unok", "ison" and "ucount".
The first 2 commands in reality are replies sent by the Gamespy master
server to the games servers when they request the validation of a
cd-key using the "auth" query.
Instead the real interesting commands are "ison" and a bit "ucount"
that are used respectively to know if a specific cd-key is currently
used in the target game server and how many players in the server are
using cd-keys.
The following are some practical usage examples:
\uok\\cd\0123456789abcdef0123456789abcdef\skey\1\errmsg\Valid CD Key
\unok\\cd\0123456789abcdef0123456789abcdef\skey\1\errmsg\Invalid CD Key
\ison\skey\1\cd\0123456789abcdef0123456789abcdef
\ucount\
Where "skey" is an ID number used to track replies to a specific query
and "cd" is the cd-key hash.
The cd-key hash is simply the MD5 hash calculated by the client on his
original cd-key, it is sent by each client to the game server that uses
it to validate the client through the master server.
When the server has assembled the available commands in memory it
compares the received query with eachone of these 4 strings and then
sends the relative answer if needed.
The following are the possible answers for the commands "ison" and
"ucount":
\uon\\skey\1 the requested cd-key is used in the target server
\uoff\\skey\1 the requested cd-key is not used in the target server
\ucount\9 in the target server there are 9 players using cd-keys
#######################################################################
===========
4) The Code
===========
-------------------------
A] crash of games'servers
-------------------------
To test this bug is needed the simple sending of the char ';' to the
UDP query port of the vulnerable game server that is hosting the match
who will crash immediately, however I have written also an useful
proof-of-concept:
http://aluigi.altervista.org/poc/gshboom.zip
-------------------
B] privacy problems
-------------------
The following is a tool to check the games that use the hidden Gamespy
code, it is able to send all the availables 4 commands (remember that
"uok" and "unok" aren't queries but replies so they cannot be used):
http://aluigi.altervista.org/papers/gshinfo.zip
Then I have written also a simple packet analyzer for Windows to know
and decode on the fly all the UDP packets sent and received from the
Gamespy master server or by any other host choosen by the user:
http://aluigi.altervista.org/papers/gshsniff.zip
The latest tool instead is a logger used to log all and only the
encoded commands sent and received on a specific UDP query port:
http://aluigi.altervista.org/papers/gshlog.zip
#######################################################################
======
5) Fix
======
----------------
Official patches
----------------
As already said, some weeks ago Gamespy has released an updated SDK
that should fix the vulnerability so virtually all the vulnerable games
that I didn't know were vulnerables have or will have a fix soon.
However ALL the developers of the vulnerable games I knew vulnerables
and I have personally checked have been quickly alerted with multiple
mails for one month.
The following is the patches'situation in the moment I'm writing:
Battlefield 1942.....................FIXED only Linux DS 1.6RC2.
I was in contact with Dice about the bug but after the Linux
dedicated server patch I lost any contact with them (no replies)
so I don't know the current status of the fixes for the retail and
the win32 dedicated server
Contract Jack........................NOT, seems no more supported
Gore.................................NOT, MYFIX
Haegemonia...........................NOT, seems to use a modified
SDK so cannot be crashed with the classic attack but contains the
vulnerable instructions
Halo.................................FIXED in 1.04
Hidden & Dangerous 2.................NOT, MYFIX DS only
IGI 2: Covert Strike.................NOT, MYFIX DS only
Judge Dredd: Dredd vs. Death.........NOT
Need For Speed Hot Pursuit 2.........NOT
Terminator 3: War of the Machines....FIX is coming, however it is not
vulnerable to the classic attack explained in the previous section
TRON 2.0.............................NOT, seems no more supported
--------
My fixes
--------
Fortunally patching the bug is very very simple so I have written some
manual patches (need hex editor) that fully patch the problem in almost
all the unpatched games:
Game file offset old patch
----------------------------------------------------------------------
BF1942 win32 DS 1.6.19 BF1942_w32ded.exe 00042370 7f 77
Gore 1.48 and 1.49 gore.exe 000B86F2 7f 77
Hidden & Dangerous 2 1.04 DS HD2DS.exe 003498CA 7f 77
Igi2 1.3 dedicated server igi2.exe 001C937A 7f 77
All the other games or retail versions use encrypted executables for
their lame and useless CD protections and I don't and I can't support
them with my fixes.
This is another confirmation that CD protections are a limit for real
users and in this case also for people who wanna fix their
"no-more-supported" games:
http://aluigi.altervista.org/patches/nocd.txt
Explanation of my fix
---------------------
My fix simply converts a JG (signed comparison) in a JA (UNsigned).
Practically when strchr() fails it returns a 0, then the Gamespy
function does a "0 - buff" to find how big is the query and then checks
if the result is major than 32.
BUT this comparison is signed (+/-) so the result of "0 - buff" in
reality is minor than 32 and the comparison fails.
My fix so does simply an UNsigned comparison so "0 - buff" is major
than 32 and the malicious query is successfully rejected.
#######################################################################
=============
6) Conclusion
=============
Trust should be gained with real facts and not with lies and secrets.
#######################################################################
---
Luigi Auriemma
http://aluigi.altervista.org