####################################################################### 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@altervista.org 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