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. 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 // 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 // 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 void V_NetMessages::Attach() const
{ {
#if !defined(DEDICATED)
auto hk_SVCPrint_Process = &SVC_Print::ProcessImpl; auto hk_SVCPrint_Process = &SVC_Print::ProcessImpl;
auto hk_SVCUserMessage_Process = &SVC_UserMessage::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_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_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*)&Base_CmdKeyValues::ReadFromBufferImpl, 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); CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID*)&Base_CmdKeyValues::WriteToBufferImpl, NetMessageVtbl::WriteToBuffer, (LPVOID*)&Base_CmdKeyValues_WriteToBuffer);
#endif // DEDICATED 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 void V_NetMessages::Detach() const
{ {
#if !defined(DEDICATED)
void* hkRestore = nullptr; 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_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_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_ReadFromBuffer, NetMessageVtbl::ReadFromBuffer, (LPVOID*)&hkRestore);
CMemory::HookVirtualMethod((uintptr_t)g_pBase_CmdKeyValues_VFTable, (LPVOID)Base_CmdKeyValues_WriteToBuffer, NetMessageVtbl::WriteToBuffer, (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 CNetChan;
class SVC_Print; class SVC_Print;
class SVC_UserMessage; class SVC_UserMessage;
class SVC_PlaylistOverrides;
class CLC_SetPlaylistVarOverride;
class Base_CmdKeyValues; class Base_CmdKeyValues;
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -51,11 +53,25 @@ inline void* g_pSVC_ServerTick_VFTable = nullptr;
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
inline void* g_pSVC_VoiceData_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 // CLC_ClientTick
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
inline void* g_pCLC_ClientTick_VFTable = nullptr; 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 // Base_CmdKeyValues
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -339,6 +355,18 @@ public:
void* m_DataOut; 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 class CLC_ClientTick : public CNetMessage
{ {
@ -393,6 +421,16 @@ public:
int m_nStringTableTick; 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: // 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_UserMessage::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_UserMessage_VFTable));
LogConAdr("SVC_ServerTick::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_ServerTick_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_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_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)); LogConAdr("Base_CmdKeyValues::`vftable'", reinterpret_cast<uintptr_t>(g_pBase_CmdKeyValues_VFTable));
//LogFunAdr("MM_Heartbeat::ToString", MM_Heartbeat__ToString.GetPtr()); //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_UserMessage_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_UserMessage@@");
g_pSVC_ServerTick_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_ServerTick@@"); g_pSVC_ServerTick_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_ServerTick@@");
g_pSVC_VoiceData_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_VoiceData@@"); 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_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@@"); g_pBase_CmdKeyValues_VFTable = g_GameDll.GetVirtualMethodTable(".?AVBase_CmdKeyValues@@");
} }
virtual void Attach(void) const; virtual void Attach(void) const;