MALHAWK Logo

MalHawk

Table of Contents

Redline Infostealer

September 26, 2025
#redline#info-stealer#crypto wallets#trojan#base64#xor#process hollowing#exfiltration#C2#pua

Overview

RedLine is a .NET information-stealer first observed in 2020, it is deployed as a trojan, masquerading to be a legitimate tool or already launched software. It has since evolved into a configurable data-harvesting platform sold as Malware-as-a-Service (MaaS). It first fingerprints the host (CPU, RAM, GPU, OS and installed software) and then runs multiple modules to extract sensitive data: browser secrets (including wallets, saved passwords, cookies and autofill form data, credit-card data), extension data, messenger session stores for Telegram and Discord, FTP client credentials (FileZilla), Steam session/config files, and VPN profiles/keys.

It applies a lot of string obfuscation to hide targets and Operators control victims through a small C2 channel that issues scan tasks, receives structured ScanResult data, and can push actions that are hidden from the user. The attackers who gain access can steal credentials, hijack sessions, impersonate users, move laterally, and add hosts to botnets.

But in October 2024, Operation Magnus; a coordinated takedown by the Dutch National Police together with the FBI, Eurojust and international partners disrupted the RedLine/META Stealer ecosystem: servers were seized, domains sinkholed, and suspects arrested. Earlier, in 2023, partial disruptions (including removal of GitHub dead-drop resolvers) had already degraded parts of the infrastructure and exposed backend components used by the service. Despite these actions, the malware’s MaaS model and leaked/cracked copies mean variants still circulate, so RedLine-style capabilities continue to pose a risk.


Fingerprint & Threat Intel

sha256hash a040d59da65288f88ded3b130199a23f33f01e9b049b89c0cceaabc5c6984bb26

alt text

Identified as a CSDP executable, which is a software library for solving semidefinite programming problems (special kind of math problem); which is actually written in C. Obviously the malware uses this application or signature to masquarade as a legitimate tool. It's capable of detecting a debugging environment for anti-analysis purposes, it contains a .net assembly file, contains sleeps that we'll see later also to aid in anti-analysis but not quite for this malware sample. Tagged as a spreader since it can propagate itself to other systems acting as a worm or a virus. Checks for user activity probably keystrokes or mouse movements.

alt text

Pua - potentially unwanted application also known as PUP (potentially unwanted program). They often come bundled with other software, sometimes without clear disclosure, and may install additional unwanted programs. This explains the earlier label of a spreader. It has similarities or features found in the three families mentioned, remcos is a genuine remote control and surveillance software that allows for remote control of a machine, remote surveiilance, remote administration and security audits. It was developed for genuine reasons but is being misued by threat actors as a Remote Access Trojan (RAT).

When I inspected the PE imports and the .NET assembly metadata, the binary only exposed GUI-related setup, nothing useful for static analysis. The file used a PDF-style icon, presumably to trick victims into opening what looks like a document even though it’s an executable. Despite being marked as a GUI app, the program shows no visible interface when run; in my experience this is a common trick in malware to avoid alarming the user, and later traces in the sample confirm it spawns hidden windows and background threads.

The sample’s entropy is ~7.6, which is high and indicates packed or compressed code and resources. That level of entropy combined with the lack of helpful imports explains why static analysis revealed very little: most strings and functionality are obscured until the program is executed.

alt text


Runtime Behaviour

On running the sample first red flag we see is tcp connections established to a host endpoint and a post request is made by the infected machine.

alt text

From the Wireshark output above we can see the TCP handshake between the infected host and the server endpoint; this channel is being used as the command-and-control (C2). The SYN / SYN-ACK / ACK sequence completes the three-way handshake, then the infected machine announces it will push data, the server acknowledges, and a POST request is made to an HTTP endpoint.

The HTTP endpoint used is 45.137.22.250:55615. The sample attempts to connect to this endpoint; when the server is down the connection fails and we observe RST, ACK packets as the remote host closes the TCP connection. The Domain name resolution for this host is customer-rental.rootlayer.net associated with a bangladesh IT solutions business.

To test further, I redirected that IP to a local machine and ran a Python mock server listening on the same IP/port. I returned a successful SOAP XML response, but the malware expected additional arguments from the server. Because those extra arguments were not present, and it kept looping: the connection-flag remained false until the server sent the expected arguments indicating a successful connection.

To get around this i tried redirecting the ip to point to my machine and used a python mock server that was listening on the same ip addr and port number to give the incoming response a success xml response but there were many more arguements expected from the server is what i suspect.Therefore the malware kept looping since the flag was set to false, until it got arguements from the server indicating successful connection.

alt text

This is the post request made by the infected machine used to check for connectivity to the server. SOAP envelope is a small XML-based RPC request (CheckConnect) wrapped in a standard SOAP envelope. The malware sends this SOAP POST to probe the C2 endpoint and check connectivity — a simple “are you there and ready?” handshake expressed as a SOAP action. The surrounding HTTP headers (Content-Type, SOAPAction, Content-Length, etc.) are standard for SOAP over HTTP. The TCP traces show how the transport is established and torn down, and the RST/ACK behavior indicates the remote endpoint refused or closed the connection which means the server is down or not responding with the required arguements.

I proceeded to check for process hollowing. The sample spawned a different executable in memory, replacing the original loader — a classic hollowing pattern. After the swap, the in-memory image headers reflected a new binary: the actual payload Happy.exe, a .NET application associated with the RedLine infostealer. The new payload had medium entropy (~5.6), suggesting little/no packing or obfuscation, and the code was straightforward to analyze.

alt text

RedLine and Hawkeye are different in style and sophistication: RedLine is feature-rich and modular, but Hawkeye’s codebase appears more polished and more advanced.


Payload Analysis

alt text alt text

The functions are pretty straightforward and it starts of with this entrypoint function which includes the hide function as we can see below calls and loads the memory addresses and windows handles of two DLLs Windows API functions, one that spawns up a console window and the other shows the window, but through the intPtr3, 0 command the console window does not show. As i was debugging the payload though, the console window popped up so this only applies to the loader (CSDP). Then sets up the different parameters of the entrypoint object.

alt text alt text

Then proceeds to execute the created object with the IP, message, ID and key parameters passed to it. It receives a message from the entrypoint function. This message is decrypted using a key, also provided by the entrypoint. Once started, the thread is hidden in the background. At this stage, the program either returns OK if decryption succeeds, or an error if it fails.

Next, the program creates an object that manages a connection to a remote server. This connection process is clean, ensuring resources are not left hanging when the connection is closed. Alongside this, it prepares a list of IP addresses by decrypting each string inside the entry.IP argument with the same key. After decryption, any unnecessary data is stripped out, leaving a clean list of IPs.

The connection object then attempts to connect to these IPs one by one. If a connection succeeds, a flag is set to true and the process continues. If all attempts fail, the program waits five seconds and retries the list. If no connection is ever established, the flag remains false.


Once a connection is active, the program creates a scanningArgs object to hold instructions received from the server. Since multiple arguments are expected, it uses the out keyword to return them. The program runs a loop that checks whether new arguments have arrived. If arguments are present, the loop ends. If no arguments are received, the program waits one second and checks again. Throughout this process, it continuously verifies whether the server connection is still alive. If a connection error occurs, an error object is created to store the error message.

When scan results are generated, they are stored in a new object. The program decrypts an ID using the same key to determine which batch the scan results belong to. It also checks whether the result has been seen before, which is handled in a separate function. At this point, the machine is effectively in a command-and-control (C2) loop: it receives scanning instructions from the server, executes them, then returns results to the server.

The machine also manages a task list. When new tasks arrive from the server, each is assigned an ID. The machine executes these tasks and reports their completion back to the server, repeating until the server confirms receipt.


If at any stage the connection to the server drops, the program waits one second, then restarts the process from the beginning.

Finally, the program checks whether it has infected the machine before. It does this by looking for the Yandex\VraAddon directory inside the LocalAppData folder. If the directory already exists, it returns true. If not, the program creates the directory and returns false.

I found this sleep durations not to be quite effiicient or rather they were too short and easily noticeable to analysis tools, but maybe not to a sandbox.

alt text


alt text alt text

The scan result is as shown above, basically making a fingerprint of the infected machine. The scan details contains a deeper scan that scans and creates a list of the information harvested.


Decrypt function

We have seen 3 instances above whereby the decrypt function is used on an encrypted message, IP and ID.

From the image below the decrypt function which involves XOR and base64 obfuscation. It takes two arguements a base64 string which is the Ip address seen earlier and the program even throws an error saying the IP address is not in base 64 format, the ip address is the value that was passed into the b64 string variable and the key used for XOR decryption.

the strings we saw earlier are encrypted 3 times base64 -> scrambled with XOR using a key -> bae64 again. But what is weird is that the ip address was hardcoded in plaintext within the code.

alt text


Wallet scanning

alt text alt text Looks for multiple cryptocurrency wallet files in their directories under AppData. Either any file found in that directory or a .wallet file. For example below we see a file scanner rule that looks for armory wallet files, but it does not search subfolders. Then returns the folder path for which the files are found in. For the atomic rule, it scans all files searching subfolders for any file with the string "Atomic" and returns paths that match the pattern. This code is used to scan for other wallets listed below.

alt text

It also looks for crypto wallet browser extensions. It uses the Unique extension ID which is a 32-character string assigned to browser extensions installed in chromium based browsers. These IDs are used in the browser's internal extension directory locally that is for example for chrome it would be *%APPDATA%\Local\Google\Chrome\User Data\Default\Extensions*. If browserpath is provided it copies them to a new list for reference and if null it keeps an empty list.

Targeted wallets

  • Armory, Atomic, Coinomi, JaxxxLiberty, Electrum, Guarda, Exodus, Eth, Tronlink, MetaMask, Coinbase, Binance Chain, iWallet, BitApp, EqualWallet,MathWallet, BraveWallet, Wombat, Yoroi, Ronin, Saturn, Guild.

alt text

This method enumerates browser data folders such as Chrome and Opera looking for key storage files such as login data, web data, cookies and generates scanning targets for specific browser extensions. Basically prepares a list of browser profiles and extension folders for the malware to harvest data from (for instance Chrome_Default_BraveWallet). This could also be extended to the wallet scanning.


alt text

For the cookies redline reads Chromium cookies from the SQLite Databases just like we saw in hawkeye although that was reading credentials. Then it uses the master key to decrypt the encryted_value blobs and collects the cookie name, value, host, path and expiry data, and adds them to a scannedcookie list. Attackers can then perform session hijacking for further damage such as transfering bank funds or stealing even more data.


alt text

It also scans for autofill form data: names and values in the modern Chromium versions, decrypts the value and adds it to a list. Similar approach to the Credit Card one.


alt text

Scans a browser profile directory for web data file as we saw earlier, where Chromium stores autofill and payment information. If a file is found, redline first extracts the browser’s AES decryption key from the Local State file (which lives in the browser's user data folder on their machine). It then creates a shadow copy (a tmp file which are actively deleted) of the Web Data SQLite database to safely read it without locking issues.

Then the function opens the credit_cards table and iterates through its rows. For each entry, it tries to read and decrypt the stored credit card number using the AES key. It also retrieves the cardholder name, expiration month, and year. The decrypted number has spaces stripped out, and all of these details are used to build a CC object representing a single credit card. Any successfully parsed credit card records are added to a list, which the function returns.


alt text

The Chromium decrypt function used determines how a Chromium-stored secret is encrypted (in redline it is used for Credit Card data and the cookies), then decrypts it using the appropriate method. It first inspects the blob’s prefix to decide between two formats: modern Chromium blobs that start with a version tag(v10/v11) and older DPAPI-protected blobs. For the modern v10/v11 style, the function uses the browser’s AES master key (unwrapped from the profile’s Local State encrypted_key by DPAPI) to perform an AES-GCM decryption of the blob and return the plaintext. Chromium stores an AES master key protected by DPAPI in Local State; if an attacker obtains code execution as the user, they can call DPAPI to unwrap the AES key and decrypt secrets.

For older entries, it calls the Windows DPAPI unprotect routine on the blob to retrieve the plaintext directly. The function therefore returns the decrypted secret (for example, a cookie value or saved password) in readable form, enabling the caller to use or collect cleartext credentials and session tokens.

alt text

This decrypt function is used as an AES decryption helper.

Redline also uses bcrypt functions for the cryptography operations. It is mainly known as a password hashing algorithm from blowfish encryption algorithm. But in this context it referss to Windows Crypto Next Gen (CNG). Redline uses CNG to perform the actual symmetric decryption (AES-GCM) of data once it has the master key which has been unwrapped through DPAPI.

alt text

This is the ParseLocalStateKey that we have been seen used for locating the Local State file path or LocalPrefs.json. Once found, it reads the file, parses the JSON, and extracts the base64-encoded os_crypt.encrypted_key, which is the AES master key Chromium uses to encrypt profile secrets.

It vastly looks for roaming files and local files for Chrome and gecko (mozilla). From the browsers it scans for the browsername, browserprofile, cookies, logins, autofills, Credit card data and wallets quite thorough.


Social sites, game launchers, FTP client

alt text

  • Telegram - Scans Telegram Desktop installations, specifically targeting their tdata folders, including subfolders, to collect encrypted session data and cached messages which can also enable account hijacking. tdata folder is used by Telegram Desktop to store session data, including login credentials and account information. It allows users to stay logged in without re-entering credentials.

alt text

  • Discord - Scans Discord’s local storage\Leveldb by scanning the Local Storage\leveldb folder within the user’s AppData directory. It specifically looks for *.log and *.ldb files, which include LevelDB database files and log files containing session tokens, cached messages, and client-side data.

alt text

  • Steam - Locates the installation path through the registry (HKCU\Software\Valve\Steam) and scans key files and folders. It specifically looks for files matching ssfn in the Steam directory (used for session authentication) and configuration files in the config subfolder, including Valve Data Format files such as loginusers.vdf and config.vdf. These files can provide information about active sessions, login states, stored user IDs, and client settings.

alt text alt text

  • FileZilla - Scans the %APPDATA%\FileZilla\ directory for key XML files, specifically recentservers.xml and sitemanager.xml, which store recently connected servers and saved site credentials. It checks if these files exist and, if so, parses them using XML readers. For each server entry, it extracts the host and port (combined as a URL), the FTP username, and the password, which is decoded from Base64. If any of these fields are missing, it assigns "UNKNOWN" to maintain consistent data formatting. This process allows the malware to collect stored FTP credentials, enabling an attacker to potentially access the victim’s previously connected servers.

I realized there is a lot of obfuscation for strings by splitting them into individual characters, also adding junk characters which are then replaced and removed at runtime to bypass static analysis.

Example: The string "1*.llldlb" is obfuscated and doesn’t immediately reveal the target.

At runtime, .Replace("1", string.Empty) removes the junk characters, resulting in "*.ldb" which targets LevelDB files in Discord’s leveldb folder.

Also helps in preventing some automated scanners from easily detecting the file patterns the malware is targeting.

alt text

It starts by resolving the user’s local AppData path to find the VPNs data folder location, the method adds a non-recursive scan target for OpenVPN profile files (*.ovpn) in %USERPROFILE%\AppData\Local. The collected profiles often contain server endpoints (IPs), ports, transport (UDP/TCP), TLS auth/cipher settings, client certificates and private keys. This can be used to recreate or impersonate a victim’s VPN session.

Targeted VPNs

  • OpenVpn Connect
  • ProtonVpn
  • NordVpn

Additional Scans Scans for programs from program files and program files (x86) directories, Firewalls, AntiSpyware, Antivirus software, Graphics Card, List of running processes and Machine Serial numbers. A lot of information about the infected machine being collected. This can act as reconnaisance to launch other attacks like a DDOS attack etc.


Command and Control

Implements C2 communication whereby the infected machine contains a a task-execution framework that accepts remote instructions from the server and as we saw earlier it also assigns these instructions IDs executes those tasks and updates the server when they are done.

alt text

This first class runs a Windows command that spawns up the console which executes the command coming from updateTask.TaskArg, it then hides the console (CreateNoWindow = true), and waits up to 20 seconds for the command to finish.

alt text

The second class fetches and runs a remote file, it expects updateTask.TaskArg to contain two separated values: a remote URL and a local path. It downloads the file (WebClient.DownloadFile(url, localPath)), then starts it from the file’s directory.


alt text Finally, the ResultFactory acts as a central coordinator for collecting and organizing all scan data. It maintains a list of functions that each perform a specific scan or data extraction task.

For example, the function sdi845sa checks if VPN scanning is enabled and then populates the result object with account data from NordVPN, OpenVPN, and ProtonVPN by applying their respective scanner rules. Each function in the ResultFactory writes its findings into the shared result object, which serves as the container for all collected data, from VPN credentials to browser sessions or FTP accounts and system profiling. Allowing the malware to flexiblys extend or update its scanning capabilities while keeping all results centralized for reporting back to the operator.


IOCS

  • 9D5F3DB272FCH9EAC13AC0EE55F810B70A13F5363F927EB52BDC3223B99D1637
  • 45.137.22.250:55615
  • a040d59da65288f88ded3b130199a23f33f01e9b049b89c0cceaabc5c6984bb26
  • customer-rental.rootlayer.net

TTPs

Behavior (TTP) MITRE ATT&CK Description
C2 connection / beaconing T1071 — Application Layer Protocol Network C2 channel.
Modular task pipeline / automated collectors T1119 — Automated Collection Ordered automatic data collection.
Browser master key DPAPI unwrap + decrypt (cookies/passwords) T1539 — Credentials from Web Browsers Recover plaintext browser secrets.
Credentials / session data stored in app files (Discord, Telegram, FileZilla, Steam, VPN profiles, Wallets) T1552.001 — Credentials in Files Theft of credentials from local files.
File & directory discovery (profiles, AppData) T1083 — File and Directory Discovery Enumerates files/folders to find targets.
String obfuscation (char-splitting, junk replace) T1027 — Obfuscated Files or Information Hides static indicators from analysis.

Reference

https://www.welivesecurity.com/en/eset-research/life-crooked-redline-analyzing-infamous-infostealers-backend/

Conclusion

Redline profiles the system (CPU, RAM, GPU/graphics card, installed hardware and OS details) to fingerprint the host. Then it runs a list of small, focused collectors each one scans and grabs a different type of data to pull browser secrets including wallet, autofill, Credit Card data, messenger sessions (tdata), Discord tokens, FTP/FileZilla credentials, Steam session files, and VPN profiles/keys. It talks to a C2 server to receive scan tasks and can run commands or download-and-run files on demand. Has used string obfuscation to hide targets. The impact is high: stolen credentials, session tokens, and VPN/profile files let an attacker hijack accounts, impersonate users, move laterally or turn the infected machine into a bot.

From a defensive standpoint, enforce strict monitoring of process creation to catch hidden executions or payloads launched from paths like AppData. Network defenses should flag unusual outbound, inbound traffic to detect C2 traffic. Since these families rely on dropping and executing secondary payloads, application control and allow-listing can help stop unknown binaries from running in the first place. Should also deploy browser hardening and secure password managers, limiting what local files can expose. Finally, having endpoint detection and memory inspection in place ensures that even if the malware bypasses static defenses, its runtime behavior can still trigger alerts. From the ESET blog, Isolate infected hosts, Preserve forensic evidence, Rotate exposed credentials and keys and Enforce MFA which will limit usefulness of some stolen credentials. Lastly, create detection rules tailored to specific indicators of compromise or malicious behaviors.

Back to Blog