Malware
Info Stealer Abusing Codespaces Puts Discord Users at Risk
In this entry, we detail our research findings on how an info stealer is able to achieve persistence on a victim’s machine by modifying the victim’s Discord client.
Discord's transition into mainstream appeal has been a double-edged sword: The surge of new users that flocked to the platform during the pandemic brought with it a growing cybercriminal presence that has raised concerns over security and privacy risks. With 150 million monthly active users worldwide, its growth has made Discord an attractive target for malicious actors looking to use its servers as a hub of illegal activity or an untapped hunting ground rife with potential victims.
In our previous entry, we examined a Rust-based info stealer targeting Windows platforms that has anti-analysis and anti-debug procedures, and uses the file-sharing and storage platform Gofile and a Codespace-based webhook to exfiltrate Chromium-based browser credentials, credit cards, cryptocurrency wallets, and Steam and Discord tokens. In this blog post, we detail our findings on how this info stealer is able to achieve persistence on a victim’s machine by modifying the victim’s Discord client. The following analysis and screenshots are based on a malware sample with the SHA256 hash c92a7425959121ff49970c53b78e714b9e450e4b214ac85deb878d0bedf82a70.
Developer environments hosted in the cloud like GitHub Codespace have given developers the opportunity to work from any location, but for all the freedom and flexibility they offer, they aren’t immune to attackers abusing these services. In July 2022, the source code for an info stealer malware written in Rust was leaked on underground forums. With any user being able to create developer environments for free, this increases the chances of attackers using the platform for performing malware development, making cloud security an important consideration for those who rely on such platforms.
Malware Analysis
The info stealer achieves persistent credential access by patching the installed Discord application. If the number of command-line arguments the info stealer is executed with are greater than two (Figure 1), then the function ‘malware::discord::inject’ is skipped. This is done to prevent the reinfection of Discord application on the victim’s machine. The values and number of parameters, provided that they are greater than two, do not matter.
![Figure 1. Discord infection routine based on number of command-line arguments](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure1.png)
If the number of command-line arguments are less than two, the stealer modifies the Atom Shell Archive Format (ASAR) file for the ‘discord_desktop_core’ node module at:
%localappdata%\\Discord\app-<version>\modules\discord_desktop_core-1\discord_desktop_core\core.asar
ASAR is an archive file format that is used by the Electron framework to package and bundle an application's resources – including JavaScript, HTML, and CSS – into a single file for distribution. The Discord application for Windows, Linux, and MacOS is developed using the Electron framework. In this case, the package ‘discord_desktop_core’ is backdoored or infected by the modification of ‘index.js’, as discussed below in Figures 2 and 3.
![Figure 2. ‘package.json’ definition pointing to the entry point of the module](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure2.png)
![Figure 3. Modified ‘index.js’ in the package ‘discord_desktop_core’ used by the Discord application](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure3.png)
A JavaScript module named ‘cdn’ is being used in the ‘startup’ function on line 24 in the above image. When compared with a legitimate installation of Discord, this JS file was the outlier. Upon investigating ‘cdn.js’, we came across two arrays of monitored URLs (Figure 4).
![Figure 4. List of URLs which are monitored by the infected module for capturing credentials](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure4.png)
This is followed by declaration of two constants, ‘json_file’ and ‘executable’ (Figure 5). They contain paths to a JSON file and a path to the info stealer itself with a few command-line parameters. As mentioned earlier, two or more command-line parameters result in skipping the function responsible for infecting the Discord desktop app.
![Figure 5. Constants used for data accumulation (‘json_file’) and exfiltration (‘executable’)](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure5.png)
Upon initial execution, the info stealer creates a clone of itself at ‘%AppData%\defender.exe’.
![Figure 6. JavaScript functions that monitor specific URLs when accessed from the Discord application](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure6.png)
In the Electron framework, ‘BrowserWindow’ is a JavaScript class which creates or controls web browser windows (Figure 6). The method ‘getAllWindows()’ returns an array of all opened browser windows. In such a scenario, the first window is fetched. The ‘webContents’ attribute is responsible for rendering and controlling a web page and ‘executeJavaScript’ executes the first argument supplied in the context of the web page, followed by the flag set to ‘true’ which avoids requiring any gesture from the user.
This function is responsible for forcing the user to log out and then log in using their email address and password. The code defined in the ‘setInterval’ method creates an iframe and clears the Discord token stored in ‘localStorage.token’ by setting it to an empty string. Chromium engine provides persistent web storage called ‘localStorage’ for Electron-based apps, and this is generally used to store user data – or in this case, a Discord token. Then, using the ‘setTimeout’ method, the login page reloads after 2.5 seconds, forcing the user to log back in. This functionality seems to be likely inspired by this Gist, shown in Figure 7.
![Figure 7. Forcing the user to logout and login using email address and password](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure7.png)
![Figure 8. Incomplete ‘findToken’ function declared in a web request event](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure8.png)
The event ‘session.defaultSession.webRequest.onBeforeRequest’ allows interception and modification of network requests before they are sent from the defaultSession of the Electron application. In this case, the URL ‘wss://remote-auth-gateway.discord.gg/’ receives a callback to cancel the request. This prevents the user from logging into Discord using their QR code to force them to use their email address and password to login instead (Figure 9), which is later captured and exfiltrated by the info stealer.
![Figure 9. The QR code never loads once the Discord App is infected by the info stealer](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure9.png)
![Figure 10. Missing response for connections to ‘wss://remote-auth-gateway.discord.gg/?v=2’](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure10.png)
![Figure 11. Failed WebSocket connections in console logs of Discord](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure11.png)
Similar to the above event, ‘session.defaultSession.webRequest.onCompleted’ is an event that allows the interception of a network request after it has been completed by the defaultSession of the Electron application.
![Figure 12. Fetching and parsing uploaded JSON data for requests with successful response codes (200, 202)](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure12.png)
As illustrated in Figure 12, the info stealer monitors the URLs mentioned in the ‘filter’ attribute from the ‘config’ object, with response status codes being either 200 (OK) or 202 (Accepted). It parses the JSON data and stores them in another variable named ‘data’. Additionally, it fetches the Discord token by calling Discord client’s function (Figure 13) - ‘getToken’ (Figure 14).
![Figure 13. Calling arbitrary function from Discord client](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure13.png)
Finally, the function that is executed in the context of the first BrowserWindow is as follows (Figure 14):
![Figure 14. Executing ‘discordFunction’ called getToken in dev-tools for Discord to fetch the token](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure14.png)
Artefacts Exfiltrated
As a result, the patched Discord installation abuses the session events to fetch and exfiltrate the following artefacts:
1. Discord token
![Figure 15. JavaScript code which is supposed to exfiltrate the Discord token](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure15.png)
Based on the code, if the file declared in the constant ‘json_file’ doesn’t exist and the Discord token has been populated, the token is saved in the file at ‘%AppData%\call.json’. This is followed by execution of the following command-line:
defender.exe deltastealer666 40929288_CLIENT_ID 309393883ndnjdje 3747dnjdj 28187dhjjsjs 298sjsj
This results in calling the info stealer again, without the discord infection routine.
2. Discord login credentials (email address and password)
When a user logs into their Discord account, the credentials are sent in a POST request, as shown in Figure 16.
![Figure 16. Network traffic when a user logs in using their email address and password in Discord](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure16.png)
The complete URL ‘https://discord.com/api/v9/auth/login’ matches the filter specified in Figure 4 at line 12. Hence, the JSON body of the request is parsed, and the password is fetched and written to the file ‘%AppData%\call.json’. This is followed by execution of exfiltration routine using the ‘exec’ call.
![Figure 17. JavaScript code which monitors successful Discord logins made with a user’s email address and password](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure17.png)
![Figure 18. Discord password exfiltrated to GitHub Codespace webhook](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure18.png)
In the ‘gofile_link’ header shown in Figure 18, the Gofile URL pointing to the exfiltrated ‘diagnostics.zip’ from the stealer is also exfiltrated by the dropped copy of the info stealer (‘defender.exe’).
3. Discord login credentials when the user updates their email or password
Similarly, whenever a user updates their email address or their password, the updated information is sent to a Codespace webhook (Figure 20).
![Figure 19. JavaScript code which monitors successful Discord email address or password changes](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure19.png)
![Figure 20. Updated Discord password exfiltrated to GitHub Codespace webhook](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure20.png)
While checking the traffic generated when a user changes their email address, the updated data is sent to the GitHub Codespace webhook. However, it seems that the malware author should have used ‘data.email’ instead of ‘data.login’ on line 109 in Figure 19 to send the updated email to the webhook. Since ‘data.login’ doesn’t exist, the email field is missing in the request, shown in Figure 21.
![Figure 21. Missing email information when updated email is exfiltrated to GitHub Codespace webhook](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure21.png)
4. Credit card details and PayPal status
![Figure 22. Exfiltration of credit card information and PayPal status](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure22.png)
Similarities with PirateStealer
Looking through GitHub for similar JavaScript code that has been used by this info stealer, we come across what seems likely to be a more advanced version with added capabilities called PirateStealer (Figures 23):
![Figure 23. PirateStealer code similar to that of the current sample](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure23.png)
The API calls to a credit card payments processor containing credit card detailsare exfiltrated as well. It also cheques whether PayPal information has been added or not, likely to ascertain whether the user has acquired Discord Nitro, their paid subscription service. If a user wants to avail of a paid subscription, they have to enter their mode of payment, such as whether to use a credit card, PayPal, or Venmo account.
Among the list of URLs being monitored, the following URL ends with ‘paypal_accounts’:
Braintree is a payment processing company owned by PayPal. In the abovementioned URL, ‘49pp2rp4phym7387’ is, according to PayPal documentation, a unique merchant ID that Discord uses to receive payments from its users. To confirm, we attempted to add credit card details in an infected Discord application and observed initial requests (Figure 25) made to the following URL:
https://client-analytics.braintreegateway.com/49pp2rp4phym7387
![Figure 24. Initial requests containing Discord’s PayPal merchant ID (49pp2rp4phym7387)](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure24.png)
If a valid credit card is added by a user, then the status of the presence of the victim’s PayPal information is sent to the attacker-controlled Codespace. This code informs the attacker if the user has entered credit card information into their Discord profile. It’s also likely that the malware is still in development by the author, as we have observed instances of missing function definitions and inaccurate code.
The abovementioned information is exfiltrated to an exposed port on GitHub Codespace, which acts like a webhook. The previously mentioned routines that we analysed are observed only if Discord is installed on the victim machine, and invoking them requires user interaction (the user must login to Discord using their email address and password, after the application has been infected by the info stealer).
The overall flow of the info stealer can be summarised in Figure 25:
![Figure 25. Overall view of the info stealer’s operation and capabilities](/content/dam/trendmicro/global/en/research/23/e/infostealer-abusing-discord/Discord-infoStealer-Figure25.png)
Conclusion and Recommendations
Discord has grown beyond its original userbase of gamers, in large part bolstered by the Covid-19 pandemic as more people turned to the platform's servers as a means of socialisation. As Discord has adapted to become accessible to a broader audience, it's increasingly attracted its share of security incidents, both as risk (as evidenced in the leak of confidential Pentagon documents), and as a victim (see a data breach earlier this year). Our findings point to cybercriminals developing more advanced tools specifically targeting its users, which could be indicative of a mounting number of sophisticated attacks on Discord in the future.
Abusing developer-focused platforms like GitHub gives attackers an additional advantage, as these platforms are generally considered to be trusted by traditional security solutions. We have observed platform abuse in various incidents, including the recent 3CX supply chain attack wherein an attacker-controlled GitHub repository had files containing encrypted command and control server information.
Using Codespace, one can expose a port publicly, which means that any user on the internet can access the exposed port on the Codespace virtual machine without any authentication whatsoever. An attacker could use this URL to exfiltrate data from secured environments, as the domain generated is randomised and has no malicious history on threat intelligence platforms.
Developer-focused features like dev-containers and services like Codespace ease the pain points for building software, such as setting up the environment and provisioning resources. However, these features also enable attackers to build, test, and distribute malicious content, just like any developer. With malware authors moving to cloud-based developer environments, picking specific bits and pieces of capabilities from existing info stealers, it enables them to rapidly build and test their malware samples.
As more of such tools, platforms, and services are made available to the public, we expect to see a rise in cyber risks associated with their abuse. To stay ahead of the attackers, organisations and cybersecurity teams need to have visibility over the various activities happening in their environments through the following recommended practises:
- Organisations and their cybersecurity teams need to be aware of the various possible ways in which environments like Codespaces can be abused, because the benefits of using these extend even to the attackers. For example, outbound DNS logs from the deployed proxies should be analysed for malicious signatures or anomalies, and anti-malware triggers.
- While rolling out features that lower the accessibility to cloud-based environments, cloud providers also need to threat model possible adversarial scenarios of abuse and risks, as we observed in our previous blog entry about abusing Codespaces as open directories.
Indicators of Compromise (IOCs)
Download the full list of indicators here.