Anti-Exploit for MaxSimulationRadius/SimulationRadius exploit ("TPing" unanchored parts to player)

So i recently had an exploit be used at my game (ARC-74) that “teleported” some of my SCPs/Unanchored parts to the player. I spent about 1 hour fixing, including a bypass for “nokick” exploit.

How the exploit works:

Essentially what the exploit does is it gets all unanchored parts in the game and then “attaches” them to the character via a bodyposition, and exploits MSR/SR to get all the unanchored parts on the map. It then “pulls” them towards the player, thus causing chaos.

When banning the person, because my map is “in doors” the SCPs are not able to return to the correct positions, as they would get stuck in the walls/bounce off them. This led to this happening: See Image

How the anti-exploit script works:

My solution, was to whenever it detected this bodyposition being made it would fire a remote event that reported this to a webhook & kicked them, then added them to a ban datastore.

This bypassed the anti-kick by making the kick happen server-sided instead of client, and of course will most likely permanently patch this due to the fact that the anti-kick script cannot just stop all remotes on the client being fired, as that would break most games.

Now you don’t need to report it, however I was purely using the webhook to collect data on exploiters and also in case they attempted to appeal to me.

There is a read me in the folder once you insert it on how to set everything up.

Hopefully this helps people protect their games better from this type of exploit.

Edit: Yes this is not the most efficient way to do it, but it works. This also contains a method for bypassing exploiters “anti-kick” exploit.

Script is located here

10 Likes

Thank you very much, and really good contribution

3 Likes

This honestly does not look as a permanent fix since exploiters could easily delete the LocalScript that fires the ban event if they find out that it is a honeypot. It should check the added childs from the server by connecting this function to every new character in-game so it cant be deleted or modified by an exploiter.

exploiters can delete scripts too

2 Likes

Not true, exploiters do not have the authority to manipulate and or delete anything owned by the server including scripts.

(Unless you were referring to local scripts.)

3 Likes

This solution is very bad because exploiters can literally just stop the remote from being fired and there is a much easier way to solve it.

The reason why your Unachored parts are able to be controlled by certain players is probably that you didn’t set the network ownership of the parts to the server.

To do so all the have to do is use the SetNetworkOwner method and just set all NPC’s parts to the server

4 Likes

Even if they delete the local script, you can hide the function in another script or name the script to something that looks like its required for the game to run.

1 Like

Was just to help out, it’ll work on lazy exploiters (which there is a lot of).

I’ll use that.

1 Like

This seems to rely on the fact that exploiters will use BodyPosition while doing this?
Why would anyone use BodyPosition when teleporting items around?
As long as someone sets Part’s CFrame, your “patch” will not work.

Also, someone already said this, but setting network ownership to nil makes it so part’s network ownership is always on server as opposed to regular behavior which automatically assigns based on distance etc.

1 Like
addcmd('tpunanchored',{'tpua'},function(args, speaker)
if sethidden then
    local players = getPlayer(args[1], speaker)
    for i,v in pairs(players) do
        local Forces = {}
        for _,part in pairs(workspace:GetDescendants()) do
            if Players[v].Character:FindFirstChild('Head') and part:IsA("BasePart" or "UnionOperation" or "Model") and part.Anchored == false and not part:IsDescendantOf(speaker.Character) and part.Name == "Torso" == false and part.Name == "Head" == false and part.Name == "Right Arm" == false and part.Name == "Left Arm" == false and part.Name == "Right Leg" == false and part.Name == "Left Leg" == false and part.Name == "HumanoidRootPart" == false then
                for i,c in pairs(part:GetChildren()) do
                    if c:IsA("BodyPosition") or c:IsA("BodyGyro") then
                        c:Destroy()
                    end
                end
                local ForceInstance = Instance.new("BodyPosition")
                ForceInstance.Parent = part
                ForceInstance.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
                table.insert(Forces, ForceInstance)
                if not table.find(frozenParts,part) then
                    table.insert(frozenParts,part)
                end
            end
        end
        if not simRadius then
            execCmd('simulationradius')
        end
        for i,c in pairs(Forces) do
            c.Position = Players[v].Character.Head.Position
        end
    end
else
    notify('Incompatible Exploit','Your exploit does not support this command (missing sethiddenproperty)')
end end)

That’s the exploit. It uses bodypositions to pull unachored parts towards the player.

The script still contains a bypass for “antikick” scripts + a “honeypot” for exploiters.

If you wish i can rename the thread.

iirc it has to do with a vulnerability of how network ownership is set for unanchored parts.

Teleporting the parts works as well is what I’m saying.
And if someone decides to teleport it, this won’t work one bit.

It’s the reason why you can teleport your character around as well – you have network ownership of it.

This is not a good way to patch this method. You never trust the client. An exploiter can just stop the remoteevent from firing. The best way to fix this is to weld an unanchored part 10k studs above the map, then doing a check every 10 seconds or so to check if the network owner has changed, if it’s a player, kick them.

I remember having a problem with this exploit myself.

I solved it by running a check on the server every second or so, which creates a sum total of all player network owned objects. It then creates an individual tally for each player within a lookup table representing how many parts each player had network ownership over. If any one player network owned an overwhelming majority of the parts (in my case it was something like 90%), I kicked them.

However, I am aware that this would not work for all types of games, as having one player control a majority of physically simulated objects might be intended in some cases.

It worked for my use case though. Don’t rely on client - side anti cheats as the client can literally manipulate every function / security check which you employ, no matter how much you try to put them off messing with your client code.