πŸ”’
There are new articles available, click to refresh the page.
Before yesterdayAvast Threat Labs

Chasing Chaes Kill Chain

25 January 2022 at 13:43

Introduction

Chaes is a banking trojan that operates solely in Brazil and was first reported in November 2020 by Cybereason. In Q4 2021, Avast observed an increase in Chaes’ activities, with infection attempts detected from more than 66,605 of our Brazilian customers. In our investigation, we found the malware is distributed through many compromised websites, including highly credible sites. Overall, Avast has found Chaes’ artifacts in 800+ websites. More than 700 of them contain Brazilian TLDs. All compromised websites are WordPress sites, which leads us to speculate that the attack vector could be exploitation of vulnerabilities in WordPress CMS. However, we are unable to perform forensics to confirm this theory. We immediately shared our findings with the Brazilian CERT (BR Cert) with the hope of preventing Chaes from spreading. By the time of this publication, Chaes’ artifacts still remain on some of the websites we observed.

Chaes is characterized by the multiple-stage delivery that utilizes scripting frameworks such as JScript, Python, and NodeJS, binaries written in Delphi, and malicious Google Chrome extensions. The ultimate goal of Chaes is to steal credentials stored in Chrome and intercept logins of popular banking websites in Brazil.

In this posting, we present the results of our analysis of the Chaes samples we found in Q4 2021. Future updates on the latest campaign will be shared via Twitter or a later post.

Infection Scheme

When someone reaches a website compromised by Chaes, they are presented with the below pop-up asking users to install the Java Runtime application:

If the user follows the instructions, they will download a malicious installer that poses as a legitimate Java Installer. As shown below, the fake installer closely imitates the legitimate Brazilian Portuguese Java installer in terms of appearance and behavior.

Once the installation begins, the user’s system is compromised. After a few minutes, all web credentials, history, user profiles stored by Chrome will be sent to attackers. Users may experience Google Chrome getting closed and restarted automatically. This indicates any future interactions with the following Brazilian banking websites will be monitored and intercepted:

  • mercadobitcoin.com.br
  • mercadopago.com.[ar|br]
  • mercadolivre.com.br
  • lojaintegrada.com.br

Technical Analysis

Infected websites

Upon inspecting the HTML code of the compromised websites, we found the malicious script inserted as shown below:

In this case, the V=28 likely represents the version number. We also found a URL with other versions as well:

  • https://is[.]gd/EnjN1x?V=31
  • https://is[.]gd/oYk9ielu?D=30
  • https://is[.]gd/Lg5g13?V=29
  • https://is[.]gd/WRxGba?V=27
  • https://is[.]gd/3d5eWS?V=26

The script creates an HTML element that stays on top of the page with β€œJava Runtime Download” lure. This element references an image from a suspicious URL

  • https://sys-dmt[.]net/index.php?D\
  • https://dmt-sys[.]net/

and an on-click download of a Microsoft Installer from

  • https://bkwot3kuf[.]com/wL38HvYBiOl/index.php?get or
  • https://f84f305c[.]com/aL39HvYB4/index.php?get or
  • https://dragaobrasileiro[.]com.br/wp-content/themes/getCorsFile.php

Microsoft Installer

The flowchart below shows the infection chain following the malicious installer execution.

Inside the MSI package

The installer contains 3 malicious JS files install.js, sched.js, and sucesso.js renamed to Binary._ as shown above. Each of them handles a different task, but all are capable of reporting the progress to the specified CnC:

Implementation of the logging function across all 3 scripts

install.js

The purpose of this script is to download and execute a setup script called runScript that will prepare the proper Python environment for the next stage loader. After making an HTTP request to a hardcoded domain, the obfuscated runScript is downloaded and then executed to perform the following tasks:

  • Check for Internet connection (using google.com)
  • Create %APPDATA%\\<pseudo-random folder name>\\extensions folder
  • Download password-protected archives such as python32.rar/python64.rar and unrar.exe to that extensions folder
  • Write the path of the newly created extensions folder to HKEY_CURRENT_USER\\Software\\Python\\Config\\Path
  • Performs some basic system profiling
  • Execute unrar.exe command with the password specified as an argument to unpack python32.rar/python64.rar
  • Connect to C2 and download 32bit and 64bitΒ __init__.py scripts along with 2 encrypted payloads. Each payload has a pseudo-random name.
runScript.js content

sched.js

The purpose of this script is to set up persistence and guarantee the execution of __init__.py downloaded by runScript from the previous step. Sched.js accomplishes this by creating a Scheduled Task as its primary means and creating aΒ  Startup link as its backup means. Ultimately, they are both able to maintain the after-reboot execution of the following command:

Β ...\\<python32|python64>\\pythonw.exe __init__.py /m

ScheduledTask Configuration

sucesso.js

This script reports to CnC that the initial installation on the victim’s computer has succeeded and is ready for the next stage

Python Loader Chain

The Scheduled Task created by sched.js eventually startsΒ  __init__.py which initiates the Python in-memory loading chain. The loading chain involves many layers of Python scripts, JS scripts, shellcode, Delphi DLLs, and .NET PE which we will break down in this section. Impressively, the final payload is executed within __init__.py process (PID 2416 and 4160) as shown below:

__init__.py

Obfuscated content

The __init__.pyΒ  xor decrypts and decompresses the pseudo-random filename downloaded by runScript.js into another Python script. The new Python script contains 2 embedded payloads: image and shellcode in encrypted form. Image represents the Chaes loader module called chaes_vy.dll while shellcode is an in-memory PE loader. We found this particular loader shellcode reappearing many times in the later stages of Chaes. Running the shellcode using CreateThread API with proper parameters pointing to chaes_vy.dll, the Python script eventually loads chaes_vy.dll into memory:

chaes_vy.dll is loaded into memory by an embedded shellcode

Chaes_vy.dll

Chaes_vy is a Delphi module that loads an embedded .NET executable that in turn runs 2 JavaScripts: script.js and engine.js. These two scripts hold the core functionalities of the Chaes_vy module.

script.js

This script acts as the interface between .NET framework and JScript framework, providing the necessary utilities to execute any scripts and modules that engine.js downloads in the future. By default, script.js will try to retrieve the paths to payloads specified in the argument of __init__.py. If nothing is found it will execute engine.js

engine.js

This script employs 2 methods of retrieving a JS payload: getBSCode() and getDWCode() both are called every 6 minutes.

GetBSCode is the primary method, also the only one we are able to observe serving payload. The encrypted payload is hidden as commented-out code inside the HTML page of a Blogspot which is shown below. Without being infected by Chaes, this site is completely harmless.

View of the Blogpost page contains hidden malicious code

On the other hand, when executed, engine.js will parse the string starting fromΒ  <div id=\”rss-feed\”> which is the marker of the encrypted payload:

Hidden code

After decrypting this text using AES with a hardcoded key, instructions.js is retrieved and executed. This script is in charge of downloading and executing Chaes’ malicious Chrome β€œextensions”. More info about instructions.js is provided in the next section.

getDWCode is the secondary method of retrieving instruction.js. It employs a DGA approach to find an active domain weekly when getBSCode fails. Since we are not able to observe this method being used successfully in the wild, we have no analysis to present here. However, you can check out the full algorithm posted on our Github.

Instructions.js

Instructions.js is the last stage of the delivery chain. Nothing up to this point has gained the attacker any true benefits. It is the job of instructions.js to download and install all the malicious extensions that will take advantage of the Chrome browser and harm the infected users. The address of all payloads are hardcoded as shown below:

The extensions are separated into password-protected archives vs encrypted binaries. The non-compressed payloads are PE files that can be run independently while compressed ones add necessary NodeJS packages for the extension to run. Below is the example of chremows63_64 archive contents:

All the binaries with dll_filename argument such as chromeows2.bin are encrypted, including the ones inside the RAR archive. The decryption algorithm is located inside script.js as we mentioned in the previous section. To decrypt and run each binary, Chaes needs to call __init__.py with the file path specified as an argument.

The extension installation can be simplified into the following steps:

  • An HTTP Request (aws/isChremoReset.php)Β  is sent to check if Google Chrome from a particular uid has been hooked. If not, Chrome and NodeJS will be closed. More information about uid in the β€œOnline” section below.
  • The download request is constructed based on 3 scenarios: 32bit, 64bit, and no Google Chrome found. Each scenario will contain suitable versions of the extensions and their download links.
  • The extension is downloaded. The compressed payload will be unpacked properly.
  • A hosts file is created for the newly downloaded module. Inside the file is the CnC randomly picked from the following pool:

Each extension will use the address specified in hosts for CnC communication

  • Launch each extension through python.exe __init__.py with proper arguments as shown below

Extensions

Online

online.dll is a short-lived Delphi module that is executed by instruction.js before other modules are deployed. Its main purpose is to fingerprint the victim by generating a uid which is a concatenation of drive C: VolumeSerialNumber, UserName, and Computername. The uid is written to a register key SOFTWARE\\Python\\Config\uid before being included inside the beaconing message.

This registry key is also where instruction.js previously gets the uid asking CnC if the victim’s Chrome has been hooked. The first time instruction.js gets launched this registry has not been created yet, therefore the Chrome process is always killed.

Online.dll retrieves the CnC server specified in the hosts file and performs the beaconing request /aws/newClient.php, sending the victim’s uid and basic system information.

Mtps4 (MultiTela Pascal)

Module mtps4 is a backdoor written in Delphi. Its main purpose is to connect to CnC and wait for a responding PascalScript to execute. Similar to the previous module, CnC is retrieved from the hosts file. Mtps4 sends a POST request to the server with a hardcoded User-Agent containing uid and command type. It currently supports 2 commands: start and reset. If the reset command is responded with β€˜(* SCRIPT OK *)’, it will terminate the process.

Start command is a bit more interesting.

Example of an HTTP request with β€œstart” command

As a reply to this command, it expects to receive a PascalScript code containing a comment β€˜(* SCRIPT OK *)’.

mtps4 is compiled with https://github.com/remobjects/pascalscript to support PascalScript. Before running, the script they create a window that copies the screen and covers the entire desktop to avoid raising suspicion when performing malicious tasks on the system.

Unfortunately during the investigation, we couldn’t get hold of the actual script from the CnC.

Chrolog (ChromeLog)

Chrolog is a Google Chrome Password Stealer written in Delphi. Although it is listed as an extension, Chrolog is an independent tool that extracts user personal data out of the Chrome database and exfiltrates them through HTTP. The CnC server is also retrieved from the hosts file previously created by instruction.js.

HTTP Request Data Exfiltration
/aws/newUpload.php Cookies, Web Data, and Login Data (encrypted)
/aws/newMasterKey.php Chrome Master Key used to decrypt Login Data
/aws/newProfileImage.php Profile Image URL collected from last_downloaded_gaia_picture_url_with_size attribute inside Local State
/aws/newPersonalData.php Username, fullname, gaia_name
/aws/bulkNewLogin.php All Login Data is decrypted and added to local.sql database. Then the corresponding section of the database is exfiltrated
/aws/bulkNewUrl.php History is added to local.sql database. Then the corresponding section of the database is exfiltrated
/aws/bulkNewAdditionalData.php Web Data is written to local.sql database. Then the corresponding section of the database is exfiltrated
/aws/bulkNewProcess.php All running processes are collected and written to local.sql database. Then the corresponding section of the database is exfiltrated
(Cookies, Web Data, Login Data, History, and Local State is standardly located at %APPDATA%\\Local\\Google\\Chrome\\User Data\\Default\\)

Chronodx (Chrome Noder)

chrolog.rar contains NodeJS packages and chronodx.bin aka Chronod2.dll.
Chronodx dependency (β€œname”: β€œchremows” is indeed how it is defined)

The chronodx extension package can be separated into 2 parts: a loader called Chronod2.dll and a JavaScript banking trojan called index_chronodx2.js. First, Chronod2.dll performs an HTTP request /dsa/chronod/index_chronodx2.js to retrieve index_chronodx2.js. If successful, Chronod2.dll will run silently in the background until it detects the Chrome browser opened by the user. When that happens, it will close the browser and reopen its own instance of Chrome along with index_chronodx2.js being run from the node.exe process.

Chronodx in idle mode
Chronodx reopens Chrome and executes β€œnode.exe index.js” command
Index.js is index_chronodx2.js in this case

Index_chronodx2.js utilizes puppeteer-core, a NodeJS framework that provides APIs to control Chrome browser, for malicious purposes. Index_chronodx2.js implements many features to intercept popular banking websites in Brazil including

  • bancobrasil.com.br/aapf
  • bancodobrasil.com.br/aapf
  • bb.com.br/aapf
  • mercadopago.com/…/card_tokens/
  • mercadopago.com/enter-pass/
  • mercadolivre.com/enter-pass/
  • lojaintegrada.com.br/public/login/
  • mercadobitcoin.com.br

Upon visiting any of the above websites, index_chronodx2.js will start collecting the victim’s banking info and send it to the attacker through a set of HTTP commands. The CnC server is stored in the hosts file, but when it is not found in the system, a hardcoded backup CnC will be used instead:

C2 Command Meaning
/aws/newQRMPClient.php Supposedly sending user info to the attacker when a QR code scan is found on banking websites listed above, but this feature is currently commented out
/aws/newContaBBPF.php Sending user banking info when Bancodobrasil banking sites are intercepted
/aws/newContaCef.php Sending user banking info when Caixa banking sites are intercepted
/aws/newCaixaAcesso.php Telling the attacker that a victim has accessed Caixa banking page
aws/newMercadoCartao.php Sending user banking info when Mercado banking sites are intercepted
/aws/newExtraLogin.php Send user credentials when logging in to one of the listed pages

Chremows (Chrome WebSocket)

Chremows is another extension that uses NodeJS and puppeteer-core, and is similar to the functionality of node.js mentioned in the Cybereason 2020 report. Chremows targets two platforms Mercado Livre (mercadolivre.com.br) and Mercado Pago (mercadopago.com.br) both belong to an online marketplace company called Mercado Libre, Inc.

Chremows dependency

Sharing the same structure of chronodx module, chremows contains a loader, CreateChrome64.dll that downloads a JavaScript-based banking trojan called index.js. CreateChrome64.dll will automatically update index.js when a newer version is found. Unlike chronodx, chremows executes index.js immediately after download and doesn’t require Google Chrome to be opened. In a separate thread, CreateChrome64.dll loads an embedded module ModHooksCreateWindow64.dll that Cybereason has analyzed in their 2020 report. Overall, this module help increase the capabilities that chremows has on Google Chrome, allowing the attacker to perform β€œactive” tasks such as sending keypresses/mouse clicks to Chrome, or opening designated pages. Finally, CreateChrome64.dll copies Chrome’s Local State file to the same location of index.js with the name local.json. Index.js uses local.json to help the attacker identify the victim.

Hardcoded CnC

Index.js employs two methods of communicating with the attacker: through WebSocket and through HTTP. Each method has its own set of C2 servers as shown in the above picture. WebSocket is used to receive commands and send client-related messages. On the other hand, HTTP is for exfiltrating financial data such as banking credentials and account information to the attacker.

List of known Index.js WebSocket commands

Command from C2 Functionality
welcome:: Send uid and information extract from local.json to the attacker
control:: The attacker establishes control over Google Chrome
uncontrol:: The attacker removes control over Google Chrome
ping:: Check if the connection to the client is OK
command:: Send command such as keystroke, mouseclick
openbrowser:: Open Chrome window with minimal size to stay hidden

If the user stays connected to the WebSocket C2 server, every six minutes it automatically goes to the targeted Mercado Pago and Mercado Livre pages and performs malicious tasks. During this routine, the attacker loses direct control of the browser. The target pages are banking, credit, and merchant pages that require users’ login. If the user has not logged out of these pages, the attacker will start to collect data and exfiltrate them through the following HTTP requests:

  • /aws/newMercadoCredito.php
  • /aws/newMercadoPago.php

If the user is not logged in to those pages but has the password saved in Chrome, after the routine ends, the attackers will get back their direct control of Chrome and log in manually.

Summary

Chaes exploits many websites containing CMS WordPress to serve malicious installers. Among them, there are a few notable websites for which we tried our best to notify BR Cert. The malicious installer communicates with remote servers to download the Python framework and malicious Python scripts which initiate the next stage of the infection chain. In the final stage, malicious Google Chrome extensions are downloaded to disk and loaded within the Python process. The Google Chrome extensions are able to steal users’ credentials stored in Chrome and collect users’ banking information from popular banking websites.

IOCs

The full list of IoCs is available here

Network

HTML Scripts

  • is[.]gd/EnjN1x?V=31
  • is[.]gd/oYk9ielu?D=30
  • is[.]gd/Lg5g13?V=29
  • tiny[.]one/96czm3nk?v=28
  • is[.]gd/WRxGba?V=27
  • is[.]gd/3d5eWS?V=26

MSI Download URLs

  • dragaobrasileiro[.]com.br/wp-content/themes/getcorsfile.php?
  • chopeecia[.]com.br/D4d0EMeUm7/index.php?install
  • bodnershapiro[.]com/blog/wp-content/themes/twentyten/p.php?
  • dmt-sys[.]net/index.php?
  • up-dmt[.]net/index.php?
  • sys-dmt[.]net/index.php?
  • x-demeter[.]com/index.php?
  • walmirlima[.]com.br/wp-content/themes/epico/proxy.php?
  • atlas[.]med.br/wp-content/themes/twentysixteen/proxy.php?
  • apoiodesign[.]com/language/overrides/p.php?

CnC Servers

  • 200[.]234.195.91
  • f84f305c[.]com
  • bkwot3kuf[.]com
  • comercialss[.]com
  • awsvirtual[.]blogspot.com
  • cliq-no[.]link
  • 108[.]166.219.43
  • 176[.]123.8.149
  • 176[.]123.3.100
  • 198[.]23.153.130
  • 191[.]252.110.241
  • 191[.]252.110.75

SHA256 Hashes

Filename Hash
MSI installer f20d0ffd1164026e1be61d19459e7b17ff420676d4c8083dd41ba5d04b97a08c
069b11b9b1b20828cfb575065a3d7e0b6d00cd1af10c85c5d6c36caea5e000b7
1836f3fa3172f4c5dbb15adad7736573b4c77976049259cb919e3f0bc7c4d5ea
02831471e4bf9ef18c46ed4129d658c8ce5b16a97f28228ab78341b31dbef3df
a3bcbf9ea2466f422481deb6cb1d5f69d00a026f9f94d6997dd9a17a4190e3aa
62053aeb3fc73ef0940e4e30056f6c42b737027a7c5677f9dbafc5c4de3590bd
e56a321cae9b36179e0da52678d95be3d5c7bde2a7863e855e331aea991d51b9
7a819b168ce1694395a33f60a26e3b799f3788a06b816cc3ebc5c9d80c70326b
__init__.py 70135c02a4d772015c2fce185772356502e4deab5689e45b95711fe1b8b534ce
6e6a44ca955d013ff01929e0fa94f956b7e3bac557babcd7324f3062491755e2
0b5646f45f0fad3737f231f8c50f4ed1a113eb533997987219f7eea25f69d93f
abc071831551af554149342ad266cc43569635fb9ea47c0f632caa5271cdf32
runScript.js bd4f39daf16ca4fc602e9d8d9580cbc0bb617daa26c8106bff306d3773ba1b74
engine.js c22b3e788166090c363637df94478176e741d9fa4667cb2a448599f4b7f03c7c
image 426327abdafc0769046bd7e359479a25b3c8037de74d75f6f126a80bfb3adf18
3311b0b667cd20d4f546c1cb78f347c9c56d9d064bb95c3392958c79c0424428
c9b3552665911634489af5e3cb1a9c0c3ab5aed2b73c55ae53b8731a1de23a9f
chremows fa752817a1b1b56a848c4a1ea06b6ab194b76f2e0b65e7fb5b67946a0af3fb5b
e644268503cf1eaf62837ec52a91b8bec60b0c8ee1fb7e42597d6c852f8b8e9d
bd5d2a0ec30fa454af1a086b4c648039422eca4fa1b1d6e8ecc4d47be7fab27f
4d2ffae69b4e0f1e8ba46b79811d7f46f04bd8482568eccf5620e6b1129c1633
faad384e124c283a8d024ee69dceaac877be52f5adbf18ca6b475a66663b0e85
969fa30802bdb81be5b57fef073896c2ee3df4211663301548f8efa86257e0cf
5a1ebf757ab9aa796a8580daafab9635660b9cc55505db194cbfefeb612e48f0
2d9e040820acca9a0fab2dc68546e0a824c4c45ee8c62332213e47e1f6923c90
e1d9effa8a56d23dbcefd2146eb5c174a245b35a4f718473452135bd064a2157
32c545e133183e6fc999e8f6a0da3c6e7fb1a12b97d2a3bbc5e84faa175a9ef6
ba3e0314b1d6e6ee10c473c1bbd883c4a5c53b5703b5ced174cd5a30b0b87160
e210217f2b5912e16a281dcbd5a5247fe2a62897dc5c2e1bf4ff61d3a07405f0
7a1d74c4d62ceee45a3cbaf79070cfc01342a05f47e0efb401c53040897bed77
550188ad28ccc07791880777c2de07e6d824a7263b9e8054423597b160e594a3
9603c4ce0f5a542945ed3ced89dd943eb865368b4e263090be9e0d9c1785615d
chrolog 9dbbff69e4e198aaee2a0881b779314cdd097f63f4baa0081103358a397252a1
6dc63ea4dbe5d710b7ba161877bd0a3964d176257cdfb0205c1f19d1853cc43b
3e48f714e793b3111ce5072e325af8130b90a326eca50641b3b2d2eba7ac0a45
754eeb010795c86d1cc47b0813da6bbc6d9153f1dd22da8af694a9e2dca51cda
0762038fe591fef3235053c7136f722820de6d8457cae09d4aa9bf6cb7f497a1
chronod ea177d6a5200a39e58cd531e3effb23755604757c3275dfccd9e9b00bfe3e129
7c275daab005bb57e8e97ac98b0ae145a6e850370e98df766da924d3af609285
96224c065027bb72f5e2caebf4167482fe25fb91c55f995e1c86e1c9884815c3
2688a7ac5b408911ae3e473278ecbc7637491df2f71f6f681bc3ed33045b9124
f3c1fd9e8674901771c5bfc4ce16eba75beff7df895a4dc6fdd33bedb2967a08
ddecc2606be56beae331000ba091e5e77ae11380f46eba45387c65289e6ce421
debe443266ab33acb34119f515f4622464edff198f77fd20006e2d79aafb6dfc
bf4a83a19065d5c45858ceb988dce39d93c412902ead6434e85fbf2caa17db44
87502ad879a658aa463088c50facfbdbb1c6592263e933b8b99e77293fdf1384
6b6abc64053d20306147efced9df2ef75153e87a1d77ce657943b2373fb4ffb9
679a02d0ae4f5382767eb11cefad59c0664f55ed2ce3e3b3df97b78c09e18aa3
564b31c3d609d96a73ee139ec53453b985673ffacacb56ecd13d2c83bbf851e0
e649f71b68cc54f3d985e398f1c6354963ec027a26230c4c30b642d2fd5af0a6
online 3fd48530ef017b666f01907bf94ec57a5ebbf2e2e0ba69e2eede2a83aafef984
mtps4 5da6133106947ac6bdc1061192fae304123aa7f9276a708e83556fc5f0619aab

The post Chasing Chaes Kill Chain appeared first on Avast Threat Labs.

BluStealer: from SpyEx to ThunderFox

20 September 2021 at 17:06
By: Anh Ho

Overview

BluStealer is is a crypto stealer, keylogger, and document uploader written in Visual Basic that loads C#.NET hack tools to steal credentials. The family was first mentioned by @James_inthe_box in May and referred to as a310logger. In fact, a310logger is just one of the namespaces within the .NET component that appeared in the string artifacts. Around July, Fortinet referred to the same family as a β€œfresh malware”, and recently it is mentioned again as BluStealer by GoSecure. In this blog, we decide to go with the BluStealer naming while providing a fuller view of the family along with details of its inner workings.

a310logger is just one of the multiple C# hack tools in BluStealer’s .NET component.

BluStealer is primarily spread through malspam campaigns. A large number of the samples we found come from a particular campaign that is recognizable through the use of a unique .NET loader. The analysis of this loader is provided in this section. Below are two BluStealer malspam samples. The first is a fake DHL invoice in English. The second is a fake General de Perfiles message, a Mexican metal company, in Spanish. Both samples contain .iso attachments and download URLs that the messages claim is a form that the lure claims the recipient needs to open and fill out to resolve a problem. The attachments contain the malware executables packed with the mentioned .NET Loader.

In the graph below, we can see a significant spike in BluStealer activity recently around September 10-11, 2021.

The daily amount of Avast users protected from BluStealer

BluStealer Analysis

As mentioned, BluStealer consists of a core written in Visual Basic and the C# .NET inner payload(s). Both components vary greatly among the samples indicating the malware builder’s ability to customize each component separately. The VB core reuses a large amount of code from a 2004 SpyEx project, hence the inclusion of β€œSpyEx” strings in early samples from May. However, the malware authors have added the capabilities to steal crypto wallet data, swap crypto addresses present in the clipboard, find and upload document files, exfiltrate data through SMTP and the Telegram Bot API, as well as anti-analysis/anti-VM tactics. On the other hand, the .NET component is primarily a credential stealer that is patched together from a combination of open-source C# hack tools such as ThunderFox, ChromeRecovery, StormKitty, and firepwd. Note that not all the mentioned features are available in a single sample.

Obfuscation

Example of how the strings are decrypted within BluStealer

Each string is encrypted with a unique key. Depending on the sample, the encryption algorithm can be the xor cipher, RC4, or the WinZip AES implementation from this repo. Below is a Python demonstration of the custom AES algorithm:

Β A utility to help decrypt all strings in IDA is available here.

Anti-VM Tactics

BluStealer checks the following conditions:

If property Model ofΒ  Win32_ComputerSystem WMI class contains:

VIRTUA (without L), VMware Virtual Platform, VirtualBox, microsoft corporation, vmware, VMware, vmw

If property SerialNumber of Win32_BaseBoard WMI class containsΒ  0 or None

If the following files exist:

  • C:\\Windows\\System32\\drivers\\vmhgfs.sys
  • C:\\Windows\\System32\\drivers\\vmmemctl.sys
  • C:\\Windows\\System32\\drivers\\vmmouse.sys
  • C:\\Windows\\System32\\drivers\\vmrawdsk.sys
  • C:\\Windows\\System32\\drivers\\VBoxGuest\.sys
  • C:\\Windows\\System32\\drivers\\VBoxMouse.sys
  • C:\\Windows\\System32\\drivers\\VBoxSF.sys
  • C:\\Windows\\System32\\drivers\\VBoxVideo.sys

If any of these conditions are satisfied, BluStealer will stop executing.

.NET Component

The BluStealer retrieves the .NET payload(s) from the resource section and decrypts it with the above WinZip AES algorithm using a hardcoded key. Then it executes one of the following command-line utilities to launch the .NET executable(s):

  • C:\Windows\Microsoft.NET\\Microsoft.NET\\Framework\\v4.0.30319\\AppLaunch.exe
  • C:\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\InstallUtil.exe
Examples of two .NET executables loaded by the VB core. The stolen credentials are written to β€œcredentials.txt”

The .NET component does not communicate with the VB core in any way. It steals the credentials of popular browsers and applications then writes them to disk at a chosen location with a designated filename (i.e credentials.txt). The VB core will look for this drop and exfiltrate it later on. This mechanic is better explained in the next section.

The .NET component is just a copypasta of open-source C# projects listed below. You can find more information on their respective Github pages:

  • ThunderFox: github.com/V1V1/SharpScribbles
  • ChromeRecovery: github.com/Elysian01/Chrome-Recovery
  • StormKitty: github.com/swagkarna/StormKitty
  • Firepwd:github.com/lclevy/firepwdΒ 

Information Stealer

Both the VB core and the .NET component write stolen information to the %appdata%\Microsoft\Templates folder. Each type of stolen data is written to a different file with predefined filenames. The VB core sets up different timers to watch over each file and keeps track of their file sizes. When the file size increases, the VB core will send it to the attacker.

Handler Arbitrary filename Stolen Information Arbitrary Timers(s)
.NET component credentials.txt Credentials stored in popular web browsers and applications, and system profiling info 80
.NET component Cookies.zip Cookies stored in Firefox and Chrome browsers 60
VB Core CryptoWallets.zip Database files that often contain private keys of the following crypto wallet:Β  ArmoryDB, Bytecoin, Jaxx Liberty, Exodus, Electrum, Atomic, Guarda, Coinomi 50
VB Core FilesGrabber\\Files.zip Document files (.txt, .rtf, .xlxs, .doc(x), .pdf, .utc) less than 2.5MB 30
VB Core Others Screenshot, Keylogger, Clipboard data 1 or None

BluStealer VB core also detects the crypto addresses copied to the clipboard and replaces them with the attacker’s predefined ones. Collectively it can support the following addresses: Bitcoin, bitcoincash, Ethereum, Monero, Litecoin.

Data Exfiltration

BluStealer exfiltrates stolen data via SMTP (reusing SpyEx’s code) and Telegram Bot, hence the lack of server-side code. The Telegram token and chat_id are hardcoded to execute the 2 commands: sendDocument and sendMessage as shown below

  • https://api.telegram.org/bot[BOT TOKEN]/sendMessage?chat_id=[MY_CHANNEL_ID]&text=[MY_MESSAGE_TEXT]
  • https://api.telegram.org/bot[BOT TOKEN]/sendDocument?chat_id=[MY_CHANNEL_ID]&caption=[MY_CAPTION]

The SMTP traffic is constructed using Microsoft MimeOLE specifications

Example of SMTP content

.NET Loader Walkthrough

This .NET Loader has been used by families such as Formbook, Agent Tesla, Snake Keylogger, Oski Stealer, RedLine, as well as BluStealer.

Demo sample: 19595e11dbccfbfeb9560e36e623f35ab78bb7b3ce412e14b9e52d316fbc7acc

First Stage

The first stage of the .NET loader has a generic obfuscated look and isn’t matched by de4dot to any known .NET obfuscator. However, one recognizable characteristic is the inclusion of a single encrypted module in the resource:

By looking for this module’s reference within the code, we can quickly locate where it is decrypted and loaded into memory as shown below

Prior to loading the next stage, the loader may check for internet connectivity or set up persistence through the Startup folder and registry run keys. A few examples are:

  • C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\chrome\chrom.exe
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\chrom
  • C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\paint\paint.exe
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\paint
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Startup
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Startup
  • C:\Users\*\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\note\notepad.exe

In the samples we looked at closely, the module is decrypted using RC4, with a hardcoded key. The key is obfuscated by a string provider function. The best way to obtain the payload is to break at the tail jump that resides within the same namespace where the encrypted module is referenced. In most cases, it usually is the call to the external function Data(). Below are examples from the different samples:

Second stage

Inside the Data() function of the second stage which has two strange resource files along with their getter functions

The second stage has the function calls and strings obfuscated, so the β€œAnalyze” feature may not be as helpful. However, there are two resource files that look out-of-place enough for us to pivot off. Their getter functions can be easily found in the Resources class of the Properties namespace. Setting the breakpoint on the Ehiuuvbfrnprkuyuxqv getter function 0x17000003 leads us to a function where it is gzip decompressed revealing a PE file.

Ehiuuvbfrnprkuyuxqv is decompressed with gzip

On the other hand, the breakpoint on the Ltvddtjmqumxcwmqlzcos getter function 0x17000004 leaves us in the middle of the Data() function, where all the function calls are made by passing a field into CompareComparator function that will invoke it like a method.

ComareComparator is used to invoke one of the argument

In order to understand what is going on, we have to know what functions these fields represent. From the experience working with MassLogger in the past, the field to method map file is likely embedded in the resource section, which in this case, β€œDic.Attr” naming is a strong tell.

Note that it is important to find out where these fields are mapped to, because β€œStep into” may not get us directly to the designated functions. Some of the mapped functions are modified during the field-method binding process. So when the corresponding fields are invoked, the DynamicResolver.GetCodeInfo() will be called to build the target function at run-time. Even though the function modification only consists of replacing some opcodes with equivalent ones while keeping the content the same, it is sufficient enough to obfuscate function calls during dynamic analysis.

Dic.Attr is interpreted into a field-method dictionary

The search of the β€œDic.Attr” string leads us to the function where the mapping occurs. The dictionary value represents the method token that will be bound, and the key value is the corresponding field. As for the method tokens start with 0x4A, just replace them with 0x6 to get the correct methods. These are the chosen ones to be modified for obfuscation purposes.

With all the function calls revealed, we can understand what’s going on inside the Data() method. First, it loads a new assembly that is the decompressed Ehiuuvbfrnprkuyuxqv. Then, it tries to create an instance of an object named SmartAssembly.Queues.MapFactoryQueue. To end the mystery, a method called β€œRegisterSerializer” is invoked with the data of the other resource file as an argument. At this point, we can assume that the purpose of this function would be to decrypt the other resource file and execute it.

Heading to the newly loaded module (af43ec8096757291c50b8278631829c8aca13649d15f5c7d36b69274a76efdac), we can see the SmartAssembly watermark and all the obfuscation features labeled as shown below.

Overview of the decompressed Ehiuuvbfrnprkuyuxqv. Here you can find the method RegisterSerializer locates inside SmartAssembly.Queues.MapFactoryQueue

The unpacking process will not be much different from the previous layer but with the overhead of code virtualization. From static analysis, our RegisterSerializer may look empty but once the SmartAssembly.Queues class is instantiated the method will be loaded properly:

The function content when analyzed statically.
The function content after instantiated. Note that argument β€œres” represents the data of the second resource file
Fast forward to where res is processed inside RegisterSerializer()

Lucky for us, the code looks fairly straightforward. The variable β€œres” holding the encrypted data and is passed to a function that RulesListener.IncludeState represents. Once again, the key still is to find the field token to method token map file which is likely to be located in the resource section. This time searching for the GetManifestResourceStream function will help us quickly get to the code section where the map is established:

The resource file Params.Rules is interpreted into a field-method dictionary

RulesListener.IncludeState has token 0x04000220 which is mapped to function 0x60000A3. Inside this function, the decryption algorithm is revealed anticlimactically: reversal and decompression:

Data from Ltvddtjmqumxcwmqlzcos is reversed
Then it is decompressed and executed

In fact, all the samples can be unpacked simply by decompressing the reversed resource file embedded in the second stage. Hopefully, even when this algorithm is changed, my lengthy walkthrough will remain useful at showing you how to defeat the obfuscation tricks.

Conclusion

In this article, we break down BluStealer functionalities and provide some utilities to deobfuscate and extract its IOCs. We also highlight its code reuse of multiple open-source projects. Despite still writing data to disk and without a proper C2 functionality, BluStealer is still a capable stealer. In the second half of the blog, we show how the BluStealer samples and other malware can be obtained from a unique .NET loader. With these insights, we hope that other analysts will have an easier time classifying and analyzing BluStealer.

IOCs:

The full list of IoCs is available atΒ https://github.com/avast/ioc/tree/master/BluStealer

BluStealer

SHA-256

678e9028caccb74ee81779c5dd6627fb6f336b2833e9a99c4099898527b0d481
3151ddec325ffc6269e6704d04ef206d62bba338f50a4ea833740c4b6fe770ea
49da8145f85c63063230762826aa8d85d80399454339e47f788127dafc62ac22
7abe87a6b675d3601a4014ac6da84392442159a68992ce0b24e709d4a1d20690

Crypto Address List

Bitcoin:
1ARtkKzd18Z4QhvHVijrVFTgerYEoopjLP (1.67227860 BTC)
1AfFoww2ajt5g1YyrrfNYQfKJAjnRwVUsX (0.06755943 BTC)
1MEf31xHgNKqyB7HEeAbcU6BhofMdwLE3r
38atNsForzrDRhJoVAhyXsQLqWYfYgodd5
bc1qrjl4ksg5h7p70jjtypr8s6cjpngzd3kerfj9rt
bc1qjg3y4d4t6hwg6h22khknlxcstevjg2qkrxt6qu
1KfRWVcShzwE2Atp1njogAqH8qodsif3pi
3P6JnvWtubxbCxgPW7GAAj8u6CLV2h9MkY
13vZcoMYRcKrDRDYUyH9Cd4kCRMZVjFkyn

Bitcoincash:
qrej5ltx0sgk5c7aygdsvt2gh7fq04umvusxhxl7wq
qrzakt59udz893u2uuwtgrwrjj9dhtk0gc3m4m2sj5

Ethereum:
0xd070c48cd3bdeb8a6ca90310249aae90a7f26303 (0.10 ETH)
0x95d3763546235393B77aC188E5B08dD4Af68d89D
0xcfE71c720b7E99e555c0e98b725919B7a69f8Bb0

Monero.address:
46W5WHQG2B1Df9uKrkyuhoLNVtJouMfPR9wMkhrzRiEtD2PmdcXMvQt52jQVWKXUC45hwYRXhBYVjLRbpDu8CK2UN2xzenr
43Q4G9CdM3iNbkwhujAQJ7TedSLxYQ8hJJHYqsqns7qz696gkPgMvUvDcDfZJ7bMzcaQeoSF86eFE2fL9njU59dQRfPHFnv

Litecoint address:
LfADbqTZoQhCPBr39mqQpf9myUiUiFrDBG
LY5jmjdFnvgFjJET2wX5fVV6Gv89QdQRv3

Telegram Tokens:


1901905375:AAFoPAvBxaWxmDiYbdJWH-OdsUuObDY0pjs
1989667182:AAFx2Rti45m06IscLpGbHo8v4659Q8swfkQ

SMTP

[email protected] (smtp.1and1.com)
[email protected] (mail.starkgulf.com )
[email protected] (mail.bojtai.club)
[email protected] (smtp.ionos.es)
[email protected]
[email protected] (shepherd.myhostcpl.com)
[email protected] (mail.farm-finn.com)
[email protected] (mail.starkgulf.com)

.NET Loader SHA-256:

ae29f49fa80c1a4fb2876668aa38c8262dd213fa09bf56ee6c4caa5d52033ca1
35d443578b1eb0708d334d3e1250f68550a5db4d630f1813fed8e2fc58a2c6d0
097d0d1119fb73b1beb9738d7e82e1c73ab9c89a4d9b8aeed35976c76d4bad23
c783bdf31d6ee3782d05fde9e87f70e9f3a9b39bf1684504770ce02f29d5b7e1
42fe72df91aa852b257cc3227329eb5bf4fce5dabff34cd0093f1298e3b5454e
1c29ee414b011a411db774015a98a8970bf90c3475f91f7547a16a8946cd5a81
81bbcc887017cc47015421c38703c9c261e986c3fdcd7fef5ca4c01bcf997007
6956ea59b4a70d68cd05e6e740598e76e1205b3e300f65c5eba324bebb31d7e8
6322ebb240ba18119193412e0ed7b325af171ec9ad48f61ce532cc120418c8d5
9f2bfedb157a610b8e0b481697bb28123a5eabd2df64b814007298dffd5e65ac
e2dd1be91c6db4b52eab38b5409b39421613df0999176807d0a995c846465b38

The post BluStealer: from SpyEx to ThunderFox appeared first on Avast Threat Labs.

  • There are no more articles
❌