mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
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.
This commit is contained in:
parent
0ffcca14ab
commit
7870f1557a
@ -9,9 +9,13 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#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)
|
||||
@ -30,6 +34,9 @@ bool SVC_Print::ProcessImpl()
|
||||
return true; // Original just return true also.
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// re-implementation of 'SVC_UserMessage::Process'
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
bool SVC_UserMessage::ProcessImpl()
|
||||
{
|
||||
bf_read buf = m_DataIn;
|
||||
@ -53,13 +60,43 @@ bool SVC_UserMessage::ProcessImpl()
|
||||
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 SVCPrint = &SVC_Print::ProcessImpl;
|
||||
auto SVCUserMessage = &SVC_UserMessage::ProcessImpl;
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VFTable, (LPVOID&)SVCPrint, 3, (LPVOID*)&SVC_Print_Process);
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VFTable, (LPVOID&)SVCUserMessage, 3, (LPVOID*)&SVC_UserMessage_Process);
|
||||
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
|
||||
}
|
||||
|
||||
@ -67,7 +104,9 @@ void V_NetMessages::Detach() const
|
||||
{
|
||||
#if !defined(DEDICATED)
|
||||
void* hkRestore = nullptr;
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VFTable, (LPVOID)SVC_Print_Process, 3, (LPVOID*)&hkRestore);
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VFTable, (LPVOID)SVC_UserMessage_Process, 3, (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_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
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
class CNetChan;
|
||||
class SVC_Print;
|
||||
class SVC_UserMessage;
|
||||
class Base_CmdKeyValues;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// MM_HEARTBEAT
|
||||
@ -45,6 +46,13 @@ inline void* g_pSVC_UserMessage_VFTable = nullptr;
|
||||
//-------------------------------------------------------------------------
|
||||
inline void* g_pSVC_ServerTick_VFTable = nullptr;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Base_CmdKeyValues
|
||||
//-------------------------------------------------------------------------
|
||||
inline auto Base_CmdKeyValues_ReadFromBuffer = CMemory().RCast<bool(*)(Base_CmdKeyValues* thisptr, bf_read* buffer)>();
|
||||
inline auto Base_CmdKeyValues_WriteToBuffer = CMemory().RCast<bool(*)(Base_CmdKeyValues* thisptr, bf_write* buffer)>();
|
||||
inline void* g_pBase_CmdKeyValues_VFTable = nullptr;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Enumeration of the INetMessage class
|
||||
//-------------------------------------------------------------------------
|
||||
@ -189,12 +197,50 @@ public:
|
||||
nettick_t m_NetTick;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// Client messages:
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NET_StringCmd : CNetMessage
|
||||
{
|
||||
const char* cmd;
|
||||
char buffer[1024];
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// This message is subclassed by 'SVC_CmdKeyValues' and 'CLC_CmdKeyValues'
|
||||
class Base_CmdKeyValues : public CNetMessage
|
||||
{
|
||||
public:
|
||||
virtual ~Base_CmdKeyValues() {};
|
||||
|
||||
virtual void SetNetChannel(CNetChan* netchan) = 0;
|
||||
virtual void SetReliable(bool state) = 0;
|
||||
|
||||
virtual bool Process(void) = 0;
|
||||
|
||||
virtual bool ReadFromBuffer(bf_read* buffer) = 0;
|
||||
static bool ReadFromBufferImpl(Base_CmdKeyValues* thisptr, bf_read* buffer);
|
||||
|
||||
virtual bool WriteToBuffer(bf_write* buffer) = 0;
|
||||
static bool WriteToBufferImpl(Base_CmdKeyValues* thisptr, bf_write* buffer);
|
||||
|
||||
virtual bool IsReliable(void) const = 0;
|
||||
|
||||
virtual int GetGroup(void) const = 0;
|
||||
virtual int GetType(void) const = 0;
|
||||
virtual const char* GetName(void) const = 0;
|
||||
virtual CNetChan* GetNetChannel(void) const = 0;
|
||||
virtual const char* ToString(void) const = 0;
|
||||
virtual size_t GetSize(void) const = 0;
|
||||
|
||||
int m_nMsgType;
|
||||
int m_nLength; // data length in bits
|
||||
bf_read m_DataIn;
|
||||
bf_write m_DataOut;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_NetMessages : public IDetour
|
||||
{
|
||||
@ -203,6 +249,7 @@ class V_NetMessages : public IDetour
|
||||
LogConAdr("SVC_Print::`vftable'", reinterpret_cast<uintptr_t>(g_pSVC_Print_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("Base_CmdKeyValues::`vftable'", reinterpret_cast<uintptr_t>(g_pBase_CmdKeyValues_VFTable));
|
||||
LogFunAdr("MM_Heartbeat::ToString", MM_Heartbeat__ToString.GetPtr());
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
@ -217,6 +264,7 @@ class V_NetMessages : public IDetour
|
||||
g_pSVC_Print_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_Print@@");
|
||||
g_pSVC_UserMessage_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_UserMessage@@");
|
||||
g_pSVC_ServerTick_VFTable = g_GameDll.GetVirtualMethodTable(".?AVSVC_ServerTick@@");
|
||||
g_pBase_CmdKeyValues_VFTable = g_GameDll.GetVirtualMethodTable(".?AVBase_CmdKeyValues@@");
|
||||
}
|
||||
virtual void Attach(void) const;
|
||||
virtual void Detach(void) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user