Turb0
Bits, bytes, and bad ideas

Using Discord Desktop for Backdoor Persistence

Wed, Mar 25, 2020 6:32:23 PM

Discord is a cool chat platform with a super smooth interface and a mobile app that runs fairly well, but in my experience the desktop application is usually a bit annoying. By default it will automatically launch on startup, likes to spam you with notifications, and will snitch what games you are playing on Steam. It is also an Electron app, so it eats memory and CPU like running another instance of slightly slimmed down chrome. Millions of people have Discord installed on their systems with it firing up at startup, so I thought it would be a fun application to try to use as a covert persistent backdoor. Here the tool's source and prebuilt binary can be found.

discord binary

Discord's installer installs the electron app to %UserProfile%\AppData\Local\Discord which is executed on login of the user automatically. Hypothetically, to use it as a persistent backdoor we could replace the Discord.exe binary and wrap the launch of it within our own custom binary, or patch it to execute our own malicious code, neither of which are very optimal. Fortunately, the way Electron apps ship, they include an asar archive that includes some of the JavaScript run unsandboxed locally on the v8 JavaScript engine to orchestrate the local code execution of the Electron app. These asar archives can be extracted, the JavaScript entrypoint can be modified to include a line to call our custom JavaScript file we dropped in, and the asar can be repacked and rewritten to its location in AppData.

discord asar

Fortunately, in Discord's case, it isn't even needed to go to the trouble of unpacking the asar, as Discord stores its own custom node modules it loads launch for things like voice, spellcheck, and the overlay in %UserProfile%\AppData\Roaming\[Discord version number]\modules. Each module folder contains an index.js entrypoint that is run every time Discord is launched. If we want to establish persistence on a system, we can just drop another script in there, call it something casual like update.js and prepend require('./update') to the index.js file of any module. The tool I wrote patches the discord_utils modules to load the update.js script that it drops. The tool takes a path to a JavaScript file hosted on the web, and hardcodes its location into the update.js script. The update.js script then grabs the script at that URL and executes it as Discord is launching. This allows for an attacker to change the script an infected machine runs, just by updating the file being hosted on the web that their Discord now attempts to download and execute on every launch. Should update.js not be able to download the script at the hardcoded URL, it will look for a cached version of the script from the last successful run, and run that if it exists.

victim module

With the module patched, we can now control the file that gets stealthy executed every time Discord is launched. We can include a script that just executes shell commands, or whatever we want to do within the context of the user on the system. From the user's point of view, Discord might be a bit slower to launch, but for the most part, the persistence mechanism would be very stealthy and likely annoying for a defender to track down. If Discord wants to make their application less useful as a backdoor, the files it executes should not be writable by the unprivileged user accounts executing them. This would require it to prompt for escalation when it install and updates, but it would make the application less of a target for establishing persistence.

If you would like to try out the tool, or look at the code, it is linked above at the top of this post.