What We Do
How We Do
Resources
Company
Partners
Get Started
Blog

Bored BeaverTail & InvisibleFerret Yacht Club – A Lazarus Lure Pt.2

BY eSentire Threat Response Unit (TRU)

November 14, 2024 | 13 MINS READ

Want to learn more on how to achieve Cyber Resilience?

TALK TO AN EXPERT

Adversaries don’t work 9-5 and neither do we. At eSentire, our 24/7 SOCs are staffed with Elite Threat Hunters and Cyber Analysts who hunt, investigate, contain and respond to threats within minutes.

We have discovered some of the most dangerous threats and nation state attacks in our space – including the Kaseya MSP breach and the more_eggs malware.

Our Security Operations Centers are supported with Threat Intelligence, Tactical Threat Response and Advanced Threat Analytics driven by our Threat Response Unit – the TRU team.

In TRU Positives, eSentire’s Threat Response Unit (TRU) provides a summary of a recent threat investigation. We outline how we responded to the confirmed threat and what recommendations we have going forward.

Here’s the latest from our TRU Team…

What did we find?

In October 2024, the eSentire Threat Response Unit (TRU) responded to an incident where a software developer downloaded a JavaScript project that contained BeaverTail malware. Upon installing the project through the Node Package Manager (NPM) command, it executed malicious JavaScript files and subsequently deployed the InvisibleFerret malware to the host. The InvisibleFerret malware was executed through a Python command, which fingerprinted the host's information and stole the browser's credentials.

In response, our team of 24/7 SOC Cyber Analysts responded by isolating the impacted host and alerting the customer with the relevant details.

Upon further investigation by eSentire’s TRU team, it was determined that the observed Tactics, Techniques, and Procedures (TTPs) were consistent with those reported to be used by North Korea threat actors, also tracked as Contagious Interview.

Initial Access

A ZIP file named 'task-space-eshop-aeea6cc51a7c.zip' was found in the user's download directory. eSentire Threat Intelligence team assesses the chances as probable that the victim downloaded the zip from a BitBucket project named “eshop” (Figure 1).

Figure 1 eshop project hosted on Bitbucket.
Figure 1 eshop project hosted on Bitbucket.

The malicious “eshop” repository was committed by the user “francesco zaid” (Figure 2).

Figure 2 Author “francesco zaid” (screenshot taken October 24th, 2024).
Figure 2 Author “francesco zaid” (screenshot taken October 24th, 2024).

The commits to eshop occurred roughly five days after a job posting for a freelancer was published on a freelance job board. The job was posted by a user named “francesco zaid” on the “www.freelancermap[.]com” (Figure 3).

Figure 3 Possible Fake Job posting associated with the Contagious Interview Campaign.
Figure 3 Possible Fake Job posting associated with the Contagious Interview Campaign.

It should be noted that the eSentire Threat Intelligence team reviewed the job posting and was unable to find a direct link to the eshop repository from the posting; however, given the contact person’s name being the same name used to upload content to the repository, it is a notable finding and is consistent with the Contagious Interview campaign Tactics, Techniques and Procedures (TTPs) of luring software developers with fraudulent jobs.

The victim in the incident eSentire responded to appears to be a software developer, which aligns with the TTPs of previously reported on campaigns by North Korean threat actors where software developers were targeted.

Execution Chain

The ZIP file downloaded by the victim contained a malicious NPM package that once installed by the victim, executed “server.js” file that is defined in the “package.json” and subsequently, loads a malicious JavaScript file (error.js) (Figure 4).

Figure 4 “server.js” file was defined to be executed in the “package.json” file
Figure 4 “server.js” file was defined to be executed in the “package.json” file

The “server.js” file is used as an entry point to load the file located in “backend/middlewares/helpers/error.js”, which facilitates further malicious activities on the victim machine such as: steal saved login credentials in the browsers; collect system information; enumerates crypto wallet extensions in the targeted browsers; and, steal configuration data from crypto wallets like Exodus and Solana. This JavaScript file (error.js) is highly obfuscated and after analysis it was determined to be a component for the Beavertail malware (Figure 5).

Figure 5 Screenshot of ‘error.js’ found on the BitBucket Repository that is a component of BeaverTail.
Figure 5 Screenshot of ‘error.js’ found on the BitBucket Repository that is a component of BeaverTail.

After the JavaScript file is loaded, it uses a cURL command to download InvisibleFerret malware components from a command and control (C2) server; in this case the C2 was located at 185[.]235[.]241[.]208[:]1224. BeaverTail then downloads the initial Python script of InvisibleFerret. It is saved on the victim machine as “.sysinfo” file in the victim’s home directory (Figure 6).

Figure 6 Initial BeaverTail Python Script that Fetches InvisibleFerret.
Figure 6 Initial BeaverTail Python Script that Fetches InvisibleFerret.

Once the file “.sysinfo” is downloaded onto the machine, InvisibleFerret’s loader file “.sysinfo” is then executed with the command “C:\Users\{username}\.pyp\python.exe" "C:\Users\{username}/.sysinfo”. It’s worth noting that this observation is different from what was reported by Unit 42 where the initial Python script was named “.npl”.

It’s also worth noting that a total of 21 crypto extensions were targeted by the BeaverTail in our observed sample; the full list can be found in the Appendix at the end of the blog (Figure 7).

Figure 7 Crypto Wallet Browser Extensions Targeted by BeaverTail.
Figure 7 Crypto Wallet Browser Extensions Targeted by BeaverTail.

Analysis of InvisibleFerret Python Files

The eSentire Threat Intelligence team conducted analysis of four Python files that were dropped in the incident; one loader (.sysinfo in this instance) and three payloads stored under “\.n2” folder in the user’s home directory (Figure 8).

Table 1: Observed Invisible Ferret Python File Locations

Request URL

Note

Destination File Path (Windows)

hxxp[://]185[.]235[.]241[.]208:1224/client/99/29

HTTP request for InvisibleFerret Python Loader (client)

%USERPROFILE%\.sysinfo

hxxp[://]185[.]235[.]241[.]208:1224/payload/99/29

HTTP GET request for InvisibleFerret Component (Fingerprint, Remote Control, and Information Stealer Component)

%USERPROFILE%\.n2\pay

hxxp[://]185[.]235[.]241[.]208:1224/brow/99/29

HTTP GET request for InvisibleFerret Component (Browser Stealer Component)

%USERPROFILE%\.n2\bow

hxxp[://]185[.]235[.]241[.]208:1224/mclip/99/29

HTTP GET request for InvisibleFerret Component (Clipboard Stealer Component)

%USERPROFILE%\.n2\mlip

Loader Component Overview

Figure 8 Python Loader (.sysinfo) Parameters (commented line was included).
Figure 8 Python Loader (.sysinfo) Parameters (commented line was included).

It's worth noting that the internal IP address (10.10.51.212) was excluded from the initial loader script, but still reappears in the various InvisibleFerret python payloads (Figure 8). This suggests that the IP address may be used for testing purposes. Furthermore, our analysis revealed that excluded or commented-out code sections are a common trait of these scripts, potentially indicative of the malware's development or testing stages.

The sample downloads three distinct payloads which are appended with a campaign ID and sub ID (sType and gType respectively, as seen in Figure 8 above and Figure 9 below): pay_campaignid_subid.py; brow_campaignid_subid.py; and, mlip_campaignid_subid.py. On disk these files are saved to the %USERPROFILE%\.n2 path without these identifiers or file extensions (Figure 9).

Figure 9 InvisibleFerret Python Files.
Figure 9 InvisibleFerret Python Files.

Some of these files are obfuscated with a combination of zlib, base64 and reverse string order (Figure 10). The script loops through the lambda function continuously until the final cleartext payload is executed.

Figure 10 Payload Retrieval
Figure 10 Payload Retrieval

An overview of the three InvisibleFerret components can be found in the table below.

Table 2: InvisibleFerret Components

InvisibleFerret Component

Purpose

Notable Network Indicators

pay

Host Fingerprinting
File Stealer
Browser Credential Stealer
Remote Access
Deploys AnyDesk

hxxp://185.235.241[.]208:1224/uploads
hxxp://185.235.241[.]208:1224/keys
hxxp://185.235.241[.]208:1224/brow
hxxp://185.235.241[.]208:1224/adc
185.235.241[.]208:2245

brow

Browser credential stealer

hxxp://:185.235.241[.]208:1224/keys

mlip

Standalone clipboard stealer and keylogger targeting web browsers.

hxxp://95.164.7[.]171:8637/api/clip

“Pay” Component Overview

The pay component conducts various host fingerprinting activities including the internal IP, external IP, OS version, username and a number of other parameters (Figure 11). It also initiates a backdoor session with the C2 server and scans and uploads sensitive files from the infected host.

Figure 11 Host Fingerprinting functionality.
Figure 11 Host Fingerprinting functionality.

Once the fingerprinting activity is concluded, it is packaged up and exfiltrated via HTTP POST request to hxxp://185.235.241[.]208:1224/keys (Figure 12). The C2 IP address is de-obfuscated by shifting the first nine characters to the end of the string then base64 decoding the set.

Figure 12 Partial screenshot of pay_campaignid_subid.py exfil process (the commented line was left in by the author of the script)
Figure 12 Partial screenshot of pay_campaignid_subid.py exfil process (the commented line was left in by the author of the script)

On non-Windows systems, the script attempts to run the client instance by calling client.run().

On Windows systems, the main backdoor client is initiated alongside a keylogger and clipboard stealer which utilizes the pyHook, pythoncom and pyperclip Python libraries (Figure 13)

Figure 13 Initializing the backdoor and keylogger/clipboard stealer.
Figure 13 Initializing the backdoor and keylogger/clipboard stealer.

Captured keystrokes and clipboard data are written to the global “e_buf” variable then sent back to the C2 (via TCP connection to 185.235.241[.]208:2245) when the ssh_clip command is called within the backdoor session.

The backdoor session is defined within the Client (Figure 14), Session and Shell classes. It initiates a network connection over port 2245 to the C2 server using sockets and accepts JSON-formatted messages containing various commands shown below. Notably, it also calls an auto_up() function which in this sample initiates an automatic file upload. This sample also contained placeholder code for automatically dropping AnyDesk (as opposed to manually via the backdoor).

Figure 14 Client class which manages the overall connection logic and initiates a file upload (code formatting and inline comments added for clarity)
Figure 14 Client class which manages the overall connection logic and initiates a file upload (code formatting and inline comments added for clarity)

InvisibleFerret contains logic to scan for and upload files of interest from multiple operating systems. Various functions in the script expedite identification of noteworthy files:

As each file is processed, the script checks if the file name contains any of these patterns:

[
'.env', 'config.js', 'secret', 'metamask', 'wallet', 'private', 'mnemonic', 'password', 'account', '.xls', '.xlsx', '.doc', '.docx', '.rtf', '.txt', 'recovery'
]

If the file is not a common document type, additional filtering is performed using ismnemonic and in_pk to target sensitive file content such as private keys. This is noteworthy given developers (likely those involved in blockchain/crypto applications) are targeted. Any system found infected with InvisibleFerret should assume these keys are compromised and take appropriate action.

Files are uploaded to hxxp://185.235.241[.]208:1224/uploads. Filenames are prepended with the current time and the hostname is prepended with the subid “29”, as seen in Figure 15.

Figure 15 Example HTTP headers from auto_upload activity.
Figure 15 Example HTTP headers from auto_upload activity.

A record of uploaded files is kept within the flist file contained within the .n2 directory. While it’s a notable forensic artifact, since this file can be arbitrarily cleared, it should not be considered a reliable record of exfiltrated files.

As has been documented by other researchers, the backdoor component contains 8 commands which are briefly outlined below.

ssh_obj

ssh_cmd

ssh_clip

ssh_run

ssh_upload

ssh_kill

ssh_any

ssh_env

“Brow” Component Overview

This InvisibleFerret component is a cross-platform browser infostealer targeting Windows, Linux and MacOS operating systems. It targets Chrome, Brave, Opera, Yandex and MsEdge browsers, uploading sensitive data to hxxp://:185.235.241[.]208:1224/keys (Figure 16).

Each OS type initializes its own class, which is inherited[BZ19] from the ChromeBase class. Each class provides instructions for decrypting browser-stored passwords on Windows, Linux and MacOS operating systems.

Figure 16 Browser infostealer. Comments from original author.
Figure 16 Browser infostealer. Comments from original author.

The script contains functionality to retrieve, decrypt and upload stored browser passwords, credit cards using methods commonly found in infostealing malware (Figure 17).

Figure 17 Snippet of credential stealing code. Original comments are from the script author(s).
Figure 17 Snippet of credential stealing code. Original comments are from the script author(s).

“Mlip” (Mclip) Component Overview

The third payload contains a standalone keylogger and clipboard stealer implemented in Python using the pyWinhook, psutil, pywin32 and wx libraries. The sample analyzed targeted Chrome and Brave browsers, uploading stolen data to hxxp://95.164.7[.]171:8637/api/clip (Figure 18).

Figure 18 Data upload structure in Mlip Python script.
Figure 18 Data upload structure in Mlip Python script.

The primary function OnKeyBoardEvent (Figure 19) is triggered by a keyboard event handler via the HookManager from the pyWinhook library. When a keypress is detected, this function is called and will check the active window process pid, process name and window name via the act_win_pn() function using the win32gui library. If the process name matches a browser ("chrome.exe", "brave.exe"), it proceeds.

Figure 19 OnKeyboardEvent funtion in mlip file.
Figure 19 OnKeyboardEvent funtion in mlip file.

If the caption of the active window is empty (indicating no specific page title or a blank tab), the function then proceeds to handle individual keystrokes for logging purposes.

The function checks for printable ASCII characters [PC20] and uses several modifiers to handle special keypresses such as CTL or enter. For example, when enter is pressed, it’s formatted as a newline character to break up the text and make it easier to process by the operator. If CTL + V is detected (signifying data being pasted into the browser), the GetTextFromClipboard() function is triggered. Data is appended to the key_log variable until a newline character is detected.

If a newline character is detected (“\n”) and the key_log is not empty, the save_log() function is triggered, uploading the data to the C2 and clearing the log. If the window caption changes, the accumulated logs are also uploaded and cleared.

GetTextFromClipboard Function

The script appears to use the the wx (wxPython) library to handle clipboard operations. It initializes a new instance of wx.Clipboard, checks that the clipboard data is text (to avoid images or binaries) then uploads it to the C2 using the save_log() function shown in Figure 20. Interestingly, it can check the clipboard for private keys and mnemonic phrases, but that line was commented out in this sample.

Figure 20 GetTextFromClipboard function.
Figure 20 GetTextFromClipboard function.

A quick test with the wx library shows clipboard data can be extracted with a simple Python script:

Figure 21 Screenshot testing whether clipboard data can be extracted through a python script
Figure 21 Screenshot testing whether clipboard data can be extracted through a python script

What did we do?

What can you learn from this TRU Positive?

Recommendations from the Threat Response Unit (TRU):

Indicators of Compromise

You can access the indicators of compromise here.

References

Appendix – Crypto Wallet Extensions Targeted by BeaverTail

Browser Extension ID

Browser Extesion Name

Target Browser

nkbihfbeogaeaoehlefnkodbefgpgknn

MetaMask

Chrome

ejbalbakoplchlghecdalmeeeajnimhm

MetaMask

Edge

fhbohimaelbohpjbbldcngcnapndodjp

BNB Chain Walle

Chrome

ibnejdfjmmkpcnlpebklmnkoeoihofec

TronLink

Chrome

bfnaelmomeimhlpmgjnjophhpkkoljpa

Phantom

Chrome

aeachknmefphepccionboohckonoeemg

Coin98 Wallet

Chrome

hifafgmccdpekplomjjkcfgodnhcellj

Crypto[.]com

Chrome

jblndlipeogpafnldhgmapagcccfchpi

Kaia Wallet

Chrome

acmacodkjbdgmoleebolmdjonilkdbch

Rabby Wallet

Chrome

dlcobpjiigpikoobohmabehhmhfoodbb

Argent X

Chrome

mcohilncbfahbmgdjkbpemcciiolgcge

OKX Wallet

Chrome

agoakfejjabomempkjlepdflaleeobhb

Core

Chrome

omaabbefbmiijedngplfjmnooppbclkk

Tonkeeper

Chrome

aholpfdialjgjfhomihkjbmgjidlcdno

Exodus Web3 Wallet

Chrome

nphplpgoakhhjchkkhmiggakijnkhfnd

TON Wallet

Chrome

penjlddjkjgpnkllboccdgccekpkcbin

OpenMask

Chrome

lgmpcpglpngdoalbgeoldeajfclnhafa

SafePal

Chrome

fldfpgipfncgndfolcbkdeeknbbbnhcc

MyTonWallet

Chrome

bhhhlbepdkbapadjdnnojkbgioiodbic

Solflare Wallet

Chrome

gjnckgkfmgmibbkoficdidcljeaaaheg

Atomic Wallet

Chrome

afbcbjpbpfadlkmhmclhkeeodmamcflc

Math Wallet

Chrome

eSentire Unit
eSentire Threat Response Unit (TRU)

The eSentire Threat Response Unit (TRU) is an industry-leading threat research team committed to helping your organization become more resilient. TRU is an elite team of threat hunters and researchers that supports our 24/7 Security Operations Centers (SOCs), builds threat detection models across the eSentire XDR Cloud Platform, and works as an extension of your security team to continuously improve our Managed Detection and Response service. By providing complete visibility across your attack surface and performing global threat sweeps and proactive hypothesis-driven threat hunts augmented by original threat research, we are laser-focused on defending your organization against known and unknown threats.

Read the Latest from eSentire