Fix playlist overrides exploit

Only allow playlist overrides when cheats are enabled on the server.
This commit is contained in:
Amos 2023-07-07 09:14:39 +02:00
parent deb913e47b
commit e9335d062f
2 changed files with 101 additions and 9 deletions

View File

@ -64,6 +64,53 @@ bool SVC_UserMessage::ProcessImpl()
return SVC_UserMessage_Process(this); // Need to return original.
}
///////////////////////////////////////////////////////////////////////////////////
// Below functions are hooked as 'SVC_PlaylistOverrides' can be abused from the
// client. The client could basically manage the server's playlists. Only allow
// reading/writing when cheats are enabled.
///////////////////////////////////////////////////////////////////////////////////
bool SVC_PlaylistOverrides::ReadFromBufferImpl(SVC_PlaylistOverrides* thisptr, bf_read* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return SVC_PlaylistOverrides_ReadFromBuffer(thisptr, buffer);
}
bool SVC_PlaylistOverrides::WriteToBufferImpl(SVC_PlaylistOverrides* thisptr, bf_write* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return SVC_PlaylistOverrides_WriteToBuffer(thisptr, buffer);
}
bool CLC_SetPlaylistVarOverride::ReadFromBufferImpl(CLC_SetPlaylistVarOverride* thisptr, bf_read* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return CLC_SetPlaylistVarOverride_ReadFromBuffer(thisptr, buffer);
}
bool CLC_SetPlaylistVarOverride::WriteToBufferImpl(CLC_SetPlaylistVarOverride* thisptr, bf_write* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return CLC_SetPlaylistVarOverride_WriteToBuffer(thisptr, buffer);
}
///////////////////////////////////////////////////////////////////////////////////
// below functions are hooked as 'CmdKeyValues' isn't really used in this game, but
// still exploitable on the server. the 'OnPlayerAward' command calls the function
@ -135,25 +182,28 @@ bool ShouldReplayMessage(const CNetMessage* msg)
void V_NetMessages::Attach() const
{
#if !defined(DEDICATED)
auto hk_SVCPrint_Process = &SVC_Print::ProcessImpl;
auto hk_SVCUserMessage_Process = &SVC_UserMessage::ProcessImpl;
auto hk_Base_CmdKeyValues_ReadFromBuffer = &Base_CmdKeyValues::ReadFromBufferImpl;
auto hk_Base_CmdKeyValues_WriteToBuffer = &Base_CmdKeyValues::WriteToBufferImpl;
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VFTable, (LPVOID&)hk_SVCPrint_Process, NetMessageVtbl::Process, (LPVOID*)&SVC_Print_Process);
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VFTable, (LPVOID&)hk_SVCUserMessage_Process, NetMessageVtbl::Process, (LPVOID*)&SVC_UserMessage_Process);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID&)hk_Base_CmdKeyValues_ReadFromBuffer, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&Base_CmdKeyValues_ReadFromBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID&)hk_Base_CmdKeyValues_WriteToBuffer, NetMessageVtbl::WriteToBuffer, (LPVOID*)&Base_CmdKeyValues_WriteToBuffer);
#endif // DEDICATED
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID*)&Base_CmdKeyValues::ReadFromBufferImpl, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&Base_CmdKeyValues_ReadFromBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID*)&Base_CmdKeyValues::WriteToBufferImpl, NetMessageVtbl::WriteToBuffer, (LPVOID*)&Base_CmdKeyValues_WriteToBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_PlaylistOverrides_VFTable, (LPVOID*)&SVC_PlaylistOverrides::ReadFromBufferImpl, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&SVC_PlaylistOverrides_ReadFromBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_PlaylistOverrides_VFTable, (LPVOID*)&SVC_PlaylistOverrides::WriteToBufferImpl, NetMessageVtbl::WriteToBuffer, (LPVOID*)&SVC_PlaylistOverrides_WriteToBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pCLC_SetPlaylistVarOverride_VFTable, (LPVOID*)&CLC_SetPlaylistVarOverride::ReadFromBufferImpl, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&CLC_SetPlaylistVarOverride_ReadFromBuffer);
CMemory::HookVirtualMethod((uintptr_t)g_pCLC_SetPlaylistVarOverride_VFTable, (LPVOID*)&CLC_SetPlaylistVarOverride::WriteToBufferImpl, NetMessageVtbl::WriteToBuffer, (LPVOID*)&CLC_SetPlaylistVarOverride_WriteToBuffer);
}
void V_NetMessages::Detach() const
{
#if !defined(DEDICATED)
void* hkRestore = nullptr;
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VFTable, (LPVOID)SVC_Print_Process, NetMessageVtbl::Process, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VFTable, (LPVOID)SVC_UserMessage_Process, NetMessageVtbl::Process, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID)Base_CmdKeyValues_ReadFromBuffer, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID)Base_CmdKeyValues_WriteToBuffer, NetMessageVtbl::WriteToBuffer, (LPVOID*)&hkRestore);
#endif // DEDICATED
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_PlaylistOverrides_VFTable, (LPVOID)SVC_PlaylistOverrides_ReadFromBuffer, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_PlaylistOverrides_VFTable, (LPVOID)SVC_PlaylistOverrides_WriteToBuffer, NetMessageVtbl::WriteToBuffer, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pCLC_SetPlaylistVarOverride_VFTable, (LPVOID)CLC_SetPlaylistVarOverride_ReadFromBuffer, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pCLC_SetPlaylistVarOverride_VFTable, (LPVOID)CLC_SetPlaylistVarOverride_WriteToBuffer, NetMessageVtbl::WriteToBuffer, (LPVOID*)&hkRestore);
}

View File

@ -22,6 +22,8 @@
class CNetChan;
class SVC_Print;
class SVC_UserMessage;
class SVC_PlaylistOverrides;
class CLC_SetPlaylistVarOverride;
class Base_CmdKeyValues;
//-------------------------------------------------------------------------
@ -51,11 +53,25 @@ inline void* g_pSVC_ServerTick_VFTable = nullptr;
//-------------------------------------------------------------------------
inline void* g_pSVC_VoiceData_VFTable = nullptr;
//-------------------------------------------------------------------------
// SVC_PlaylistOverrides
//-------------------------------------------------------------------------
inline bool(*SVC_PlaylistOverrides_ReadFromBuffer)(SVC_PlaylistOverrides* thisptr, bf_read* buffer);
inline bool(*SVC_PlaylistOverrides_WriteToBuffer)(SVC_PlaylistOverrides* thisptr, bf_write* buffer);
inline void* g_pSVC_PlaylistOverrides_VFTable = nullptr;
//-------------------------------------------------------------------------
// CLC_ClientTick
//-------------------------------------------------------------------------
inline void* g_pCLC_ClientTick_VFTable = nullptr;
//-------------------------------------------------------------------------
// CLC_SetPlaylistVarOverride
//-------------------------------------------------------------------------
inline bool(*CLC_SetPlaylistVarOverride_ReadFromBuffer)(CLC_SetPlaylistVarOverride* thisptr, bf_read* buffer);
inline bool(*CLC_SetPlaylistVarOverride_WriteToBuffer)(CLC_SetPlaylistVarOverride* thisptr, bf_write* buffer);
inline void* g_pCLC_SetPlaylistVarOverride_VFTable = nullptr;
//-------------------------------------------------------------------------
// Base_CmdKeyValues
//-------------------------------------------------------------------------
@ -339,6 +355,18 @@ public:
void* m_DataOut;
};
class SVC_PlaylistOverrides : public CNetMessage
{
public:
static bool ReadFromBufferImpl(SVC_PlaylistOverrides* thisptr, bf_read* buffer);
static bool WriteToBufferImpl(SVC_PlaylistOverrides* thisptr, bf_write* buffer);
private:
int m_nMsgType;
int m_nLength; // data length in bits
bf_read m_DataIn;
bf_write m_DataOut;
};
class CLC_ClientTick : public CNetMessage
{
@ -393,6 +421,16 @@ public:
int m_nStringTableTick;
};
class CLC_SetPlaylistVarOverride : public CNetMessage
{
public:
static bool ReadFromBufferImpl(CLC_SetPlaylistVarOverride* thisptr, bf_read* buffer);
static bool WriteToBufferImpl(CLC_SetPlaylistVarOverride* thisptr, bf_write* buffer);
private:
// !TODO:
};
///////////////////////////////////////////////////////////////////////////////////////
// Client messages:
@ -448,7 +486,9 @@ class V_NetMessages : public IDetour
LogConAdr("SVC_UserMessage::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_UserMessage_VFTable));
LogConAdr("SVC_ServerTick::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_ServerTick_VFTable));
LogConAdr("SVC_VoiceData::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_VoiceData_VFTable));
LogConAdr("SVC_PlaylistOverrides::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_PlaylistOverrides_VFTable));
LogConAdr("CLC_ClientTick::`vftable'", reinterpret_cast<uintptr_t>(g_pCLC_ClientTick_VFTable));
LogConAdr("CLC_SetPlaylistVarOverride::`vftable'", reinterpret_cast<uintptr_t>(g_pCLC_SetPlaylistVarOverride_VFTable));
LogConAdr("Base_CmdKeyValues::`vftable'", reinterpret_cast<uintptr_t>(g_pBase_CmdKeyValues_VFTable));
//LogFunAdr("MM_Heartbeat::ToString", MM_Heartbeat__ToString.GetPtr());
}
@ -465,7 +505,9 @@ class V_NetMessages : public IDetour
g_pSVC_UserMessage_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_UserMessage@@");
g_pSVC_ServerTick_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_ServerTick@@");
g_pSVC_VoiceData_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_VoiceData@@");
g_pSVC_PlaylistOverrides_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_PlaylistOverrides@@");
g_pCLC_ClientTick_VFTable = g_GameDll.GetVirtualMethodTable(".?AVCLC_ClientTick@@");
g_pCLC_SetPlaylistVarOverride_VFTable = g_GameDll.GetVirtualMethodTable(".?AVCLC_SetPlaylistVarOverride@@");
g_pBase_CmdKeyValues_VFTable = g_GameDll.GetVirtualMethodTable(".?AVBase_CmdKeyValues@@");
}
virtual void Attach(void) const;