Skip to content

Commit

Permalink
Merge branch 'netcode-exploits' into 'next'
Browse files Browse the repository at this point in the history
Fix an exploit where players could steal the final hash of a login

See merge request STJr/SRB2!508
  • Loading branch information
MonsterIestyn committed Aug 17, 2019
2 parents 99f04f1 + 9c1fa86 commit 9a4a90c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 70 deletions.
57 changes: 57 additions & 0 deletions src/d_clisrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "lzf.h"
#include "lua_script.h"
#include "lua_hook.h"
#include "md5.h"

#ifdef CLIENT_LOADINGSCREEN
// cl loading screen
Expand Down Expand Up @@ -116,6 +117,9 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
static UINT8 player_joining = false;
UINT8 hu_resynching = 0;

UINT8 adminpassmd5[16];
boolean adminpasswordset = false;

// Client specific
static ticcmd_t localcmds;
static ticcmd_t localcmds2;
Expand Down Expand Up @@ -3760,6 +3764,7 @@ static void HandlePacketFromPlayer(SINT8 node)
XBOXSTATIC INT32 netconsole;
XBOXSTATIC tic_t realend, realstart;
XBOXSTATIC UINT8 *pak, *txtpak, numtxtpak;
XBOXSTATIC UINT8 finalmd5[16];/* Well, it's the cool thing to do? */
FILESTAMP

txtpak = NULL;
Expand Down Expand Up @@ -3958,6 +3963,32 @@ FILESTAMP
textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
}
break;
case PT_LOGIN:
if (client)
break;

#ifndef NOMD5
if (doomcom->datalength < 16)/* ignore partial sends */
break;

if (!adminpasswordset)
{
CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]);
break;
}

// Do the final pass to compare with the sent md5
D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5);

if (!memcmp(netbuffer->u.md5sum, finalmd5, 16))
{
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]);
COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately
}
else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]);
#endif
break;
case PT_NODETIMEOUT:
case PT_CLIENTQUIT:
if (client)
Expand Down Expand Up @@ -4841,3 +4872,29 @@ tic_t GetLag(INT32 node)
{
return gametic - nettics[node];
}

void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest)
{
#ifdef NOMD5
(void)buffer;
(void)len;
(void)salt;
memset(dest, 0, 16);
#else
XBOXSTATIC char tmpbuf[256];
const size_t sl = strlen(salt);

if (len > 256-sl)
len = 256-sl;

memcpy(tmpbuf, buffer, len);
memmove(&tmpbuf[len], salt, sl);
//strcpy(&tmpbuf[len], salt);
len += strlen(salt);
if (len < 256)
memset(&tmpbuf[len],0,256-len);

// Yes, we intentionally md5 the ENTIRE buffer regardless of size...
md5_buffer(tmpbuf, 256, dest);
#endif
}
9 changes: 9 additions & 0 deletions src/d_clisrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ typedef enum
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_RESYNCHING, // Packet sent to resync players.
// Blocks game advance until synched.

PT_LOGIN, // Login attempt from the client.

#ifdef NEWPING
PT_PING, // Packet sent to tell clients the other client's latency to server.
#endif
Expand Down Expand Up @@ -398,6 +401,7 @@ typedef struct
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes
UINT8 md5sum[16];
serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes
Expand Down Expand Up @@ -526,5 +530,10 @@ void D_ResetTiccmds(void);
tic_t GetLag(INT32 node);
UINT8 GetFreeXCmdSize(void);

void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);

extern UINT8 hu_resynching;

extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
#endif
74 changes: 6 additions & 68 deletions src/d_netcmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,19 @@
#include "p_spec.h"
#include "m_cheat.h"
#include "d_clisrv.h"
#include "d_net.h"
#include "v_video.h"
#include "d_main.h"
#include "m_random.h"
#include "f_finale.h"
#include "filesrch.h"
#include "mserv.h"
#include "md5.h"
#include "z_zone.h"
#include "lua_script.h"
#include "lua_hook.h"
#include "m_cond.h"
#include "m_anigif.h"
#include "md5.h"

#ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR
Expand Down Expand Up @@ -143,7 +144,6 @@ static void Command_Clearscores_f(void);
// Remote Administration
static void Command_Changepassword_f(void);
static void Command_Login_f(void);
static void Got_Login(UINT8 **cp, INT32 playernum);
static void Got_Verification(UINT8 **cp, INT32 playernum);
static void Got_Removal(UINT8 **cp, INT32 playernum);
static void Command_Verify_f(void);
Expand Down Expand Up @@ -437,7 +437,6 @@ void D_RegisterServerCommands(void)

// Remote Administration
COM_AddCommand("password", Command_Changepassword_f);
RegisterNetXCmd(XD_LOGIN, Got_Login);
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
COM_AddCommand("promote", Command_Verify_f);
RegisterNetXCmd(XD_VERIFIED, Got_Verification);
Expand Down Expand Up @@ -2652,35 +2651,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
// Attempts to make password system a little sane without
// rewriting the entire goddamn XD_file system
//
#include "md5.h"
static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest)
{
#ifdef NOMD5
(void)buffer;
(void)len;
(void)salt;
memset(dest, 0, 16);
#else
XBOXSTATIC char tmpbuf[256];
const size_t sl = strlen(salt);

if (len > 256-sl)
len = 256-sl;
memcpy(tmpbuf, buffer, len);
memmove(&tmpbuf[len], salt, sl);
//strcpy(&tmpbuf[len], salt);
len += strlen(salt);
if (len < 256)
memset(&tmpbuf[len],0,256-len);

// Yes, we intentionally md5 the ENTIRE buffer regardless of size...
md5_buffer(tmpbuf, 256, dest);
#endif
}

#define BASESALT "basepasswordstorage"
static UINT8 adminpassmd5[16];
static boolean adminpasswordset = false;

void D_SetPassword(const char *pw)
{
Expand Down Expand Up @@ -2718,7 +2689,6 @@ static void Command_Login_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else
XBOXSTATIC UINT8 finalmd5[16];
const char *pw;

if (!netgame)
Expand All @@ -2738,47 +2708,15 @@ static void Command_Login_f(void)
pw = COM_Argv(1);

// Do the base pass to get what the server has (or should?)
D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &finalmd5);
D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &netbuffer->u.md5sum);

// Do the final pass to get the comparison the server will come up with
D_MD5PasswordPass(finalmd5, 16, va("PNUM%02d", consoleplayer), &finalmd5);
D_MD5PasswordPass(netbuffer->u.md5sum, 16, va("PNUM%02d", consoleplayer), &netbuffer->u.md5sum);

CONS_Printf(M_GetText("Sending login... (Notice only given if password is correct.)\n"));

SendNetXCmd(XD_LOGIN, finalmd5, 16);
#endif
}

static void Got_Login(UINT8 **cp, INT32 playernum)
{
#ifdef NOMD5
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
(void)cp;
(void)playernum;
#else
UINT8 sentmd5[16], finalmd5[16];

READMEM(*cp, sentmd5, 16);

if (client)
return;

if (!adminpasswordset)
{
CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]);
return;
}

// Do the final pass to compare with the sent md5
D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", playernum), &finalmd5);

if (!memcmp(sentmd5, finalmd5, 16))
{
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]);
COM_BufInsertText(va("promote %d\n", playernum)); // do this immediately
}
else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[playernum]);
netbuffer->packettype = PT_LOGIN;
HSendPacket(servernode, true, 0, 16);
#endif
}

Expand Down
4 changes: 2 additions & 2 deletions src/d_netcmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ typedef enum
XD_ADDPLAYER, // 10
XD_TEAMCHANGE, // 11
XD_CLEARSCORES, // 12
XD_LOGIN, // 13
XD_VERIFIED, // 14
// UNUSED 13 (Because I don't want to change these comments)
XD_VERIFIED = 14,//14
XD_RANDOMSEED, // 15
XD_RUNSOC, // 16
XD_REQADDFILE, // 17
Expand Down

0 comments on commit 9a4a90c

Please sign in to comment.