r5sdk/r5dev/common/netmessages.cpp
Kawe Mazidjatari 7870f1557a Fix 'CLC_CmdKeyValues' exploit
Fix exploitation vector that could be performed on the game client to submit commands to other game clients connected to the same server, specifically the 'OnPlayerAward' command. Base_CmdKeyValues now only works when sv_cheats is enabled. SVC/CLC_CmdKeyValues subclass 'Base_CmdKeyValues', so these messages are 'fixed' as well.
2023-04-15 02:13:29 +02:00

112 lines
4.4 KiB
C++

//===============================================================================//
//
// Purpose:
//
// $NoKeywords: $
//
//===============================================================================//
// netmessages.cpp: implementation of the CNetMessage types.
//
///////////////////////////////////////////////////////////////////////////////////
#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "engine/net.h"
#include "common/netmessages.h"
///////////////////////////////////////////////////////////////////////////////////
// re-implementation of 'SVC_Print::Process'
///////////////////////////////////////////////////////////////////////////////////
bool SVC_Print::ProcessImpl()
{
if (this->m_szText)
{
Assert(m_szText == m_szTextBuffer); // Should always point to 'm_szTextBuffer'.
size_t len = strnlen_s(m_szText, sizeof(m_szTextBuffer));
Assert(len < sizeof(m_szTextBuffer));
if (len < sizeof(m_szTextBuffer))
{
DevMsg(eDLL_T::SERVER, m_szText[len-1] == '\n' ? "%s" : "%s\n", m_szText);
}
}
return true; // Original just return true also.
}
///////////////////////////////////////////////////////////////////////////////////
// re-implementation of 'SVC_UserMessage::Process'
///////////////////////////////////////////////////////////////////////////////////
bool SVC_UserMessage::ProcessImpl()
{
bf_read buf = m_DataIn;
int type = buf.ReadByte();
if (type == HUD_PRINTCONSOLE ||
type == HUD_PRINTCENTER)
{
char text[MAX_USER_MSG_DATA];
int len;
buf.ReadString(text, sizeof(text), false, &len);
Assert(len < sizeof(text));
if (len >= NET_MIN_MESSAGE && len < sizeof(text))
{
DevMsg(eDLL_T::SERVER, text[len-1] == '\n' ? "%s" : "%s\n", text);
}
}
return SVC_UserMessage_Process(this); // Need to return original.
}
///////////////////////////////////////////////////////////////////////////////////
// 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
// 'UTIL_SendClientCommandKVToPlayer' which forwards the keyvalues to all connected clients.
///////////////////////////////////////////////////////////////////////////////////
bool Base_CmdKeyValues::ReadFromBufferImpl(Base_CmdKeyValues* thisptr, bf_read* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return Base_CmdKeyValues_ReadFromBuffer(thisptr, buffer);
}
bool Base_CmdKeyValues::WriteToBufferImpl(Base_CmdKeyValues* thisptr, bf_write* buffer)
{
// Abusable netmsg; only allow if cheats are enabled.
if (!sv_cheats->GetBool())
{
return false;
}
return Base_CmdKeyValues_WriteToBuffer(thisptr, buffer);
}
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
}
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
}