During routine detection maintenance, our Mac researchers stumbled upon a small set of files with backdoor capabilities that seem to form part of a more complex malware toolkit. The following analysis is incomplete, as we are trying to identify the puzzle pieces that are still missing.
As of now, these samples are still largely undetected and very little information is available about any of them. The earliest mention we could find is an anonymous April 18 upload on VirusTotal (IoC A), as well as the three samples (B through D) that seem to have been uploaded by the victim we worked with in the investigation.
IoC A seems very similar to IoC B and shares the same feature set. The only difference is the order of two Python imported libraries.
Two of the three isolated samples are generic backdoors written in Python that seem to target Mac OS, Windows and Linux-based operating systems.
To identify the victim’s operating system, the shared.dat backdoor has a routine that checks the OS, then returns 0 for Windows, 1 for macOS and 2 for Linux.
The first file identified is called shared.dat
and uses rot13 substitution to hide the values of specific file paths and strings. It also generates a unique device identifier for later use in requests to the command and control center.
Upon execution, the backdoor first generates the UID mentioned above. This UID is then used to name a temporary file (<uid>.dat
) The malware then enters a while True loop
where it attempts to communicate with a remote server using a custom packet format. These packets start with either GITHUB_RES
or GITHUB_REQ
+ the UID generated in the previous step. The backdoor supports four commands sent out as cmdType numbers by the remote server:
Code 501: Extract basic info
When the backdoor receives a cmdType 501 command, it extracts details such as Current Time
, Username
, Hostname
, OS Version
, as well as the results of the following commands:
ifconfig -a
and ps -ef
when executed on a Unix system;ipconfig /all
and tasklist /svc
when executed on a Windows machine.These details are also written to a file received as an argument – in our case, the file is called called b.dat
Code 502: CmdExec
The cmdExec function is apparently used to run a specific command provided as an argument using the subprocess.Popen
function. The request contains the command encoded as base64 and the results are encoded using the same method.
Code 503: DownExec
The DownExec routine behaves differently, based on the victim’s operating system. For MacOS devices, the function writes a file to /Users/Shared/AppleAccount.tgz
. The content that is written to the archive is also encoded as base64 when received from server. It unpacks the archive to the /Users/Shared
folder, then opens the /Users/Shared/TempUser/AppleAccountAssistant.app
application.
On Linux systems, the malware calls a dist_name
function that checks the /etc/os-release
to validate whether the victim distro is Debian, Fedora or anything else. The function writes some C code received from the C2 to a temporary file named tmp.c
, that is later compiled to a file named /tmp/.ICE-unix/git
using the cc
command on Fedora and gcc
on Debian. After compilation, the file is executed in background with two parameters, also received from C2.
Code 504: KillSelf
This function is self-explanatory and is used to just exit the script.
The sh.py (SHA-1 bd8626420ecfd1ab5f4576d83be35edecd8fa70e
) backdoor is also written in Python and has cross-platform capabilities. It stores its configuration options in the ~/Public/Safari/sar.dat
file after it encodes them to base64. The settings stored in this file include details such as UID, SleepCycleMin
, as well as two possible Server URLs. Much like the shared.dat
backdoor, sh.py
also generates and saves a UID (albeit a 9-digit one).
Unlike the shared.dat
backdoor, this one does not come with a hardcoded value for the C&C server. Instead, the value for the C&C can be provided as a parameter when running the script or can be loaded from the settings file.
In its main
function, the script communicates with the remote server using a while
loop and handles specific commands using the `process_command' function that can receive any of the following values as argument:
xs
, xsi
executes a command which is initially encoded as base64load_setting()
function and sends the current configuration to the server (from sar.dat
file), also encoded as base64SleepCycleMin
or ServerUrl
(2 elements array) using the save_settings functionThe backdoor also includes a 'get_basic_information' function that extracts specific details about the system, such as hostname
, username
, OS version
, Python version
and much more. When executed, the script attempts to connect to one of the two server URLs in order to send these details over. If the first URL is not available, it then attempts to contact the second one.
Unlike the previous two files, this third component is a FAT binary (a multi-architecture file) that contains Mach-O files for 2 architectures (x86 Intel
and ARM M1
). The xcc
binary is written in Swift and targets MacOS version 12 and newer. Its primary purpose is apparently to check permissions before using a potential spyware component (probably to capture the screen) but does not include the spyware component itself. This leads us to believe that these files are part of a more complex attack and that several files are missing from the system we investigated.
In addition to the xcc file uploaded on Jun 1st, we were able to isolate a second one dated June 6 (sample E in our IoC list). Unlike the “original” xcc file, this one only contains a Mach-O binary for the x86
architecture.
The xcc files have an ad-hoc signature, meaning that they are not associated with a recognized Apple Developer. The identifier of the file contains the keyword XProtectCheck
, as well as a path identified inside the file content, /Users/joker/Downloads/Spy/XProtectCheck/
which hints at the project’s purpose, as well as at the role of this component.
xcc checks for permissions managed by Apple's TCC (Transparency, Consent and Control), such as Full Disk Access
, Screen Recording
and Accessibility
. The latter is verified using "AXIsProcessTrusted" function, part of macOS Accessibility API, while the permission to capture the screen is obtained by calling CGPreflightScreenCaptureAccess()
. Also, the function getTopWindowApp
identifies the active app that the user currently interacts with using Apple's frontmostApplication
property.
Command and Control
The command-and-control server is hardcoded in the share.dat Python backdoor. The first reference to this domain dates back to February 10 2023, roughly around the same time it was mentioned in a series of Tweets related to an infected MacOS QR code reader (QRLog).
Detection
Bitdefender products flag the Python components as Trojan.Python.JokerSpy
. The Mach-O
binaries are detected as Trojan.MAC.JokerSpy
.
Files
ID | File Name | SHA-1 | Discovery Date | Detection Name |
---|---|---|---|---|
A | shared.dat | 937a9811b3e5482eb8f96832454723d59229f945 | Apr 18, 2023 | Trojan.Python.JokerSpy.B |
B | shared.dat | c7d6ede0f6ac9f060ae53bb1db40a4fbe96f9ceb | Jun 1, 2023 | Trojan.Python.JokerSpy.C |
C | sh.py | bd8626420ecfd1ab5f4576d83be35edecd8fa70e | Jun 1, 2023 | Trojan.Python.JokerSpy.A |
D | xcc (Mach-O) | 370a0bb4177eeebb2a75651a8addb0477b7d610b | Jun 1, 2023 | Trojan.MAC.JokerSpy.B |
E | xcc (FAT binary) | 1ed2c5ee95ab77f8e1c1f5e2bd246589526c6362 | Jun. 6, 2023 | Trojan.MAC.JokerSpy.A |
F | xcc (Mach-O) | 76b790eb3bed4a625250b961a5dda86ca5cd3a11 | Jun. 1, 2023 | Trojan.MAC.JokerSpy.C |
URLs:
https://www.git-hub.me/view.php
tags
I'm a Security Researcher at Bitdefender, always trying to be one step ahead of cybercriminals targeting Unix. I am passionate about exploring the world and staying active through sports.
View all postsJune 08, 2023
May 02, 2023
January 11, 2023
January 05, 2023