Sulphur [Anticheat module]

Edit: It’s been a little while since I posted this but, I don’t recommend using a client sided anti cheat, if possible, use a server sided anti cheat instead; this may stop exploiters who don’t know what they’re doing but, an experienced exploiter could easily bypass this through the use of metamethods and functions hooks.

Sulphur

Just another project I was working on because I was bored

About Sulphur

Sulphur is a client sided anti cheat module I’ve been working for a little while now and I thought I would open source it since I haven’t come across an anti cheat on The Devforum yet.
It was created to prevent client sided exploits such as teleportation.

How to get Sulphur

How to use Sulphur

Sulphur was designed with security in mind, it uses an authentication key which is generated to authenticate whether a function was called from a script which has been authorized or else, the called function won’t run.

Authenticating a script
The module should contain a Child called Scripts which is an IntValue, change the value of Scripts to the number of scripts which will use Sulphur (I recommend placing scripts which will use Sulphur in ReplicatedFirst since we don’t want an exploiter to be given a key & I don’t recommend placing the module in a folder which will be explained later).

local AuthenticationKey = Sulphur:Authenticate()
This will return a key which will be used to authenticate requests, each script will be provided a unique key

Checking if a script has been removed
We don’t want an exploiter to disable scripts which use Sulphur; using the module would be futile as a result.
We will be using our Authentication Key to verify that we are calling the function through an authorized script

Sulphur:ScriptRemovedCheck(AuthenticationKey, {Table})
The table will contain the locations which we want to check(e.g game.ReplicatedFirst)
We will place 2 scripts in the same directory which will both check if a script has been removed, we will use 2 scripts because, if we were using 1 script, it could be easily removed without triggering the check
I recommend that you don’t use a folder since folders can be destroyed and the script won’t be able to check if the folder which it’s in has been removed, instead, place the scripts in a location which can’t be removed such as ReplicatedFirst or StarterPlayerScripts

Checking if a script has been disabled
As well as checking if a script has been removed, we will also check if a script has been disabled, since scripts can be disabled by exploiters which would make using an anticheat module useless.

Sulphur:ScriptDisableCheck(AuthenticationKey, {Table})
We’ll call this from 2 scripts, if we had one script checking if a script has become disabled, it could be easily disabled without triggering the check

Checking if a player has changed their speed
We can check if a player has changed their speed, we could check on the server but bear in mind, this is a clientsided anticheat and it’s made to reduce strain on the server (I might work on a server sided anticheat in the future)

Sulphur:EnableHumanoidSpeedCheck(AuthenticationKey)
If a player attempts to change their speed, it will be changed back to the speed allowed by the developer, if you want to change a players speed, there is a function that can be used which will be explained later

Checking if a player has teleported
You can check if a player has teleported by measuring the total distance they have moved by within a given time. We can use a really simple equation to measure the maximum distance the player can travel within a given time (Distance = Speed * Time).

  • First, we find the players position then we wait (I’ve used RenderStepped:Wait()) since it seems to be the most accurate. Before we wait, we will store the current time in a local variable then, after the wait, we will find the players position again, then will calculate the total time taken.

  • We will work out the magnitude by creating a vector using Vector2; we will also subtract the players walk speed multiplied by the time taken to account for the time taken by the wait().
    We will calculate the maximum distance possible by multiplying it by 0.1 which is an upper bound to decrease the frequency of / (prevent) false positives.

  • Once we have done all the calculations, we can check if the magnitude is greater than the maximum distance possible, if so, we will move the player back to where they were before and the player will be given a strike, if the number of strikes exceeds 10 (feel free to modify this value or delete the function), the player will teleported back to the game preventing them from attaching them selves to players. (We’re assuming that they must be trying to attach them selves to a player if they’re trying to teleport more than 10 times)

Sulphur:AntiTeleportation(AuthenticationKey)
Note: This is only for the axis X and Z since a player can jump from a building which would trigger a false positive, there is a check for the Y axis which will be explained later.
As long as you don’t change the players speed to something extremely high such as 1000, there shouldn’t be any false positives

Checking if a player is attempting to fly
I won’t go into much detail about how this function works but, it checks whether a descendant has been added to the players character; if the object added is in the check, the player will be teleported back to the game (preventing them from flying).

Sulphur:AntiFly(AuthenticationKey)

Checking if a player has changed their JumpPower
This is really similar to how the Walkspeed check is done, so I won’t go into how it works.

Sulphur:JumpPowerCheck(AuthKey)

Checking if a player has added a humanoid
Players can remove their humanoids and insert another humanoid preventing them from dying, to prevent this, we can check if a humanoid has been added to the players character, if so, the player will be teleported back into the game.

Sulphur:HumanoidModificationCheck(AuthenticationKey)

Checking if a player has changed their HipHeight
When a player changes their HipHeight, it’ll appear as if they’re floating and may give them some advantage in some games, to prevent this, you can check if a players HipHeight changes, if it does, we will change it back

Sulphur:AntiHipHeight(AuthenticationKey)

Preventing players from teleporting in the Y axis
The reason I didn’t want to include this in the anti teleportation function mentioned before is because players can jump from high altitudes and trigger false positives, so I created a separate check for the Y axis, this checks if a players Y position has increased by a large amount but it doesn’t check if a players Y position has decreased by a large amount (I’m not certain whether I will update this in the future). This only works with a constant jump power of 50 currently since there are many factors that affect how high up a player can jump such as the gravity of the Workspace, etc. I don’t recommend using this if you’re going to not use the default values of JumpPower and Gravity.

  • First, the players position is saved to a local variable, then there is a wait of 0.1 second and then the players Y position is saved to a local variable
  • After the values have been saved, they are ready to be compared, if the second position (position saved after the wait) - 10 is greater than the original position, the player is teleported back to their position before the wait. There are no strikes since there is a higher chance of false positives.

Sulphur:AntiTeleportationY(AuthenticationKey)

Changing a players speed without triggering any checks
While I was making this, I had trouble changing the players speed without triggering any checks; I didn’t want to use global variables since they could be changed by an exploiter, instead, I made it so the module would change the players speed for you without triggering any checks.

  • The players speed is constantly checked for any changes and then compared against a local variable, when you change the players speed using the function mentioned before, a Boolean which we will call Bool1 is set to true, then the script waits until a Boolean which indicates whether the anti teleportation loop has ended or is currently running, we will call this Boolean Bool2, there is a wait() loop in the anti teleportation loop which is triggered when the Bool1 is true, once Bool2 is true, the characters speed is changed then Bool1 is set to false and the anti teleportation loop continues since Bool1 is no longer true.

Sulphur:ChangeCurrentAllowedSpeed(AuthenticationKey, Speed)
Note: The argument “Speed” is an integer

Note

This is intended for games without an anticheat against simple exploits, if you can make your own anticheat, I recommend that you do so instead of using this module

Test out some features of the module:
-https://www.roblox.com/games/4561870834/Sulphur-Test
Example Place (if you’re not sure how to use the module yet):
-Sulphur Example - Roblox

If you’re wondering why players aren’t kicked or banned, it’s because I’m currently aware that Roblox doesn’t like it when you kick/ban players but I do plan on implementing a ban list in the future.

If you find any bugs, vulnerabilities or have any suggestions, feel free to contact me on the Devforum

24 Likes

Client-sided anti-cheats are rarely a good idea, if ever. They’re possibly okay in use-cases such as rogue lineage where they’re updated frequently however, they’re always entirely bypassable with ease. And a module like this is no different.

Stuff like anti-teleport should never be client-side, as anti-teleport, anti-noclip and some others can be made entirely on the server. I hope your script does those on the server rather than the client - else that is really pointless.

How does this script protect itself from metatable attacks, and disconnectall() which prevents all of its :Changed namecalls from ever being called? Not to mention the fact users can simply use the genv / senv to simply make the script error.

I’m sure you may have solutions to the above, but there are a thousand more edge-cases. Client-sided cheats are not time-effective. You will spend about quadruple the time developing it than the malicious client takes to bypass it with a few simple custom-functions.

In conclusion just never settle for client-sided solutions and definitely don’t in use-cases like teleport; something that can be done entirely by the server. Client-sided anti-cheat wont ever beat good game design and server-side solutions. It becomes a waste of development time.

18 Likes

Hi, I appreciate the feedback and advice. I do plan on creating a server sided version of the exploit really soon as it has become apparent to me that client sided exploits aren’t as effective as I thought they would be even with checks in place to prevent exploiters from removing these checks. Most exploiters won’t be able to bypass these checks since they usually copy scripts. Could you elaborate(if you don’t mind) on how some of the vulnerabilities described above may work(such as metatable attacks and how an exploiter can disconnctall()). Sulphur was initially created to reduce strain on the server and do checks on the client hence it’s a client sided anticheat (currently).

4 Likes

Please note, this is merely one of many vulnerabilities your script (like all other client-sided scripts) has.

But for example, you say you stop it from being disabled - and so on. Well an malicious user has access to functions such as diconnectall( instance ) This will break all connections on the instance given, so if any scripts are listening for that connection; well, now they’re not. So next time the changed signal would’ve been fired, it wont be.

And the main core issue I see with clientsided anti-cheats:
Other than simply kicking, or locally punishing a user - what are they good for? Because its impossible to relay information over to the server in any reliable way. Exploiters can simply use metatables and hookfunc to stop whatever remote you’re using to contact the server.

So against any mediocre exploiter, you wont be able to:

  • Ban them
  • Put them in a banland
  • Punish them outside of the singular session they’re in
  • Generally communicate anything to the server at all

Now sure like I said, some games DO this, like Rogue Lineage with their bans and client-side detection, and Phantom Forces. However, they both fail. These games have not prevented scripts for their games, they’ve just privatized them and indirectly make scripts stronger.

Games like Phantom are the reason most ESP’s now use DrawAPI which is impossible to detect.

Stronger Server-side anti-cheat = Stronger game
Stronger Client-side anti-cheat = Stronger Exploiters.

3 Likes

Okay, thank you for explaining, I’ve decided to begin transitioning my anti exploit so most of it is server sided (such as speed checks and anti teleportation) but some checks won’t be server sided since the server can’t “see” everything the client is doing such as inserting “legacy body movers” which clients can use to bypass speed checks done on the server or inserting hopper bins (btools).

Well I’m glad you actually took the feedback and want to improve what you’ve made. It’s a good trait to have, as now your script will be tons better for it.

Detecting btools via use of hopperbins doesn’t really work. Back when I was a part of that side of the community, I made a public script that just detects a mouse click and moves Mouse.Target to CoreGui.

If you ever have any questions you can ask me on my discord Ava.gg#7103
I was a part of rerversing games and making malicious scripts for about 5~6 years. So I know pretty much the majority of what they can do. - Which isn’t secrative knowledge. The rule of thumb is - the client is entirely controlled by the user. Not you.

4 Likes

This looks like an interesting module, however, it has very poor security.

An ‘authentication key’ can be easily bypassed or stolen by exploiters. EVERYTHING can be taken by a malicious client and there is no way to detect this, at all.

Always assume that the client has been compromised!!


That being said, basic client anti-exploits are still cool (most of the people exploiting your game don’t know what they’re doing, you will catch a lot of people) but you should focus on server-sided defences.

2 Likes

Hi, I appreciate the feedback; I’m currently aware that authentication keys aren’t in fact the best way of securing modules and as a result I’m working on a server sided anti exploit which should be more secure but I won’t be able to implement checks such as humanoid modification checks since they’re local.

Yes, there are ways to detect this; although most methods are pretty complicated, it has been achieved by multiple people. A lot of client-sided exploits that most people don’t think you can detect, you can. Anti-exploits are pretty much a cat and mouse game with detecting vulnerabilities in exploits, patching them, waiting for the exploiters to patch the vulnerability / bypass the detection method, and repeat the process. Yeah server sided anti-exploits are a lot easier to make so you can call it more efficient but if you have a lot of time on your hands and you’re willing to commit yourself then you can actually accomplish a lot of stuff regarding protecting your game from exploiters through client-sided anti-exploits.

3 Likes

Yes, but it is a waste of your time. You should focus on server-based exploit detection or more subtle ways.

Can you explain your thought process behind your opinion? I feel like you kinda just ignored everything I said…

1 Like

Yes lets spend tons of time trying to implement update after update to ban the few who don’t really know what they’re doing; meanwhile Wally and others will make $$$ off of selling scripts for your game that you’ll never dream of detecting; and if you do it’ll be bypass within the same day.

Anyone with a brain is going to monitor the previous update of a game and then when it changes, trigger their script to stop until whomever runs it can make sure no new detection have been placed it.

There are already LuaU decompilers now, so if you’re not obfuscating your code then its entirely naked to the exploiter. They can just spoof your checks using upvalues

I respect your opinion on doing it, and I don’t deny that it can work. In cases like Rogue Lineage they ban plenty of people and since its a paid game; its very hard to justify buying it again to continue exploiting. So I’m not entirely rejecting what you say. I just think its very rare that its executed well. And halfmeasures are always pointless

1 Like

You know there are many ways to defeat users like “Wally” not that hard ~
confidential information
most of the time it’s not “well executed” because 98% of the people who try doing what metry said have NO experience at all and don’t know what they’re doing.
that’s my opinion tho!

1 Like

You’d be surprised how easily some games could detect wally’s scripts.
Implementing additional security is never wrong, as long as you know what you’re doing (finish your server checks before adding client ones, make sure they don’t lag the game or have false positives, and so on).

From my knowledge there isn’t anybody who does that automatically, as games that use TeleportService usually have a lot of places. Saving and comparing the last update timestamp of each wouldn’t be very practical.

It is not very rare. Strucid, Sound Space, Rogue Lineage, they all have client sided checks with instant auto bans.
In Strucid’s case, having just client sided checks allowed them to ban at least hundreds of exploiters with very few false positives. I don’t know about the rest but the case is probably similar.

3 Likes

I understand your points - and I agree with most but I don’t really think games like Strucid were ‘effective’ - the game is free which means once one alt was banned, the user was just instantly creating a new account and doing the exact same thing again.

From my knowledge there isn’t anybody who does that automatically, as games that use TeleportService usually have a lot of places. Saving and comparing the last update timestamp of each wouldn’t be very practical.

I disagree - I myself when making scripts would always do this. And so do many others who make premium scripts. Sure, it isn’t very practical to do so - but exploit scripts are not the same as production game scripts, extra time can be spent to go to a few extra places and simply get versions. Don’t forget there are various ways to do it automatically when your user-base is large.