← Home

🦹‍♀️

Analyzing a VIDAR Infostealer Sample

Published: 12/31/2022

Introduction

While reviewing samples submitted to Any.Run, I came across a binary that appeared to inject into a target process before performing some suspicious HTTP requests. After further analysis, this binary was found to be consistent with the VIDAR infostealer. This article aims to explain exactly how the infostealer works, the loader chain, what it attempts to steal, and how it exfiltrates data stolen from the host in a short time without leaving a trace.

Since this sample already had a dynamic, sandbox run within Any.Run, I decided to download a copy and attempt to reverse engineer it with the aim of understanding more about how it worked, what it was designed to do, and to attempt to identify the malware family.

The sample being analyzed in this post has the following file hashes:

  • MD5: 9BB9FD7110158BEA15B3EB3881C52606
  • SHA1: F545BF2A5E310ED8E9A8F553DA11B5C03D859A79
  • SHA256: F2FEEFF2C03FE54E6F8415390CFA68671576D4CA598C127B5C73B60864E7372B

 

The entire infection chain and malware operation can be summarized at a high level by this diagram:

malware diagram

About VIDAR

Although this is not unique to the VIDAR malware family, this infostealer performs a smash-and-grab approach to harvesting data by harvesting as much data from the host and exfiltrating as quickly as possible. Public reporting shows that delivery mechanisms for the VIDAR infostealer include fake software installers, Windows 11 installers and even malicious Microsoft help files delivered via phishing.

Since the service provided to the customers of VIDAR exists only to facilitate payload configuration, generation and C2, it is left to the customer to get the malware on to systems; whether themselves or via a third-party malware distribution service. An example of such a malware distribution service is a group Microsoft tracks as DEV-0569, who leverage techniques such as malvertising, phishing etc. to distribute BATLOADER; a separate malware designed to deliver additional payloads, including VIDAR, ROYAL ransomware and COBALT STRIKE.

 


Loader Analysis

Based on the sandbox run, the binary appears to spawn a child process instance of AppLaunch.exe, which is a legitimate binary and part of the .NET framework. The suspicious activity performed by the malware then appears to originate from this legitimate process, which is a good indicator that some form of process injection is occurring.

Initial Assessment

The binary being analyzed has the following characteristics:

  • MD5: 9BB9FD7110158BEA15B3EB3881C52606
  • SHA1: F545BF2A5E310ED8E9A8F553DA11B5C03D859A79
  • SHA256: F2FEEFF2C03FE54E6F8415390CFA68671576D4CA598C127B5C73B60864E7372B
  • Compiled Timestamp: Fri Dec 23 14:09:41 2022 UTC
  • Linker: Linker GNU linker ld (GNU Binutils)

The executable itself has very few imports, which indicates that there is some form of obfuscation going on to conceal the malware’s true purpose and functionality.

First Stage Loader

This first loader works by XOR decrypting at runtime both the second stage malware, and an additional loader shellcode, which loads the final stage payload. It then stores a pointer to the decrypted loader shellcode in the register edx, that was previously made executable using VirtualProtect. Next, it pushes the parameters to be passed to the loader function (consisting of a pointer to the decrypted second stage payload and a filepath to the injection target) on to the stack before executing it with a call edx instruction.

loader decryption routine

Second Stage Loader

The second stage loader performs the process injection to load the final stage payload into memory. In this case, it used a process hollowing but not really approach to injecting the VIDAR binary into an AppLaunch.exe process.

The process injection method uses the following sequence of API calls:

  • NtCreateUserProcess
  • VirtualAlloc
  • VirtualAllocEx
  • WriteProcessMemory
  • ResumeThread

 

Firstly, NtCreateUserProcess is called with the following arguments to spawn the process injection target in a suspended state.

ntcreateuserprocess arguments

NtCreateUserProcess is an undocumented function, however more information about this function can be found here, and has been well documented by security researchers. For the purposes of this loader, two important arguments are passed:

  • CreateThreadFlags, which is set to 0x01, and corresponds to starting the process in a suspended state.
  • ProcessParameters, which is a RTL_USER_PROCESS_PARAMETERS structure, and within it the image path C:\Windows\Microsoft.NET\Framework\v4.0.30319\AppLaunch.exe is provided.

 

Next, the loader calls both VirtualAlloc and VirtualAllocEx to allocate a region in the memory space of the target process for the final payload to be injected.

VirtualAlloc Arguments virtualalloc arguments

VirtualAllocEx Arguments virtualallocex arguments

As per the documentation for these functions, both calls pass in the same arguments. The only difference being that VirtualAlloc is not provided a lpAddress pointer, which results in the function returning a pointer to the allocated memory region, whereas the hProcess argument provided to VirtualAllocEx is 0x009C. Aside from those differences, the arguments provided to both functions are the same:

  • dwSize: 0x67000, which corresponds to 421888 bytes.
  • flAllocationType: 0x03000, which corresponds to both committing and reserving the address range in one step.
  • flProtect: 0x40, which corresponds to read, write and execute (RWX) permissions.

 

These API calls serve to allocate a region in memory for the target AppLaunch.exe process that is readable, writable and executable, which allows the loader to finally write the bytes for the finaly payload into this memory region within the target process using WriteProcessMemory. Finally, the injected process is then resumed from its suspended state using ResumeThread, which allows it to execute the injected payload.

Dumping the Injected Payload

Dumping the injected payload was straight forward using x32dbg. All that was needed was a breakpoint to be set to pause execution when the malware reaches the WriteProcessMemory call.

bp WriteProcessMemory
BOOL WriteProcessMemory(
  [in]  HANDLE  hProcess,
  [in]  LPVOID  lpBaseAddress,
  [in]  LPCVOID lpBuffer,
  [in]  SIZE_T  nSize,
  [out] SIZE_T  *lpNumberOfBytesWritten
);

WriteProcessMemoryArguments writeprocessmemory arguments

The arguments passed to WriteProcessMemory correspond to the following:

  • hProcess: 0x009C, which is the same process handle passed into the previous VirtualAllocEx function call.
  • lpBaseAddress: 0x00400000, which corresponds to the image base address in which the process memory is written.
  • lpBuffer: 0x02EA0000
  • nSize: 0x67000, which corresponds to the same 421888 bytes.

 

The argument of interest is lpBuffer, which is the pointer to the memory region containing the bytes to be written to the memory space of the new process.

memory map of buffer space

As shown, this memory region starts with a MZ header and DOS string, which means this memory region must contain the binary that is being injected into AppLaunch.exe. The final stage executable payload can then be retrieved by dumping the memory region to disk.

Realigning the Dumped PE

When viewing the dumped executable in PEBear, or CFF Explorer, both programs were unable to determine the presence of any imports used by the binary. This is actually because the PE recovered from memory was in a mapped format. This caused a misalignment of section offsets within the raw executable on disk and therefore resulted in a misaligned import address table (IAT). This video explains the concept far better than I can.

unreadable imports

Fortunately, we can edit the section table to unmap the sections within the executable and realign the IAT. By setting the raw address offsets to be equivalent to the virtual address offsets, and modifying the section sizes accordingly.

realigned section table

Now the executable has been correctly aligned, the module and function imports are now readable.

readable imports

Since we now have an unmapped exectable, it is possible to reverse engineer and analyze the resulting payload. In this case, the reconstructed executable is written in C++.


VIDAR Infostealer Analysis

Once the dumped payload has been realigned and otherwise fixed to become a valid portable executable, the second stage executable has the following characteristics:

  • MD5: 47a6959ac869f65dd31e65b1c80fa8b2
  • SHA1: f9d9ecf59523c202bca9ac4364b2a2042f116f32
  • SHA256: 1521e9e7b06676a62e30e046851727fe4506bdf400bcf705a426f0f98fba5701
  • Compiled Timestamp: Mon Dec 19 12:33:40 2022 UTC
  • Compiler: Microsoft Visual C/C++
  • Linker: Microsoft Linker 10.0 - (Visual Studio 2010)

 

Encrypted Strings & Module Imports

The VIDAR malware stores some of its strings, and module imports in a base64-encoded, RC4 encrypted format. By combining the different functions in the binary, along with the decrypted and decoded strings, we arrive at a full list of browser extensions targeted by the malware. These are mainly cryptocurrency wallets, but also include two factor authentication (2FA) extensions, and other password managers.

Before doing anything else, VIDAR first calls a built-in routine to base64-decode and RC4 decrypt each string before writing it into a memory region. A pointer to each string and module import can then be referenced by the malware to use them.

The malware leverages the BCryptDecrypt API call to decode base64, and a custom-coded RC4 decryption function.

Cryptocurrency wallets and 2FA browser extensions and applications targeted by VIDAR

TronLink
MetaMask
BinanceChainWallet
Yoroi
NiftyWallet
MathWallet
Coinbase
Guarda
EQUALWallet
JaxxLiberty
BitAppWallet
iWallet
Wombat
MewCx
GuildWallet
RoninWallet
NeoLine
CloverWallet
LiqualityWallet
Terra_Station
Keplr
Sollet
AuroWallet
PolymeshWallet
ICONex
Harmony
Coin98
EVER Wallet
KardiaChain
Trezor Password Manager
Rabby
Phantom
BraveWallet
Oxygen (Atomic)
PaliWallet
BoltX
XdefiWallet
NamiWallet
MaiarDeFiWallet
WavesKeeper
Solflare
CyanoWallet
KHC
TezBox
Temple
Goby
Authenticator
Authy
EOS Authenticator
GAuth Authenticator
Tronium
Trust Wallet
Exodus Web3 Wallet
Braavos
Enkrypt
OKX Web3 Wallet
Sender
Hashpack
Eternl
GeroWallet
Pontem Wallet
Petra Wallet
Martian Wallet
Finnie
Leap Terra
Microsoft AutoFill
Bitwarden
KeePass Tusk
KeePassXC-Browser
Bitwarden
Ethereum\Ethereum\
Electrum\Electrum\wallets\
ElectrumLTC\Electrum-LTC\wallets\
Exodus\exodus\conf.json,window-state.json
\Exodus\exoduswallet\passphrase.json,seed.seco,info.seco
ElectronCash\ElectronCash\wallets\default_wallet
MultiDoge\MultiDoge\multidogewallet
Jaxx_Desktop_Old\jaxx\Local Storage\file__0localstorage
Binance\Binance\app-store.json
Coinomi\Coinomi\wallets\
*wallets
*config
wallet_path
SOFTWARE\monero-project\monero-core,\Monero\

Also encrypted in the binary are the SQL queries used to harvest data stored in web browsers:

SQL queries used by VIDAR to harvest browser data

SELECT origin_url, username_value, password_value FROM logins
SELECT name, value FROM autofill
SELECT name_on_card, expiration_month, expiration_year, card_number_encrypted FROM credit_cards
SELECT target_path, tab_url from downloads
SELECT url FROM urls
SELECT HOST_KEY, is_httponly, path, is_secure, (expires_utc/1000000)-11644480800, name, encrypted_value from cookies

In addition, one of the encrypted strings, C:\ProgramData\ is the staging directory used by the malware when it downloads additional libraries and stages data for exfiltration. This staging directory appears to be consistent across all VIDAR samples.

Retrieving C2 Servers

The malware stores its C2 servers in an unencrypted format within the binary:

  • hxxps://t[.]me/traduttoretg
  • hxxps://steamcommunity[.]com/profiles/76561199445991535
  • hxxp://5.75.253[.]16:80

 

Interestingly, the VIDAR malware leverages legitimate services to host C2 configuration data. For example, the Telegram and Steam profile links contain IP addresses, whereas the 5.75.253[.]16 appears to be consistent with threat actor infrastructure. This way, the malware operators can contiunously cycle C2 servers and have the malware beacon back to each new IP address so long as the social media profiles hosting the C2 IP address remain active.

steam profile telegram profile

This particular VIDAR sample uses the string grundic to identify where on the webpage the C2 address is, and grabs the string up until the ending | character.

Initial C2 Callback

Once the malware has retrieved a C2 IP address from one of the social media profiles hardcoded within the binary, it then submits a HTTP GET request containing the profile ID of the affiliate. Since the VIDAR malware is sold as an infostealer-as-a-service where the cybercriminal gains access to a control panel to configure and generate the malware, this ID is used to retrieve the configuration data set by the VIDAR customer. In this sample, the profile ID is 1375.

VIDAR configuration retrieved

1,1,1,1,1,36bfd46626a0b531909b016919dd1fbd,1,1,1,1,0,Default;%DOCUMENTS%\;*.txt;50;true;movies:music:mp3;desktop;%DESKTOP%\;*.txt:*.doc:*.docx:*.xlsx:*.xlsm:*.xls:*.pptx;950;true;movies:music:mp3:exe;

Downloading Additional Libraries

To be able to perform its full credential harvesting tasks, the VIDAR malware must download additional DLL libraries to extend its capability. For example, to interact with web browsers or use SQLite3.

In previous samples, the download of these additional libraries was achieved by sending a HTTP GET request to the C2 server for a ZIP file named with random alphanumeric characters. In an apparent change of technique, or configuration, this sample retrieves the additional libraries by downloading a resource from the C2 server named update.zip.

ida update.zip

Nevertheless, once the ZIP file containing the DLLs is downloaded, it is extracted and the DLL binaries are saved to the C:\ProgramData staging directory. The resource update.zip contained the following DLLs:

MD5 (freebl3.dll) = ef2834ac4ee7d6724f255beaf527e635
MD5 (libcurl.dll) = 37f98d28e694399e068bd9071dc16133
MD5 (mozglue.dll) = 8f73c08a9660691143661bf7332c3c27
MD5 (msvcp140.dll) = 109f0f02fd37c84bfc7508d4227d7ed5
MD5 (nss3.dll) = bfac4e3c5908856ba17d41edcd455a51
MD5 (softokn3.dll) = a2ee53de9167bf0d6c019303b7ca84e5
MD5 (sqlite3.dll) = e477a96c8f2b18d6b5c27bde49c990bf
MD5 (vcruntime140.dll) = 7587bf9cb4147022cd5681b015183046

Data Exfiltration

The harvested data is then sent back to the C2 server using a HTTP POST request.

IDA post

HTTP POST body

------1531306219445135
Content-Disposition: form-data; name="profile"

1375
------1531306219445135
Content-Disposition: form-data; name="profile_id"

1700
------1531306219445135
Content-Disposition: form-data; name="hwid"

d8d914bc22c31291311131-90059c37-1320-41a4-b58d-816d-806e6f6e6963
------1531306219445135
Content-Disposition: form-data; name="token"

36bfd46626a0b531909b016919dd1fbd
------1531306219445135
Content-Disposition: form-data; name="file"

UEsDBBQAAgAIAMSYl1XqxfupygAAAJMB...[truncated base64-encoded ZIP file]
------1531306219445135--

Interestingly, the token 36bfd46626a0b531909b016919dd1fbd matches the string contained within the initial config downloaded from the C2 server.

The data harvested from the host is stored within the ZIP file in the POST request body.

Directory structure of the ZIP file

/History/Mozilla Firefox_qldyz51w.default.txt
/Cookies/Google Chrome_Default.txt
/History/Google Chrome_Default.txt
/passwords.txt
/information.txt
/Files/Default.zip
/Files/desktop.zip
/screenshot.jpg

It is important to note that this is not an exhaustive list of what the ZIP file exfiltrated from every system will look like. It will depend on both the stealer configuration set by the threat actor during the payload generation stage, and the software present on the compromised system. For example, the sample analyzed in this writeup included routines for stealing Discord tokens, data from Telegram and even FTP and SCP clients.

Cleanup Operations

Once the data has been succesfully harvested and exfiltrated, the malware then deletes itself and any created files from the host with the following command:

"C:\Windows\System32\cmd.exe" /c timeout /t 6 & del /f /q "C:\Windows\Microsoft.NET\Framework\v4.0.30319\AppLaunch.exe" & exit

ida cmd