From 1460a7ad91a708cef38e7deb8af887229def7531 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 Oct 2016 15:51:49 +0300 Subject: [PATCH] Fix for HealOtherPlayer exploit, also fix #1309 --- TShockAPI/ConfigFile.cs | 4 ++++ TShockAPI/GetDataHandlers.cs | 40 +++++++++++++++++++++++++++++++++++- TShockAPI/TSPlayer.cs | 7 ++++++- TShockAPI/TShock.cs | 11 +++++++++- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index c4f9cf35..2b9466ca 100755 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -295,6 +295,10 @@ namespace TShockAPI [Description("Disable a player if this number of projectiles is created within 1 second.")] public int ProjectileThreshold = 50; + /// ProjectileThreshold - Disables a player if this number of projectiles is created within 1 second. + [Description("Disable a player if this number of projectiles is created within 1 second.")] + public int HealOtherThreshold = 50; + /// ProjIgnoreShrapnel - Whether or not to ignore shrapnel from crystal bullets for the projectile threshold count. [Description("Ignore shrapnel from crystal bullets for projectile threshold.")] public bool ProjIgnoreShrapnel = true; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 92a8b7f6..0f7781f3 100755 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1261,7 +1261,8 @@ namespace TShockAPI { PacketTypes.PlaceItemFrame, HandlePlaceItemFrame }, { PacketTypes.SyncExtraValue, HandleSyncExtraValue }, { PacketTypes.LoadNetModule, HandleLoadNetModule }, - { PacketTypes.ToggleParty, HandleToggleParty } + { PacketTypes.ToggleParty, HandleToggleParty }, + { PacketTypes.PlayerHealOther, HandleHealOther } }; } @@ -1283,6 +1284,43 @@ namespace TShockAPI return false; } + private static bool HandleHealOther(GetDataHandlerArgs args) + { + byte plr = args.Data.ReadInt8(); + short amount = args.Data.ReadInt16(); + + if (amount <= 0 || Main.player[plr] == null || !Main.player[plr].active) + { + return true; + } + + if (amount > TShock.Config.MaxDamage * 0.2) + { + args.Player.Disable("HealOtherPlayer max amount cheat attempt!", DisableFlags.WriteToLogAndConsole); + return true; + } + + if (args.TPlayer.whoAmI != plr && (args.TPlayer.team == 0 || args.TPlayer.team != Main.player[plr].team)) + { + args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole); + return true; + } + + if (args.Player.HealOtherThreshold > TShock.Config.HealOtherThreshold) + { + args.Player.Disable("Reached HealOtherPlayer threshold.", DisableFlags.WriteToLogAndConsole); + return true; + } + + if (TShock.CheckIgnores(args.Player) || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + return true; + } + + args.Player.HealOtherThreshold++; + return false; + } + private static bool HandlePlayerSlot(GetDataHandlerArgs args) { byte plr = args.Data.ReadInt8(); diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 95feb980..d8a5537a 100755 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -93,7 +93,12 @@ namespace TShockAPI /// The number of projectiles created by the player in the last second. /// public int ProjectileThreshold { get; set; } - + + /// + /// The number of HealOtherPlayer packets sent by the player in the last second. + /// + public int HealOtherThreshold { get; set; } + /// /// A timer to keep track of whether or not the player has recently thrown an explosive /// diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 1bbb7052..046f274c 100755 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1030,6 +1030,15 @@ namespace TShockAPI player.PaintThreshold = 0; } + if (player.HealOtherThreshold > TShock.Config.HealOtherThreshold) + { + player.Disable("Reached HealOtherPlayer threshold", flags); + } + if (player.HealOtherThreshold > 0) + { + player.HealOtherThreshold = 0; + } + if (player.RespawnTimer > 0 && --player.RespawnTimer == 0 && player.Difficulty != 2) { player.Spawn(); @@ -1458,7 +1467,7 @@ namespace TShockAPI /// The CommandEventArgs object private void ServerHooks_OnCommand(CommandEventArgs args) { - if (args.Handled) + if (args.Handled || string.IsNullOrWhiteSpace(args.Command)) return; // Damn you ThreadStatic and Redigit