Having a problem with exploiters

  1. What do you want to achieve?
    I would like to be able to hinder exploiters from ruining game experiences.

  2. What is the issue?
    The issue is that somehow and I don’t know-how exploiters run code that allows them to get 20k strength ever second. The way for players to get this strength is through activating a tool, which then sends a remote event to the server and then the servers check if they did lift and then add strength to a bool value, which is then made equal to equal the leaderstats.
    The exploiter went from 0 strength to 100k strength in less than a minute…

CODE:

--Varaibles
local RS = game:GetService("ReplicatedStorage")
local aB = RS.remoteE:WaitForChild("addBanana")

--IngameEvents
local GlobalEvent = 1

--Events

aB.OnServerEvent:Connect(function(plr)
	if plr.Character.Humanoid or plr.Character:WaitForChild("Humanoid") then
		local pSChildren = pS:GetChildren()
		local depth =  plr.Character.Humanoid.BodyDepthScale.Value
		local height = plr.Character.Humanoid.BodyHeightScale.Value
		local width = plr.Character.Humanoid.BodyWidthScale.Value
		local head = plr.Character.Humanoid.HeadScale.Value
		local humMaxHealth = plr.Character.Humanoid.MaxHealth
		local humSpeed = plr.Character.Humanoid.WalkSpeed
		local msize =  0.003 --For testing = 0.05
		local gPassSize = 0.009
		local bsize = 0.003 --For testing = 0.07
		local gHeadSize = 0.003
		local health = 0.155
		local speedV =0.0055
		local punchpowerV = 0.0045
		local twogamepass = 2
		local morehealthpass = 1.5
		
		for i,v in pairs (game.ServerStorage.playerStats:GetChildren()) do --LOOPS THROUGH A FOLDER WITH VALUES
			if v.Name == plr.Name then
				if v.gamePasses.twoSP.Value == true then
					v.strength.Value = v.strength.Value + (1 * GlobalEvent * twogamepass)
					plr.leaderstats.Strength.Value = v.strength.Value
				else
					v.strength.Value = v.strength.Value + (1 * GlobalEvent )
					plr.leaderstats.Strength.Value = v.strength.Value
				end
				v.totalStrength.Value = v.strength.Value
			end
		end
	end
end)
  1. What solutions have you tried so far?
    I have tried passing the values through different places to hinder the addition to the leaderboard however that did not help.

I hope you guys can help me out and show me where I might be able to better my code and try to fix this problem!

5 Likes

Remotes need to be protected meaning that you must make a Check to see if Remote is allowed because Client are the area that Exploiters can attack and so they can send any remotes: AddBanana must have a ServerSide Check, Can we see you localscript that run that function?

1 Like

As @Trystanus has said, you need some server sided checks, which are called sanity checks. Since you don’t check any logic in your Server it’s open to all exploiters to just fire your remote. To answer if anyone has the question, no, you can’t prevent exploiters from firing your remote event as they have full control over their whole client. Use those sanity checks to your advantage and prevent exploitation of your remotes.

An example would be to check if the player is holding a tool if your game is based off tools or something along the lines that would be logical to check for. Another example would be, a player would not be able to back-stab someone from 100 studs away, so they would check the magnitude of the player.

You also want to be mindful to not give the exploiter too much detail when you are firing your remotes, if you have loads of parameters it’ll be much easier for them to figure out a way to bypass your system.

1 Like

scoopity woop

1 Like

Yeah, here is the local script to fire the event:

Local Script:

--Variables
local RS = game:GetService("ReplicatedStorage")
local aB = RS.remoteE:WaitForChild("addBanana")
local BananaTool = script.Parent
local playeZ = game.Players.LocalPlayer
local deb = false
local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://04915073005"--04869325755 (Glitched Anim)
local sound1 = Instance.new("Sound")
sound1.SoundId = "rbxassetid://990183576"
sound1.Volume = 0.3
sound1.Parent = BananaTool

BananaTool.Activated:Connect(function()
	if playeZ.Character.Humanoid or playeZ.Character:WaitForChild("Humanoid") then
		if not deb then
			deb = true
			local animload = playeZ.Character:WaitForChild("Humanoid"):LoadAnimation(anim)
			animload:Play()
			sound1:Play()
			RS.remoteE.addBanana:FireServer() 
			wait(2)
			deb = false
		end
	end
end)

However I do check the remote event on the server side?

1 Like

If it’s a tool, you can access the Tool.Activated event through a server script.
I would just have a server script parented to the tool and do everything in there

I did not know that. Thank you.

However, even with my sanity check the exploiter still managed to somehow bypass the only way to add points.

Make sure the debounce bool value is on the server. The exploiters have all control over the localside

1 Like

Aye, which makes me wonder how they managed to change the leaderstat’s on the server side.

On the client side they can spam fire a remote so if you have any remote you can spam to get coins you maybe need to add an debounce. with a remote event they will fire the function on the server

A debounce needs to be implemented on both the client and server. One on the client so that it may reduce spamming, and one on the server for sanity checks to make sure they haven’t bypassed the denounce on their client. Another check to implement is checking if they have the tool equipped on the server

Alright. As an example could I do it like this?

local deb

------Inside the Serverevent

 deb = true
 if deb then 
    deb = false
    wait(5)
    deb = true
end

Example.rbxl (18.2 KB)

Thank you! Think I’ve got it now. However, can you not do it with a normal variable? Like:

local debounce = false
if not debounce then
 deboucne  = true
 wait(5)
debounce = false
end

That’s just going to put everyone on a cooldown. What you can do is make a table for the player upon joining and when they fire the event on their client, we add the strength on the server and apply a cooldown. During the cooldown, strength will not be added if the exploiter managed to bypass the cooldown on their client:

local cooldowns = {}
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    cooldowns[player] = false
end)

-- code in the RemoteEvent on the server
if not cooldowns[player] then
    cooldowns[player] = true
    -- add strength and do whatever
    wait(5)
    cooldowns[player] = false
end
-- end of code for the event

Players.PlayerRemoving:Connect(function(player)
    cooldowns[player] = nil
end)
1 Like

i think so but it´s safer if you do it in a bool value

Thank you! That’s a good way of handling that.

yes and no

That’s how you make a normal cooldown but if it’s a server event, this would make all players share that cooldown.

If you had a single script inside a Tool object, you could do something like this:

-- Server Script

Tool = script.Parent

inCooldown = false

Tool.Activated:Connect(function()

  plr = game.Players:GetPlayerFromCharacter(Tool.Parent)

  if not inCooldown then

    inCooldown = true
    
    local pSChildren = pS:GetChildren()
    local depth =  plr.Character.Humanoid.BodyDepthScale.Value
    local height = plr.Character.Humanoid.BodyHeightScale.Value
    local width = plr.Character.Humanoid.BodyWidthScale.Value
    local head = plr.Character.Humanoid.HeadScale.Value
    local humMaxHealth = plr.Character.Humanoid.MaxHealth
    local humSpeed = plr.Character.Humanoid.WalkSpeed
    local msize =  0.003 --For testing = 0.05
    local gPassSize = 0.009
    local bsize = 0.003 --For testing = 0.07
    local gHeadSize = 0.003
    local health = 0.155
    local speedV =0.0055
    local punchpowerV = 0.0045
    local twogamepass = 2
    local morehealthpass = 1.5
    
    local v = game.ServerStorage.playerStats:FindFirstChild(plr.Name)
    if v then
      if v.gamePasses.twoSP.Value == true then
        v.strength.Value = v.strength.Value + (1 * GlobalEvent * twogamepass)
        plr.leaderstats.Strength.Value = v.strength.Value
      else
        v.strength.Value = v.strength.Value + (1 * GlobalEvent )
        plr.leaderstats.Strength.Value = v.strength.Value
      end
      v.totalStrength.Value = v.strength.Value
    end

    wait(2)

    inCooldown = false
    
  end
    
end)

(I changed the for loop to a FindFirstChild)

Though even this has potential security flaws.
Namely, if the user got their hands on multiple copies of the tool, they could spam all of them at once.

so this final method is a little better

-- Server Script

Tool = script.Parent
Debris = game:GetService('Debris')

Tool.Activated:Connect(function()

  plr = game.Players:GetPlayerFromCharacter(Tool.Parent)
  
  local v = game.ServerStorage.playerStats:FindFirstChild(plr.Name)

  inCooldown = plr:FindFirstChild('inCooldown')

  if not inCooldown then
    
    cooldownObj = Instance.new('BoolValue')
    cooldownObj.Name = 'inCooldown'
    cooldownObj.Parent = plr
    -- Add the cooldown object to Debris service's wait list so that it's deleted after 2 seconds
    Debris:AddItem(cooldownObj,2)
    
    local pSChildren = pS:GetChildren()
    local depth =  plr.Character.Humanoid.BodyDepthScale.Value
    local height = plr.Character.Humanoid.BodyHeightScale.Value
    local width = plr.Character.Humanoid.BodyWidthScale.Value
    local head = plr.Character.Humanoid.HeadScale.Value
    local humMaxHealth = plr.Character.Humanoid.MaxHealth
    local humSpeed = plr.Character.Humanoid.WalkSpeed
    local msize =  0.003 --For testing = 0.05
    local gPassSize = 0.009
    local bsize = 0.003 --For testing = 0.07
    local gHeadSize = 0.003
    local health = 0.155
    local speedV =0.0055
    local punchpowerV = 0.0045
    local twogamepass = 2
    local morehealthpass = 1.5
    
    if v then
      if v.gamePasses.twoSP.Value == true then
        v.strength.Value = v.strength.Value + (1 * GlobalEvent * twogamepass)
        plr.leaderstats.Strength.Value = v.strength.Value
      else
        v.strength.Value = v.strength.Value + (1 * GlobalEvent )
        plr.leaderstats.Strength.Value = v.strength.Value
      end
      v.totalStrength.Value = v.strength.Value
    end
    
  end
    
end)

Exactly what I needed to read! Thank you so much for explaining it to me in so much detail, means a lot.

1 Like