####################################################################### Luigi Auriemma Application: Zdaemon http://www.zdaemon.org (and also X-Doom R6 1.06.07 http://www.doom2.net/~xdoom/) Versions: <= 1.08.01 Platforms: Windows and Linux Bugs: A] buffer-overflow in is_client_wad_ok B] Invalid memory access in ZD_MissingPlayer, ZD_UseItem and ZD_LoadNewClientLevel/ZD_ValidClient Exploitation: A] remote, versus server B] remote, versus server (in-game) Date: 31 Mar 2006 Author: Luigi Auriemma e-mail: aluigi@autistici.org web: aluigi.org ####################################################################### 1) Introduction 2) Bugs 3) The Code 4) Fix ####################################################################### =============== 1) Introduction =============== Zdaemon is the most played Doom engine on Internet with tons of servers available online and many players. X-Doom instead is an old server-only port focused on Linux/BSD and is/was based on the latest Zdaemon source code which was available before becoming closed source. ####################################################################### ======= 2) Bugs ======= -------------------------------------- A] buffer-overflow in is_client_wad_ok -------------------------------------- When a client joins the match, the server checks if the wad files (the maps) used on the client are the same it has. So the client sends the name of each wad used on the server followed by the local md5 hash of the file, the server gets the received filename and copies it in a buffer of 256 bytes using strcpy(). The resulted buffer-overflow is limited by the my_strupr function which converts all the chars in their capital case but during my tests with GDB I was able to overwrite a return address with the original string using a longer filename. The attacker needs to know the right keyword if the server is protected by password. IP banning doesn't protect versus this attack because it's a subsequent check and so an attacker can exploit any server on which he is banned. From server/src/w_wad.cpp (X-Doom / Zdaemon 1.06): char *wad_check::is_client_wad_ok(const char *fname,const byte *csum) { int i; char temp[256]; static char errmsg[512]; strcpy(temp,plain_filename(fname)); my_strupr(temp); if ( (i=find(fname)) < 0 ) { sprintf(errmsg,"\nYou should not load \"%s\" on this server.\nGet rid of it!\n",temp); return errmsg; } ... ------------------------------------------------------------ B] Invalid memory access in ZD_MissingPlayer, ZD_UseItem and ZD_LoadNewClientLevel/ZD_ValidClient ------------------------------------------------------------ Zdaemon supports many commands for playing, like changing the player name, chatting, moving, selecting weapons and so on... just like any common multiplayer game. The functions ZD_MissingPlayer, ZD_UseItem and ZD_ValidClient (exploitable through ZD_LoadNewClientLevel) read an 8 bits number from the client which is used to select a specific player slot or item and then doing some operations. The server uses 16 slots (MAXPLAYERS) and less than 40 items (NUMARTIFACTS) so if an attacker uses an invalid number the server crashes immediately after trying to access an invalid memory zone. This is an in-game bug so must be respected all the requirements for accessing the server (correct md5 hashes of the wads, password and no banning) or it can't be exploited. From server/src/sv_main.cpp (X-Doom / Zdaemon 1.06): void ZD_MissingPlayer(void) { int pnum = ZD_ReadByte(); // the player that our client is missing int cl = parse_cl; player_t* player = &players[pnum]; if (!playeringame[pnum]) { Printf("ZD_MissingPlayer: BIG PROBLEM!!\n"); return; } ZDOP.Init(); if (player->isbot) ... void ZD_UseItem(void) { int which = ZD_ReadByte(); int i; // None left! if (players[parse_cl].inventory[which] <= 0) ... static void ZD_LoadNewClientLevel(char *levelname, int i) { player_s *pli; if (!ZD_ValidClient(i)) return; ... bool ZD_ValidClient(int i) { return (playeringame[i] && !players[i].isbot); } ####################################################################### =========== 3) The Code =========== A] http://aluigi.org/poc/zdaebof.zip B] Add the following code at line 179 of my Zdaemon Fake Players DoS: for(i = 0; i < 256; i++) { p = buff; *p++ = 0xff; *p++ = cl_missingplayer; // cl_useitem cl_wantnewlevel *p++ = i; len = send_recv(sd, buff, p - buff, buff, sizeof(buff), 0); if(len < 0) break; } if((len < 0) && (i < 256)) { printf("\n Server IS vulnerable!!!\n\n"); } else { printf("\n Server doesn't seem vulnerable\n\n"); } close(sd); return(0); The tool is available here: http://aluigi.org/fakep/zdaemonfp.zip ####################################################################### ====== 4) Fix ====== No fix. Developers have not been contacted for the following reason: Zdaemon has some problems with its license, it is based on many open source code (mainly Zdoom) and it was open source till version 1.06 (the old website was http://www.zdaemon.info, you can still find the cache on some search engines). Then the developers decided to close the source code because some cheaters created an aimbot (a tool/patch for killing enemies more easily) for this game but IMHO, and this is the same opinion of many people, what they have done is not compatible with the GPL license (the id Software Doom engine is GPLed) and with the strong philosophy behind the open source movement. Personal comment: closing the source code is not a solution, will never stop cheaters (they do only what the server allows to do) and has not stopped me to find these security vulnerabilities. #######################################################################