you’re a genius. Thank you!
Oh my, can’t believe I didn’t know about GetDescendants until this! Thank you for sharing. Using this information and a few hacky methods I was able to create a plugin for the automated detection and removal of this infection (as well as any script hiding in a protected locations or known infections located in the game.) The plugin will also allow you to choose to “Store” the infections in a new folder in ServerStorage that it will name “Infections” so you can view the scripts it detected as infections if you’d like.
https://www.roblox.com/library/2670956620/Hidden-Infection-Script-Detector for anyone who wants to use it.
(This plugin uses 1 require so I can easily update the known infection source excerpt string table that the plugin uses to scan scripts and check if they are infection scripts or not. This module is located here: https://www.roblox.com/library/2682779959/Hidden-Script-Scanner-Known-Infections-Table)
Oh jeez. I may or may not have completely forgotten about Insert, because, well, that’s not something you think about… Ever. Shout out to Roblox for unintentionally leaving us the tools we need to get the job done.
My initial worry was that now that we’ve called attention to this method it could be used maliciously by doing something like inserting the CoreGui into the workspace, but Insert is actually restricted already so it works in our favor! Please no patch Roblox! We mean well!
Incidentally, if you’re worried about a property being named ‘PropertyThatDoesNotExistPlz’ existing at any point in the future (I cannot possibly imagine you are) you can get the Classname of an Instance by checking the error that shows up when you call it with no arguments. Apparently calling an Instance is a thing because it actually casts a proper and unique error?
The fact that the infected plugin was disguised as a simple class converter is really worrying. I could have easily fallen for that.
I’m really not liking having to fear installing plugins (or even updating my current ones) because they might have backdoors I don’t know about.
Also a quick note, you should check if you’re in studio to run this because it currently sends an error whenever you’re on a client.
I already built in a Selection service fallback for just in case the InsertService method gets patched for this reason. Also in reply to your next post I’m pushing an update now for this, thanks for letting me know!
It would be nice if you could hook this up to #learning-resources:community-tutorials-resources for public exposure, since infected assets affect many developers, evidently.
A word of caution though: you should not be using a require module, even if the source code is public, because such support is being discontinued in no more than 3 months. Have the module placed internally in the plugin and instead prompt the user if the plugin is outdated and to go update it. When you update a plugin, people will be able to bring their installation up to speed and Studio will automatically refresh the toolbar to allow the updated plugin to commence its functions.
I’ll probably do that. (Update: Done, link to this post is here.)
As for the caution; That’s likely why I built in support for require failure to fallback to a local version of the table. Also to my knowledge the support is only removed for closed-source modules. Meaning as long as I leave it public it should be fine. (Which I intended to do anyways.)
We are investigating what we can do to resolve this issue.
A temporary patch would be to not allow the engine to execute scripts inside of “Backpack” instances that aren’t parented to a player. (This is an engine bug that the exploit creator is abusing to make the scripts execute in odd/hidden locations.)
Note: I’m unsure if “PlayerGui” instances will have the same effect but if “Backpack” instances do then I assume it will too.
There are a couple things we are looking at:
- Only executing scripts inside Backpacks/PlayerGuis if those objects are parented to a Player
- Preventing plugins and other scripts from parenting objects to CSGDictionaryService and other locked/hidden services
Separately we are going to add an optional setting to see everything in the DataModel, so power users will be able to see everything that goes on.
Is there any reason that any of these services are ‘super-RobloxLocked’ (as in, inaccessible to plugins)? None of them have any special API attached to them (and even if they did, they would have a separate security flag on them) and it seems to just be creating this sort of vulnerability without any gain from an outside perspective.
We did not intend for these services to be accessible to developers, e.g. CSGDictionaryService is for holding CSG data. It is possible that we will someday remove CSGDictionaryService so we did not want developers to start storing objects within it.