From e75d7561f090eca1a76b2bc0bb7de9dc3f1d5081 Mon Sep 17 00:00:00 2001
From: -ffs-PLASMA <33094646+ffsPLASMA@users.noreply.github.com>
Date: Sat, 8 Feb 2025 01:52:39 +0100
Subject: [PATCH] Add recently introduced events, name and explosion/projectile
checking (#588)
---
[admin]/security/events.lua | 24 ++++++++-
[admin]/security/meta.xml | 3 +-
[admin]/security/players.lua | 101 ++++++++++++++++++++++++++++++++++-
[admin]/security/utils.lua | 16 ++++++
4 files changed, 141 insertions(+), 3 deletions(-)
create mode 100644 [admin]/security/utils.lua
diff --git a/[admin]/security/events.lua b/[admin]/security/events.lua
index b918bedf9..50c2d4569 100644
--- a/[admin]/security/events.lua
+++ b/[admin]/security/events.lua
@@ -12,4 +12,26 @@ addEventHandler("onPlayerTriggerInvalidEvent", root, clientTriggersInvalidEvent)
function clientTriggersEventThreshold()
logViolation(source, "Exceeded event trigger threshold of "..tostring(getServerConfigSetting("max_player_triggered_events_per_interval")));
end
-addEventHandler("onPlayerTriggerEventThreshold", root, clientTriggersEventThreshold);
\ No newline at end of file
+addEventHandler("onPlayerTriggerEventThreshold", root, clientTriggersEventThreshold);
+
+
+
+-- https://wiki.multitheftauto.com/wiki/OnPlayerConnect
+-- we use onPlayerConnect event to check if the player got a valid username
+function clientConnectServer(strPlayerNick, strPlayerIP, strPlayerUsername, strPlayerSerial, iPlayerVersionNumber, strPlayerVersionString)
+ if(not isPlayerNameValid(strPlayerNick)) then
+ logAction("Client "..strPlayerNick.." with IP "..strPlayerIP.." and Serial "..strPlayerSerial.." tried to join with invalid nickname! Version: "..iPlayerVersionNumber.." | "..strPlayerVersionString);
+ cancelEvent(true, "INVALID NICKNAME!");
+ return;
+ end
+end
+addEventHandler("onPlayerConnect", root, clientConnectServer);
+
+
+
+-- https://wiki.multitheftauto.com/wiki/OnPlayerChangesWorldSpecialProperty
+-- gets triggered when client changes world special property
+function clientChangesWorldSpecialProperty(strProperty, bEnabled)
+ logViolation(source, "Changed world special property \""..strProperty.."\" to "..tostring(bEnabled));
+end
+addEventHandler("onPlayerChangesWorldSpecialProperty", root, clientChangesWorldSpecialProperty);
\ No newline at end of file
diff --git a/[admin]/security/meta.xml b/[admin]/security/meta.xml
index 736b40ee2..a255356de 100644
--- a/[admin]/security/meta.xml
+++ b/[admin]/security/meta.xml
@@ -1,8 +1,9 @@
-
+
+
diff --git a/[admin]/security/players.lua b/[admin]/security/players.lua
index 4eb979784..7f2f87973 100644
--- a/[admin]/security/players.lua
+++ b/[admin]/security/players.lua
@@ -1,3 +1,14 @@
+-- used to check how many explosion/projectile sync packets a client sends overtime
+local iExplosionCheckInterval = 3000; -- the interval in ms to check for players sending too many explosion and projectile sync packets
+local tblPlayerProjectiles = {}; -- store players sending projectile sync packets
+local tblRegularExplosions = {}; -- store players sending regular explosion sync packets
+local tblVehicleExplosions = {}; -- store players sending vehicle explosion sync packets
+local iPlayerProjectileThreshold = 10; -- the threshold when we consider client suspicious for projectile creations
+local iRegularExplosionThreshold = 10; -- the threshold when we consider client suspicious for regular explosions
+local iVehicleExplosionThreshold = 10; -- the threshold when we consider client suspicious for vehicle explosions
+
+
+
-- add the elementdatas you want to protect from client updates in here
local tblProtectedElementDatas = {["Score"] = true};
@@ -16,6 +27,18 @@ addEventHandler("onElementDataChange", root, clientChangesElementData);
+-- https://wiki.multitheftauto.com/wiki/OnPlayerChangesProtectedData
+-- gets triggered when a client tries to change protected element data
+-- see elementdata_whitelisted config https://wiki.multitheftauto.com/wiki/Server_mtaserver.conf#elementdata_whitelisted
+-- this needs to be setup in conjunction with your existing elementdatas to take necessary action!
+-- the key feature is to prevent the client from updating non synced server elementdatas if they know the key and attached element
+function clientChnagesProtectedData(uElement, strKey, unValue)
+ logViolation(source, "Tried to change protected elementdata for key "..tostring(strKey).." to value "..tostring(unValue).." for element "..tostring(uElement).." ("..getElementType(uElement)..")");
+end
+addEventHandler("onPlayerChangesProtectedData", root, clientChnagesProtectedData);
+
+
+
-- https://wiki.multitheftauto.com/wiki/OnPlayerACInfo
-- gets triggered when AC detects something for client on connect
function clientNotifyACInfo(tblDetectedACList, iD3D9Size, strD3D9MD5, strD3D9SHA256)
@@ -55,4 +78,80 @@ function clientNetworkStatus(iStatus, iTicks)
logViolation(source, "Network interruption has stopped after "..iTicks.." ticks");
end
end
-addEventHandler("onPlayerNetworkStatus", root, clientNetworkStatus);
\ No newline at end of file
+addEventHandler("onPlayerNetworkStatus", root, clientNetworkStatus);
+
+
+
+-- https://wiki.multitheftauto.com/wiki/OnPlayerProjectileCreation
+-- gets triggered when a player creates a projectile sync packets (eg. shoots a weapon, vehicle weapon or via createProjectile)
+function clientCreateProjectile(iWeaponType, fPX, fPY, fPZ, fForce, uTarget, fRX, fRY, fRZ, fVX, fVY, fVZ)
+ if(isElement(source)) then
+ if(tblPlayerProjectiles[source]) then
+ tblPlayerProjectiles[source] = tblPlayerProjectiles[source] + 1;
+ else
+ tblPlayerProjectiles[source] = 1;
+ end
+ end
+end
+addEventHandler("onPlayerProjectileCreation", root, clientCreateProjectile);
+
+
+
+-- https://wiki.multitheftauto.com/wiki/OnExplosion
+-- gets triggered when an explosion occurs, either via server script or client sync packet
+function clientCreateExplosion(fPX, fPY, fPZ, iType)
+ if(isElement(source)) then
+ if(getElementType(source) == "player") then
+ if(tblRegularExplosions[source]) then
+ tblRegularExplosions[source] = tblRegularExplosions[source] + 1;
+ else
+ tblRegularExplosions[source] = 1;
+ end
+ end
+ end
+end
+addEventHandler("onExplosion", root, clientCreateExplosion);
+
+
+
+-- https://wiki.multitheftauto.com/wiki/OnVehicleExplode
+-- gets triggered when a vehicle explodes, either via server script or client sync packet
+function clientCreateVehicleExplosion(bWithExplosion, uPlayer)
+ if(isElement(uPlayer)) then
+ if(tblVehicleExplosions[uPlayer]) then
+ tblVehicleExplosions[uPlayer] = tblVehicleExplosions[uPlayer] + 1;
+ else
+ tblVehicleExplosions[uPlayer] = 1;
+ end
+ end
+end
+addEventHandler("onVehicleExplode", root, clientCreateVehicleExplosion);
+
+
+
+-- setup a timer with specified interval above and check if any client sent too many sync packets in the given time
+-- thresholds need to be adjusted for your need and actions taken!
+setTimer(function()
+ for uPlayer, iCounter in pairs(tblPlayerProjectiles) do
+ if(iCounter >= iPlayerProjectileThreshold) then
+ logViolation(uPlayer, "Exceeded projectile threshold "..tostring(iPlayerProjectileThreshold).." - Count: "..tostring(iCounter));
+ end
+ end
+
+ for uPlayer, iCounter in pairs(tblRegularExplosions) do
+ if(iCounter >= iRegularExplosionThreshold) then
+ logViolation(uPlayer, "Exceeded regular explosions threshold "..tostring(iRegularExplosionThreshold).." - Count: "..tostring(iCounter));
+ end
+ end
+
+ for uPlayer, iCounter in pairs(tblVehicleExplosions) do
+ if(iCounter >= iVehicleExplosionThreshold) then
+ logViolation(uPlayer, "Exceeded vehicle explosions threshold "..tostring(iVehicleExplosionThreshold).." - Count: "..tostring(iCounter));
+ end
+ end
+
+ tblPlayerProjectiles = {};
+ tblRegularExplosions = {};
+ tblVehicleExplosions = {};
+
+end, iExplosionCheckInterval, 0);
\ No newline at end of file
diff --git a/[admin]/security/utils.lua b/[admin]/security/utils.lua
new file mode 100644
index 000000000..fa7bee82a
--- /dev/null
+++ b/[admin]/security/utils.lua
@@ -0,0 +1,16 @@
+-- checks if a player nickname is valid in terms of length and ascii chars
+function isPlayerNameValid(strPlayerName)
+ if(not strPlayerName) then return false end;
+ if(not tostring(strPlayerName)) then return false end;
+ if(#strPlayerName == 0) then return false end;
+ if(#strPlayerName > 22) then return false end;
+
+ for i = 1, #strPlayerName do
+ local strChar = strPlayerName:sub(i, i);
+ local iCharByte = strChar:byte();
+
+ if(iCharByte < 33 or iCharByte > 126) then return false end;
+ end
+
+ return true;
+end
\ No newline at end of file