CL_CopyExistingEntity: implement missing bounds check

Implement bounds check for non-sanitized value of u.m_nNewEntity.
Debug builds of the engine have an assertion, however in release these are stripped.
This fixes a full chain client RCE exploit, for more information, see: https://ctf.re/source-engine/exploitation/2021/05/01/source-engine-2/
This commit is contained in:
Kawe Mazidjatari 2022-09-21 02:38:58 +02:00
parent 7a48c5ab6e
commit 7912b79fa2
9 changed files with 98 additions and 3 deletions

View File

@ -63,6 +63,9 @@
#include "rtech/rtech_utils.h"
#include "rtech/stryder/stryder.h"
#include "rtech/rui/rui.h"
#ifndef DEDICATED
#include "engine/client/cl_ents_parse.h"
#endif // !DEDICATED
#include "engine/client/cl_main.h"
#include "engine/client/client.h"
#include "engine/client/clientstate.h"
@ -149,6 +152,9 @@ void Systems_Init()
#ifdef DEDICATED
//PRX_Attach();
#endif // DEDICATED
#ifndef DEDICATED
CL_Ents_Parse_Attach();
#endif // !DEDICATED
CBaseClient_Attach();
CBaseFileSystem_Attach();
@ -276,6 +282,9 @@ void Systems_Shutdown()
#ifdef DEDICATED
//PRX_Detach();
#endif // DEDICATED
#ifndef DEDICATED
CL_Ents_Parse_Detach();
#endif // !DEDICATED
CBaseClient_Detach();
CBaseFileSystem_Detach();

View File

@ -0,0 +1,33 @@
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose: Parsing of entity network packets.
//
// $NoKeywords: $
//=============================================================================//
#include "core/stdafx.h"
#include "tier0/frametask.h"
#include "public/const.h"
#include "engine/host.h"
#include "engine/client/cl_ents_parse.h"
bool CL_CopyExistingEntity(__int64 a1, unsigned int* a2, char* a3)
{
int nNewEntity = *reinterpret_cast<int*>(a1 + 40);
if (nNewEntity >= MAX_EDICTS || nNewEntity < 0)
{
v_Host_Error("CL_CopyExistingEntity: m_nNewEntity >= MAX_EDICTS");
return false;
}
return v_CL_CopyExistingEntity(a1, a2, a3);
}
void CL_Ents_Parse_Attach()
{
DetourAttach((LPVOID*)&v_CL_CopyExistingEntity, &CL_CopyExistingEntity);
}
void CL_Ents_Parse_Detach()
{
DetourDetach((LPVOID*)&v_CL_CopyExistingEntity, &CL_CopyExistingEntity);
}

View File

@ -0,0 +1,32 @@
#ifndef CL_ENTS_PARSE_H
#define CL_ENTS_PARSE_H
inline CMemory p_CL_CopyExistingEntity;
inline auto v_CL_CopyExistingEntity = p_CL_CopyExistingEntity.RCast<bool (*)(__int64 a1, unsigned int* a2, char* a3)>();
///////////////////////////////////////////////////////////////////////////////
class V_CL_Ents_Parse : public IDetour
{
virtual void GetAdr(void) const
{
spdlog::debug("| FUN: CL_CopyExistingEntity : {:#18x} |\n", p_CL_CopyExistingEntity.GetPtr());
spdlog::debug("+----------------------------------------------------------------+\n");
}
virtual void GetFun(void) const
{
p_CL_CopyExistingEntity = g_GameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x40\x53\x48\x83\xEC\x70\x4C\x63\x51\x28"), "xxxxxxxxxx");
v_CL_CopyExistingEntity = p_CL_CopyExistingEntity.RCast<bool (*)(__int64, unsigned int*, char*)>(); /*40 53 48 83 EC 70 4C 63 51 28*/
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }
virtual void Attach(void) const { }
virtual void Detach(void) const { }
};
///////////////////////////////////////////////////////////////////////////////
void CL_Ents_Parse_Attach();
void CL_Ents_Parse_Detach();
REGISTER(V_CL_Ents_Parse);
#endif // !CL_ENTS_PARSE_H

View File

@ -7,7 +7,7 @@ inline CMemory p_Host_RunFrame_Render;
inline auto v_Host_RunFrame_Render = p_Host_RunFrame_Render.RCast<void(*)(void)>();
inline CMemory p_Host_Error;
inline auto v_Host_Error = p_Host_Error.RCast<int(*)(char* error, ...)>();
inline auto v_Host_Error = p_Host_Error.RCast<int(*)(const char* error, ...)>();
inline CMemory p_VCR_EnterPausedState;
inline auto v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
@ -47,7 +47,7 @@ class VHost : public IDetour
v_Host_RunFrame = p_Host_RunFrame.RCast<void(*)(void*, float)>();
v_Host_RunFrame_Render = p_Host_Error.RCast<void(*)(void)>();
v_Host_Error = p_Host_Error.RCast<int(*)(char*, ...)>();
v_Host_Error = p_Host_Error.RCast<int(*)(const char*, ...)>();
v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
}
virtual void GetVar(void) const

View File

@ -8,6 +8,11 @@
#ifndef CONST_H
#define CONST_H
// How many bits to use to encode an edict.
#define MAX_EDICT_BITS 14 // # of bits needed to represent max edicts
// Max # of edicts in a level
#define MAX_EDICTS (1<<MAX_EDICT_BITS)
enum RenderMode_t
{
kRenderNormal = 0, // src
@ -25,4 +30,4 @@ enum RenderMode_t
kRenderModeCount, // must be last
};
#endif
#endif // CONST_H

View File

@ -29,6 +29,7 @@
<ClCompile Include="..\ebisusdk\EbisuSDK.cpp" />
<ClCompile Include="..\engine\client\client.cpp" />
<ClCompile Include="..\engine\client\clientstate.cpp" />
<ClCompile Include="..\engine\client\cl_ents_parse.cpp" />
<ClCompile Include="..\engine\client\cl_rcon.cpp" />
<ClCompile Include="..\engine\clockdriftmgr.cpp" />
<ClCompile Include="..\engine\cmodel_bsp.cpp" />
@ -170,6 +171,7 @@
<ClInclude Include="..\ebisusdk\EbisuSDK.h" />
<ClInclude Include="..\engine\client\client.h" />
<ClInclude Include="..\engine\client\clientstate.h" />
<ClInclude Include="..\engine\client\cl_ents_parse.h" />
<ClInclude Include="..\engine\client\cl_main.h" />
<ClInclude Include="..\engine\client\cl_rcon.h" />
<ClInclude Include="..\engine\clockdriftmgr.h" />

View File

@ -594,6 +594,9 @@
<ClCompile Include="..\engine\sdk_dll.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
<ClCompile Include="..\engine\client\cl_ents_parse.cpp">
<Filter>sdk\engine\client</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1754,6 +1757,9 @@
<ClInclude Include="..\engine\sdk_dll.h">
<Filter>sdk\engine</Filter>
</ClInclude>
<ClInclude Include="..\engine\client\cl_ents_parse.h">
<Filter>sdk\engine\client</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">

View File

@ -29,6 +29,7 @@
<ClCompile Include="..\ebisusdk\EbisuSDK.cpp" />
<ClCompile Include="..\engine\client\client.cpp" />
<ClCompile Include="..\engine\client\clientstate.cpp" />
<ClCompile Include="..\engine\client\cl_ents_parse.cpp" />
<ClCompile Include="..\engine\client\cl_rcon.cpp" />
<ClCompile Include="..\engine\clockdriftmgr.cpp" />
<ClCompile Include="..\engine\cmodel_bsp.cpp" />
@ -180,6 +181,7 @@
<ClInclude Include="..\ebisusdk\EbisuSDK.h" />
<ClInclude Include="..\engine\client\client.h" />
<ClInclude Include="..\engine\client\clientstate.h" />
<ClInclude Include="..\engine\client\cl_ents_parse.h" />
<ClInclude Include="..\engine\client\cl_main.h" />
<ClInclude Include="..\engine\client\cl_rcon.h" />
<ClInclude Include="..\engine\clockdriftmgr.h" />

View File

@ -633,6 +633,9 @@
<ClCompile Include="..\engine\sdk_dll.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
<ClCompile Include="..\engine\client\cl_ents_parse.cpp">
<Filter>sdk\engine\client</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1841,6 +1844,9 @@
<ClInclude Include="..\engine\sdk_dll.h">
<Filter>sdk\engine</Filter>
</ClInclude>
<ClInclude Include="..\engine\client\cl_ents_parse.h">
<Filter>sdk\engine\client</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">