Exploit Side of Things: Part 1

Your own game can be exploited and it's probably your code.

by Lykaon

Author Avatar

Preface, More Information, and Requirements:

This lesson requires a basic understanding of how FilteringEnabled works, alongside a fair amount of experience with scripting in ROBLOX.

This post will detail what exploiters can do if your game is vulnerable and what to do if you find a vulnerability.

I also want to provide further information in which you can proceed to go in-depth and understand the concepts. I highly suggest looking at the DevForum link provided below by Autterfly. He provides a ton more information than this post provides. Please also check the links posted on the ROBLOX Developer website to understand FilteringEnabled & security more.

Extra Credit to:

[1] Autterfly

https://devforum.roblox.com/t/exploiting-explained/170977

[2] ROBLOX: Game Security

https://developer.roblox.com/en-us/articles/Game-Security

[3] ROBLOX: Remote Functions and Events

https://developer.roblox.com/en-us/articles/Remote-Functions-and-Events

[4] ROBLOX: Roblox Client-Server Model

https://developer.roblox.com/en-us/articles/Roblox-Client-Server-Model

Introduction:

Ever since the permanent implementation of FilteringEnabled, a large number of games were broken. This was mostly because they used LocalScripts. The cool free model script of the ice god Neflhelm you found appears on your screen and it's so cool! You get to shoot lasers, bring up icicles, and form big barriers of snow & ice.

However, for your friend, he just sees you floating in the air in front of him.

Just your character.

This is FilteringEnabled in action. While there are plenty of great tutorials that further explain FilteringEnabled to you, we still need to understand the basic concept of the Client-Server model, how information passed along RemoteEvents can be manipulated and changed, and some of the various possibilites of what could happen to your game.

Keep in mind of this rule:

NEVER. TRUST. THE. CLIENT.


Section 1: The Client-Server Model In A Nutshell

Let's start off with a basic example. There were two players: Player 1 and Player 2.

Player 1 has loaded an exploit and is able to execute any code he wants to. He proceeds to execute this piece of code:

workspace.Player2:BreakJoints()

Now on his screen, Player 2 just fell apart. Player 2 on the other hand is still walking around as if nothing has happened.

This is the Client-Server Model. The changes that is made from one client isn't sent over to ROBLOX's server, therefore ROBLOX doesn't send that information to Player 2.

Player 2 is still alive and well, and doesn't have to suffer Player 1's abuse.


Section 2: How YOUR Code Can Result In Disaster

There is a method to communicate information to the server. Using RemoteEvents and RemoteFunctions, information can be passed from the client to the server, or server to the client.

Bad Example 1: Flawed Code

When the client wants to communicate the server but isn't expecting a response, it has to fire a RemoteEvent. Let's say whenever I clicked a button on my screen, it gives me points. The server has to interpret the information from the fired RemoteEvent. Let's say I wanted to give myself 30 points everytime I clicked that button. I go ahead and write down the code and press play.

--LocalScript
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local Button
local RemoteEvent = ReplicatedStorage:WaitForChild("PointGiver")

local function Client_GivePoints()
    RemoteEvent:FireServer(30)
end

Button.MouseButton1Down:Connect(Client_GivePoints)

--Server Script
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteEvent = ReplicatedStorage:WaitForChild("PointGiver")

local function Server_GivePoints(Player,PointAmount)
    local IntValue = ServerStorage:FindFirstChild(Player.Name.."_Points)
    if IntValue then
        IntValue.Value = IntValue.Value + PointAmount
    end
end

RemoteEvent.OnServerEvent:Connect(Server_GivePoints)

End of Example 1

Something is very wrong with this script.

How?

Look at the function: Server_GivePoints

Once the RemoteEvent fires, two arguments are passed. The player, and the amount of points. The function runs, looking in ServerStorage for the pointholder. In this case, it's a IntValue object. The function finds the point holder, and proceeds to add the amount of points, and it ends.

The major problem here was that the amount of points was determined by the client. As you can see in the Server Script, the server takes the information from the client and uses it. An exploiter can easily run this code:

game:GetService("ReplicatedStorage").PointGiver:FireServer(500000)

This is a very big problem is that a person can get a million of points, thus surpassing everyone else through unfair means and depending upon how those values are utilized in your game, can be very disastrous.

Bad Example 2: The Band-Aid Solution

But what if the server only TAKES away points? Then I should be safe right?

Nope. You're still receiving information AND utilizing that information from the client. Take this code for example:

--Server Script
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Server_RemoteEvent = ReplicatedStorage:WaitForChild("PointGiver")

local function Server_GivePoints(Player,PointAmount)
    local IntValue = ServerStorage:FindFirstChild(Player.Name.."_Points)
    if IntValue then
        IntValue.Value = IntValue.Value - PointAmount
    end
end

How can an exploiter take advantage of this? Simple. All they need to do is run this code:

game:GetService("ReplicatedStorage").PointGiver:FireServer(-500)

What the code on the server is running now:

IntValue.Value = IntValue.Value - (-500)

A double negative equals a positive. An exploiter just gave himself points just by flipping a sign.

End of Example 2

Well darn, what can I do now?

We're going to have to make some changes to both the scripts if we want to make this secure. We have to remember the golden rule: never trust the client.

Good Example

First of all, there's no need to USE the information from the client. Obviously we need to know if this person is buying something or lost points, but all the information that needs to be calculated should be on the server. All we really need right now is a sign from the client to subtract the points, but we won't TAKE the amount of points from the client.

Take the code below for example:

--LocalScript
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local Button
local RemoteEvent = ReplicatedStorage:WaitForChild("PointGiver")

local function Client_GivePoints()
    RemoteEvent:FireServer("SubtractPoints")
end

Button.MouseButton1Down:Connect(Client_GivePoints)

--Server Script
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteEvent = ReplicatedStorage:WaitForChild("PointGiver")

local function Server_GivePoints(Player,Method)
    if Method == "SubtractPoints" then
        local IntValue = ServerStorage:FindFirstChild(Player.Name.."_Points)
        if IntValue then
            IntValue.Value = IntValue.Value - 30
        end
    end
end

RemoteEvent.OnServerEvent:Connect(Server_GivePoints)

So how is this different?

In this example, all we did now is just pass over a string.

The exploiter can't fire any other types of arguments because the RemoteEvent doesn't need to. The condition hasn't been met, in which it MUST pass over the string "SubtractPoints" in order for the server to do something. If the exploiter does fire it with that argument, the exploiter couldn't pass any information over such as the amount of points because that's already been set by the server.

It's also very unlikely that the exploiter would want to lose points for any reason whatsoever, since the goal here is to get a lot of it.

End of Good Example

This is one of many ways that you can do to protect your game's crucial functionalities. However, there are STILL cases in which you don't even want to bother letting the client send anything. For example, an AddPoints RemoteEvents, where if the client fires this RemoteEvent, it adds points on the server.

This is BAD, because an exploiter can just run this code and receive 30 points for the indefinite time.

game:GetService("ReplicatedStorage").AddPoints:FireServer()

While it takes a lot longer to receive a ton of points, they can easily just copy and paste the code over and over again, run a loop to add it, or both!

In this context using these examples, you absolutely need to let the server determine what values to add or subtract, but also think about how these exploiters can use it to their advantage.

Be sure to apply this concept when creating your game: Any LocalScript can be manipulated.


Section 3: What Can and Can't Be Done

Now while all of this can sound exciting and you feel like you own the world, you need to take a step back and understand what's going on behind the scenes, what you can do, and what you can't do.

  1. You can't find every single exploiter.
    
  2. You can't stop every single exploit.
    
  3. Doing too much is not necessary, but you CAN make it harder.
    
  4. It's difficult to locate basic enhancements (ex. ESP). 
    
  5. It's difficult to locate whose at fault at times. 
    
  6. Gather facts and information. You don't want to ban the wrong person.
    

ROBLOX is endlessly updating their game all the time, and there is no doubt about it that there's plenty of measures in place which makes exploiter's lives a bit more difficult. However there will ALWAYS be people that will find a way around things, and it's your responsibility in the end to protect your game and your players as much as possible.

Remember that.


Conclusion

This is only a portion of how you'd be able to protect your game.

Due to the format of how these lessons are formed and in the case this gets published, I will be writing a part 2.

It will focus more on client-sided and server-sided checking, alongside personal recommendations of mine, and how I prevent or locate exploiters in action.

Leave a review, and let me know if you have any questions or concerns.

Keep educating yourselves and never trust the client.

Written by: [X] Lykaon Discord: Lykaon#1118

Special Thanks To: [X] Autterfly - Education/Sources [X] ROBLOX Dev Wiki - Information/Sources