Dissecting SSLoad Malware: A Comprehensive Technical Analysis

Written by and

    Share article
    FacebookTwitterLinkedInRedditCopy Link

    Top Blogs

    SSLoad is a stealthy malware that is used to infiltrate systems through phishing emails, gather reconnaissance and transmit it back to its operators while delivering various payloads. Recently, Unit42 highlighted an active campaign leveraging SSLoad in their attack arsenal. One attack vector involves a decoy Word document that delivers an SSLoad DLL, which eventually executes Cobalt Strike. The other attack utilizes a phishing email that leads to a fake Azure page, downloading a JavaScript script that ultimately downloads an MSI installer, which loads the SSLoad payload.

    SSLoad is a new malware that has been targeting victims since April 2024. A recent report by Secournix highlighted the latest SSLoad activity, and we are already seeing additional delivery variants. The diverse delivery methods uncovered by our technical analysis suggest its use in Malware-as-a-Service (MaaS) operations, highlighting its versatile nature.

    This blog presents a detailed technical analysis of the loaders and payloads used in these campaigns. We examined the payloads, techniques, and functionality at each stage of the malware execution chain. Our analysis also includes conclusions drawn from additional IOCs identified through threat-hunting and pivoting efforts. We aim to shed more light on the technical functionality of this rapidly evolving malware.

    MSI Installer 

    We began our analysis by dissecting the MSI file identified in one of the campaigns. This installer initiates a delivery chain comprising several loaders, ultimately deploying the final payload.

    SHA256: 90f1511223698f33a086337a6875db3b5d6fbcce06f3195cdd6a8efa90091750

    Using msitools, we can determine what actions the installer will execute:

    ❯ msiinfo export 90f1511223698f33a086337a6875db3b5d6fbcce06f3195cdd6a8efa90091750.sample CustomAction
    [...]
    SET_APPDIR 307 APPDIR [AppDataFolder][Manufacturer]\[ProductName]
    LaunchFile 1026 viewer.exe C:\Windows\System32\regsvr32.exe /S [LocalAppDataFolder]sharepoint\MenuEx.dll

    The Loader: PhantomLoader 

    The initial loader is a 32-bit DLL written in C/C++, serving as the first-stage loader. We named it “PhantomLoader” to emphasize its elusive and stealthy behavior. The loader is added to a legitimate DLL, usually EDR or AV products, by binary patching the file and employing self-modifying techniques to evade detection. This loader has not been reported or documented previously.

    Analysis of its metadata reveals that the PhantomLoader attempts to disguise itself as a legitimate DLL named ‘MenuEx.dll,’ associated with 360 Total Security, a Chinese antivirus program. Additionally, we discovered a PDB path in the metadata: C:\vmagent_new\bin\joblist\500965\out\Release\MenuEx.pdb. The loader also shares code with the antivirus software and retains remnants of a digital signature, as shown by Intezer’s analysis.

    SHA256: 09ffc4188bf11bf059b616491fcb8a09a474901581f46ec7f2c350fbda4e1e1c

    String and Code reuse between the loader and 360 Total Security.

    The payload is stored encrypted in the resource section, which exhibits a high entropy level, as shown in the screenshot below. 

    The sections of MenuEx.dll
    The sections of the PhantomLoader.

    Phantom Loader is a self-modifying loader. It first decrypts the stub function, which then extracts the payload from the resource section. The screenshot above shows that the `.text` section has RWX permissions, which is uncommon. However, since the loader is self-modifying, this explains the unusual permissions.

    The decoding logic employs an XOR decryption method. Each byte of the encrypted code at a specified address is XORed with a corresponding byte from a predefined encryption key. The key repeats cyclically if the code’s length exceeds the key’s length.

    The XOR key is a stack string with the following value:

    71 21 2a 43 74 52 4f 42 65 6a 6c 64 57 46 37 45 33 40 31 4c 69 79 55 53 00

    Below is an IDA Python script that modifies the code based on the logic described above:

    import ida_bytes
    import ida_auto

    def decode_code(start_addr, length, key_hex):
        # Convert the hex key string into a byte array
        key_bytes = bytearray.fromhex(key_hex)

        # Read the current encrypted data from the IDB
        encrypted_data = ida_bytes.get_bytes(start_addr, length)

        # Create a bytearray for the encrypted data to perform mutable operations
        encrypted_data = bytearray(encrypted_data)
        key_length = len(key_bytes)

        # Perform the XOR decryption
        for i in range(length):
            encrypted_data[i] ^= key_bytes[i % key_length]

        # Write the decrypted data back to the IDB
        # Convert bytearray back to bytes since patch_bytes expects a ‘bytes’ type
        ida_bytes.patch_bytes(start_addr, bytes(encrypted_data))
       
        # Optionally, inform IDA to reanalyze modified areas to reflect changes in disassembly
        ida_auto.auto_make_code(start_addr)
        ida_auto.auto_wait()

    # Constants
    encryption_key_hex = “71212a4374524f42656a6c64574637453340314c6979555300”  # The decryption key in hex
    code_region_length = 0x76C  # Length of the code region
    start_address = 0x1000AF77  # Starting address of the encrypted code

    # Decode the encrypted code region
    decode_code(start_address, code_region_length, encryption_key_hex)

    print(“Decryption complete. The code region has been updated.”

    Once the code is decrypted, the instruction pointer (EIP) will point to the first instruction. The stub then implements the same XOR decryption using the same key to extract the encoded payload from the resource section. After decoding the payload, the stub loads and executes it. This payload is another loader.

    Encoded resource.

    Another version of the loader, observed in the attack that uses the decoy document, follows the same logic but employs a different XOR key:

    25 5e 47 51 4d 4a 42 44 77 42 64 58 4c 41 46 57 75 28 21 46 61 67 32 24 34 46 47 00

    SHA256: 73774861d946d62c2105fef4718683796cb77de7ed42edaec7affcee5eb0a0ee

    Second Stage of The Phantom Loader

    The second stage of the Phantom Loader is a small, simple 32-bit DLL written in C/C++. It loads the payload and sets the entry point to the “DllRegisterServer” function.

    SHA256: 6aa3daefee979a0efbd30de15a1fc7c0d05a6e8e3f439d5af3982878c3901a1c

    SSLoad: The Downloader

    The payload is a 32-bit DLL written in Rust, identified as SSLoad. This stage has not been documented in previous blogs, indicating it might be an additional step in the delivery chain. Key strings, such as the user agent and domains, are encrypted using a unique algorithm.

    SHA256:265514c8b91b96062fd2960d52ee09d67ea081c56ebadd7a8661f479124133e9

    This SSLoad variant begins by decrypting a URL and a user agent. The URL directs to a Telegram channel named SSLoad, which serves as a dead-drop site, as shown in the screenshot below. This channel contains another encrypted string that indicates the Command-and-Control (C2) server responsible for delivering the final payload. 

    The variant we have analyzed uses the following address with the corresponding user agent.

    • https://t[.]me/+st2YadnCIU1iNmQy
    • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
    SSLoad malware Telegram channel.
    SSLoad Telegram channel.

    The Telegram channel is used as a dead drop host.

    Once the C2 address is decrypted, the malware decrypts another user agent string, SSLoad/1.1, and the string “/api/g.” This string is appended to the C2 address, forming the URL http://85[.]239.53.219/api/g. The malware then sends an HTTP GET request to this URL to retrieve the next payload from the C2 server.

    String Decoding

    This SSLoad variant employs a custom and unique method to decrypt strings, utilizing the standard RC4 algorithm. Notably, each string is encrypted with its own distinct key, which is stored alongside the encrypted string.

    We’ll use the first string as an example to explain the decryption logic. The blob below contains both the encrypted string and the RC4 key.

    uTjvTPJayj/5Af1pr+qBtvkwh9KKDV2mKF0C+7lBoOJHnmLwZJzKE

    Converted to hexadecimal:

    75 54 6A 76 54 50 4A 61 79 6A 2F 35 41 66 31 70 72 2B 71 42 74 76 6B 77 68 39 4B 4B 44 56 32 6D 4B 46 30 43 2B 37 6C 42 6F 4F 4A 48 6E 6D 4C 77 5A 4A 7A 4B 45

    The decryption key for each string is composed of the first 6 bytes of the encoded string concatenated with the last 7 bytes. For the given example, the key is:

    75 54 6A 76 54 50 4C 77 5A 4A 7A 4B 45

    The remaining part of the blob (from the 7th byte up to the length of the blob minus 7 bytes) is processed by a custom function that calculates the length of the encrypted string using the following logic:

    scaled_length = (length >> 2)
    if (length & 3) == 1:
        scaled_length -= 1
    scaled_length *= 3

    Essentially, the encrypted string starts at the 7th byte of the blob, and the value of scaled_length determines its length. 

    The malware uses Base64 encoding. In this example, the scaled_length is calculated to be 30 (0x1E).


    Base64 decryption.

    The Base64-decoded payload is then decrypted using the RC4 algorithm with the key derived earlier. This process decrypts the URL of the Telegram channel.

    SSLoad: The Payload

    The extracted payload from this file is: 6329244cfb3480eae11070f1aa880bff2fd52b374e12ac37f1eacb6379c72b80 which is another Rust file.

    The payload will first create a mutex, using a hardcoded string. This is a check if the machine is already infected. If the mutex exists, it will cease execution. 

    SSLoad will check the Process-Environment-Block (PEB) to see if the BeingDebugged flag is set, as an anti-debugging technique. 

    Next the library Advapi32.dll will be dynamically located in memory

    The DLL uses multiple arithmetic operations to derive a rolling XOR key. This key is used to decode strings dynamically. Every single string that is decrypted in this format has a unique stub of arithmetic operations and inputs, therefore every string has a unique XOR key. This is used in order to hamper static configuration extraction and differs from the method used by the downloader.

    The library Advapi32.dll is dynamically loaded in order to get the function RtlGenRandom (SystemFunction036). This randomly generated number is used to help generate a unique name for a working folder. Located under AppData\Roaming\Microsoft.

    Some library calls are dynamically located using a common malware technique. SSLoad does this by locating the PEB, and finding the PEB_LDR_DATA structure. This structure contains information about the currently loaded modules for the executed process. In this structure it will jump forward to the “InMemoryOrderModuleList”. This is a list of LDR_DATA_TABLE_ENTRY structures. It will loop through the names of these modules and perform a simple hash routine comparing it to a hardcoded hash. If the hash matches, the handle (HMODULE) of the module will be returned.

    Similarly, the malware resolves functions by hash, looping through the functions of the matching module to locate the corresponding function address based on the hash. It stores these pointers as local variables to be called at the appropriate time. This technique is most commonly used for the winhttp.dll module to evade static analysis that detects network capabilities.

    Next the DLL will start the fingerprinting process, in preparation for sending a registration beacon to the C2. The fingerprint results are built into a JSON object. Below are the following fields:

    FieldDescription
    versionThe version of the loader. Hardcoded into the binary.
    ipThe public IP address, obtained using api.ipify[.]org.
    domainThe Windows network domain
    hostnameComputer host name taken from environment variable
    archArchitecture of the infected machine, taken from environment variable
    os_versionThe version of the Windows operating system. Retrieved using GetVersionExW
    cur_userString indicating whether the current user is an administrator or not
    ownerAppears to indicate campaign name

    This JSON fingerprint is sent to the C2 over plaintext via a HTTP POST request. If the registration is successful, the C2 will respond with a JSON object containing a key and an ID. The “key” field is a Base64 string that is used as an RC4 key in later communications. The ID is a unique identifier for the infected host that is primarily used to identify itself to the C2 during further HTTP requests. When the registration is complete, SSLoad will begin its task beaconing loop. The malware will send a HTTP POST request to the C2, using the unique identifier as a URL path. No data is sent from the client in this POST request.

    POST /api/[unique_identifier]/tasks

    If the C2 has a task for the infected host, it will send over a JSON structure containing a “job” and another unique identifier for this job. The job is an RC4 encrypted struct that is encoded in a Base64 string. The job structure has two fields, a “command”, and an array of arguments. We have only observed the command “exe” in communications, with an argument that is a URL pointing to a server to download an additional payload. The way that the job struct is formed means that the malware is designed to be easily expanded to support more commands in the future.

    Conclusion

    The comprehensive SSLoad analysis reveals this malware’s intricate nature. SSLoad demonstrates its capability to gather reconnaissance, attempt to evade detection and deploy further payloads through various delivery methods and techniques. Its use of a Rust-based downloader, a never-seen-before loader, implements dynamic string decryption, and anti-debugging measures emphasize its complexity and adaptability.

    As SSLoad continues to evolve, it highlights the necessity for ongoing monitoring and advanced threat detection methods to combat malware campaigns effectively. This analysis deepens our understanding of SSLoad and emphasizes the importance of adaptive cybersecurity measures in the face of ever-evolving threats.

    IOCs

    Files

    90f1511223698f33a086337a6875db3b5d6fbcce06f3195cdd6a8efa90091750MSI Installer
    09ffc4188bf11bf059b616491fcb8a09a474901581f46ec7f2c350fbda4e1e1cPhantomLoader
    73774861d946d62c2105fef4718683796cb77de7ed42edaec7affcee5eb0a0eePhantomLoader
    6aa3daefee979a0efbd30de15a1fc7c0d05a6e8e3f439d5af3982878c3901a1cSecond stage of the PhantomLoader
    265514c8b91b96062fd2960d52ee09d67ea081c56ebadd7a8661f479124133e9SSLoad Downaloder
    6329244cfb3480eae11070f1aa880bff2fd52b374e12ac37f1eacb6379c72b80SSLoad Payload

    Network

    https://t[.]me/+st2YadnCIU1iNmQy
    85.239.53[.]219
    Nicole Fishbein

    Nicole is a malware analyst and reverse engineer. Prior to Intezer she was an embedded researcher in the Israel Defense Forces (IDF) Intelligence Corps.

    Ryan Robinson

    Ryan is a security researcher analyzing malware and scripts. Formerly, he was a researcher on Anomali's Threat Research Team.

    Generic filters
    Exact matches only
    Search in title
    Search in content
    Search in excerpt