#######################################################################
Luigi Auriemma
Application: Zdaemon
http://www.zdaemon.org
(and also X-Doom 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 (at) autistici (dot) org [email concealed]
web: http://aluigi.altervista.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.altervista.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!!!nn");
} else {
printf("n Server doesn't seem vulnerablenn");
}
close(sd);
return(0);
The tool is available here:
http://aluigi.altervista.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.
#######################################################################
---
Luigi Auriemma
http://aluigi.altervista.org