Busted programs outshine gold: a novel macOS backdoor pilfers crypto wallets
Just about a month back, we stumbled upon some compromised applications floating around on various illicit websites, which were infected with a Trojan proxy. These cyber troublemakers had cleverly repackaged pre-compromised apps into PKG files, embedding them with a Trojan proxy and a script that would initiate the infection after installation. Not long ago, we spotted a new macOS malware family, which until now was unknown, and it was hitching a ride on these compromised software. This threat turned out to be much more powerful than just an unauthorized proxy server installation.
Phase 1: The Activator.app
The specimens we discovered were able to effectively operate on macOS Ventura 13.6 and subsequent versions. This implies that the culprits were solely aiming at users of the more recent operating system versions on both Intel chips and Apple silicon devices. The tampered disk images include a software called “Activator” and the app the user intends to set up. Launching/mounting the image yields a window featuring the installation guide.
Popup featuring setup guidelines
The directions ask the user to move the app into the /Applications/ folder and then initiate Activator. The latter appears rather simple: it’s only a PATCH button that shows a request for a password once pressed.
Window trigger and password field
Diving into the details immediately uncovered a fascinating discovery: the Resources folder in the application intriguingly housed a Python 3.9.6 installer along with an additional Mach-O file named ‘tool’. The primary Fat Mach-O file, aptly dubbed ‘GUI’, essentially activated the ‘PATCH’ button. When this button was clicked, it triggered two events.
Once operational, the instrument scrutinized the system for an already installed version of Python 3. If it didn’t spot one, it proceeded to install the version it had earlier copied onto /tmp/. Following this, it “adjusted” the acquired application: the instrument juxtaposed the initial 16 bytes of the altered executable with a sequence embedded within Activator and eliminated them if they happened to match:
Examining the initial 16 bytes of the program.
In a rather humorous twist, the application started functioning, seemingly hacked. The joke here was that the cyber culprits had manipulated pre-hacked versions of the app, adding just a few bytes to the start of the executable, which in turn disabled it. This forced users to kick off the Activator.
Phase 2: The Downloader
Once the “patching” process was finalized, it commenced the primary payload. The sample communicated with its Command and Control (C2) to access an encrypted script. It managed to obtain the C2 URL by joining words from two pre-set lists and integrating a random five-letter sequence as a tertiary domain name. Utilizing this URL, the sample issued a request to a DNS server, aiming to acquire a TXT record for the domain. This approach to connect to a Command-and-Control server and conceal activity within the traffic was quite unique and intriguing. It assured the payload’s download as the response message was sourced from the DNS server. TXT records can hold various domain specifics that the application might need, making such a request appear completely ordinary in itself.
In our research, we experimented with every imaginable permutation of the hardcoded terms, identical across all our samples, only to identify a single operational domain name: imohub[.]net. The precise third-tier domain name didn’t matter, as long as it was included in the request. The DNS server’s response comprised three TXT documents that the software subsequently processed to form a comprehensive message. Every record embodied a Base64-encoded cipher piece, with the first byte housing a sequence number that was discarded during composition. The cipher was encrypted using AES in CBC mode. When decrypted, the message revealed the subsequent Python script.
Prior to executing the program, the software underwent the subsequent procedures:
Terminating NotificationCenter operations
Initiate program script
Interpreting the deciphered code, it attempted to connect to apple-health[.]org every half minute and endeavored to download and run the subsequent script. The script was allotted a total of 14,400 seconds for execution, post which the operation was terminated and a fresh variant of the script was fetched.
Phase 3. Uncovering the Hidden Entrance
Initially, we were under the impression that the downloaded Python script had become obsolete because the apple-health[.]org command and control (C2) server was not reciprocating our attempts to interact. Nevertheless, after a period of trying, we were able to acquire a payload that was presented as an additional Python script. This, at last, unveiled the true intentions of the malware operators: the principal purpose of the script was to carry out random commands it received from the server. The way the command processing code was designed suggested that these instructions were delivered as additional Base64-encoded Python scripts.
Software that carries out input instructions
In addition to carrying out instructions, the script gathered the subsequent details and transferred them to the server:
During our probe, we found that the server notably didn’t return any instructions and eventually ceased to function. Consequently, we decided to re-download the third-stage Python script. Upon doing so, we discovered alterations in the new version. Specifically, the creators had modified the “metadata” located at the onset of the program. This metadata includes the C2 server IP address and domain name, along with the program’s GUID and version. It seemed these details were promptly updated within the script whenever the server IP address was altered, a change that occurred roughly every 10 to 20 minutes. Moreover, there were also modifications made to the operational code, which required human intervention (refer to the images below for more details).
Three iterations of the code are displayed together (from left to right: the initial version tagged as 18c564a5cc4b7414df8345a8bdce7418, followed by the second and third versions identified as f4282d7e32c7e8ab4e075c572ac43803 and 352f0d288e612e4f66c50aaf9214a81d respectively).
This implied that the malicious software operation was still under development. The instructions we’ve been attempting to retrieve from the server might not even have been composed yet.
Phase 4. The Trusty Cryptostealer
Besides the previously mentioned attributes, the code held two more significant functions: verify_exodus_and_hash() and confirm_btccore_and_hash().
Script that fetches a compromised Exodus wallet
The spotlight was on the domain apple-analyser[.]com in both instances, acting as the base for additional payloads. The dual functions shared a common objective: to verify the presence of an appropriate cryptowallet application in the device, and if found, substitute it with a version downloaded from apple-analyser[.]com. Along with the application, a pristine version of the Electron framework, essential for initiating a “fresh” version of Exodus, was also conserved on the server. Additionally, Exodus.scpt, visible in the above screenshot, was stored, which is indispensable for executing the subsequent Shell command when Exodus.app kicks off.
execute the shell script “~/electron/Electron.app/Contents/MacOS/Electron ~/exodus”
Could it be possible that the cyber attackers were actually assisting their victims in updating their wallets as a form of reparation? Regrettably, expecting such goodwill was rather innocent: both wallets were confirmed to be compromised.
The harmful individuals had compromised Exodus by incorporating their ingenious creation at the very start of the application: the main/index.js file, which was the initial one to boot up when the application was fired up.
Portion of the primary/index.js file that holds the harmful payload
The visual representation of the code revealed that the app dispatched data into the channel labeled 334b4425988b47a5b67c92518f9815c6, which later ended up at 22[.]imohub[.]workers[.]dev. So, our next mission was to pinpoint the specific part of the code responsible for this data transfer. Cue the drumroll… it’s wallet/index.js! The code was initially without any line breaks or indents, so we spruced it up with suitable formatting for a clearer understanding of its workings.
Components within wallet/index.js
The harmful culprits incorporated into the wallet unlock handler a prompt to a function, which straightforwardly delivered an input seed phrase to the Command and Control (C2) via the channel. No additional fresh features were observed.
Script that transmits information to the Command and Control center
Therefore, even without receiving instructions from the C2, the software could still wreak considerable havoc on the user by pilfering their digital currency wallets.
The previously discussed compromised applications serve as an easy gateway for harmful intruders to access individuals’ computers. All they need to do to increase their control is request the password, a step that often doesn’t raise any red flags for users during the software setup process. However, it’s worth noting the unique and clever strategies employed by the creators of this malware operation, such as embedding a Python script within a domain TXT record on the DNS server. Subsequently, this script was included in startup agents to repeatedly download and execute the following stage of the payload, allowing the malware administrators to consistently update the compromised machine. The concluding payload was a backdoor that had the ability to run any scripts with administrator access, and substitute Exodus and Bitcoin crypto wallet applications already installed on the computer with tainted versions. These infected versions would then stealthily steal secret recovery phrases as soon as the wallet was accessed.