Last active
November 22, 2025 22:49
-
-
Save daily3014/041e37ce57a25c9db73a0025e63306e0 to your computer and use it in GitHub Desktop.
RandomService: Bruteforcing the RNG state
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local Seed = 568182 | |
| local RNGState = Random.new(Seed) | |
| -- The seed is unknown to the exploiter at this point | |
| local function Advance(Seed) | |
| math.randomseed(Seed or math.random(1, 1000)) | |
| for i = 1, math.random(1, 3) do | |
| if math.random() > 0.5 then | |
| continue | |
| end | |
| RNGState:NextInteger(math.random(1, 50), math.random(51, 100)) | |
| end | |
| math.random() -- Calling math.random to match RandomService's implementation | |
| end | |
| for i = 1, 50 do | |
| Advance() -- 50 advances | |
| end | |
| -- Exploiter bruteforces the seed by getting two consecutive randomly generated numbers in the 0-2.5 second timeframe | |
| local N1, N2 = RNGState:NextNumber(), RNGState:NextNumber() | |
| local MaxAdvancements = 1000 -- To stop it from running forever | |
| local Found = false | |
| -- In this case, the exploiter doesn't know about the server's uptime, forcing them to bruteforce an unknown amount of advancements | |
| local function Bruteforce(StartingSeed) | |
| local RandomState, NextSeed = Random.new(Seed) | |
| local Advancements = 1 | |
| local function AdvanceState(Start, State) | |
| math.randomseed(if Start then StartingSeed else NextSeed) | |
| for i = 1, math.random(1, 3) do | |
| if math.random() > 0.5 then | |
| continue | |
| end | |
| (State or RandomState):NextInteger(math.random(1, 50), math.random(51, 100)) | |
| end | |
| math.random() | |
| NextSeed = math.random(1, 1000) | |
| end | |
| AdvanceState(true) | |
| while true do | |
| if Advancements > MaxAdvancements or Found then | |
| break | |
| end | |
| local TryState = Random.new(Seed) | |
| local NextSeedCopy = NextSeed | |
| AdvanceState(true, TryState) | |
| for i = 1, Advancements - 1 do | |
| AdvanceState(false, TryState) | |
| end | |
| NextSeed = NextSeedCopy | |
| local RN1, RN2 = TryState:NextNumber(), TryState:NextNumber() | |
| if RN1 == N1 and RN2 == N2 then | |
| Found = true | |
| warn("Found the new state! Advancements:", Advancements, "Starting seed:", StartingSeed) | |
| warn("Next 10 numbers:") | |
| for i = 1, 10 do | |
| warn(i, TryState:NextNumber()) | |
| end | |
| break | |
| end | |
| AdvanceState() | |
| Advancements += 1 | |
| task.wait() | |
| end | |
| end | |
| for i = 1, 1000 do | |
| task.spawn(Bruteforce, i) -- Try all 1000 starting seeds | |
| end | |
| print("Next 10 numbers of server state:") | |
| for i = 1, 10 do | |
| print(i, RNGState:NextNumber()) | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment