Recent reports from researchers at BitDefender and Elastic have exposed an active adversary deploying novel spyware, cross-platform backdoors and an open-source reconnaissance tool to compromise organizations with macOS devices in their fleets. Although the number of known victims at this time is small, the nature of the tooling suggests that the threat actors have likely targeted other organizations.
In this post, we review the key components and indicators used in the campaign to help raise awareness and aid security teams and threat hunters.
QRLog | Suspected Infection Vector
There is little information about how initial compromise was achieved in the known compromises, but analysis of the known components provide a strong link to a trojanized QR code generator discovered in the wild in February 2023.
According to researcher Mauro Eldritch, QRLog is a trojanized QR code generator written in Java that opens a reverse shell on the host device, allowing the attacker privileged access. The malicious code is hidden inside a file QRCodeWriter.java
, buried in an otherwise legitimate open source QR code project.
After determining the host device’s operating system, QRLog decodes an embedded base64 blob and writes it out to a temporary directory and executes it.
The decoded blob is a .java
file that reaches out to a C2 at hxxps[:]//www[.]git-hub.me/view.php
. This is the same C2 as used in the compromise reported by BitDefender (see below).
If the QRLog malware receives the right response from the C2, it then writes two further files – p.dat
and a Java executable prefTmp.java
– to the temp directory and executes the latter, which now opens the reverse shell from the victim to the attacker.
Shared.dat & sh.py | Cross-Platform Python Backdoors
In the intrusions seen to date, researchers identified two Python backdoors, shared.dat
and sh.py
. The former uses a simple rot13 string obfuscation technique.
The script’s behavior depends on the response from the server, whose address is hardcoded in plain text. In the intrusion seen by BitDefender, the C2 matched that seen in the QRLog malware. shared.dat
also uses the same strings found in QRLog to identify packets sent and received from the C2, namely “GITHUB_RES” and “GITHUB_REQ”.
A simple conditional parses the responses.
If the device is identified as a macOS device, the malware downloads and executes the next stage to /Users/Shared/AppleAccount.tgz
, which in turn decodes a further stage to /Users/Shared/TempUser/AppleAccountAssistant.app
.
The sh.py
backdoor is also multi-platform and requires a separate configuration file stored at ~/Public/Safari/sar.dat
, likely containing the C2 as well as other parameters. The C2 observed by Elastic in an attack on an unnamed Japanese cryptocurrency exchange was app.influmarket[.]org
.
The backdoor is capable of surveilling the host device and executing commands, exfiltrating data and deleting files.
Depending on the value received from the configuration file, the backdoor will beacon out to the C2 at regular intervals, the default being 5 seconds. Information sent to the attacker includes:
- Current working directory
- Username
- Hostname
- Domain name
- OS version
- Python version
- Path to sh.py
According to researchers at Elastic, the sh.py
script was seen dropping the open-source macOS red-teaming tool SwiftBelt to the file path /Users/shared/sb
and writing out to a file sb.log
in the same directory.
/bin/sh -c /users/shared/sb > /users/shared/sb.log 2>&1
JokerSpy | macOS Spyware Stager
In both intrusions seen to date, a further macOS only component was observed. The file, named “xcc”, attempts to hide as an XProtect component, and uses the Launch Services identifier com.apple.xprotectcheck
.
Identifier=XProtectCheck-55554944f74096a836b73310bd55d97d1dff5cd4 Format=Mach-O universal (x86_64 arm64) CodeDirectory v=20400 size=911 flags=0x2(adhoc) hashes=17+7 location=embedded Hash type=sha256 size=32 CandidateCDHash sha256=89706d1258b6f1c165ff8d1d6d13346e02b48e22 CandidateCDHashFull sha256=89706d1258b6f1c165ff8d1d6d13346e02b48e22d1a741ff451d1cb6ba81bab2 Hash choices=sha256 CMSDigest=89706d1258b6f1c165ff8d1d6d13346e02b48e22d1a741ff451d1cb6ba81bab2 CMSDigestType=2 Launch Constraints: None CDHash=89706d1258b6f1c165ff8d1d6d13346e02b48e22 Signature=adhoc Info.plist=not bound TeamIdentifier=not set Sealed Resources=none # designated => cdhash H"89706d1258b6f1c165ff8d1d6d13346e02b48e22" or cdhash H"9860c28299d58e71540c64e56c709aa619cfac27"
The binary is ad hoc signed and is built for both Apple silicon and Intel architectures. On execution, it runs through several functions with the purpose of determining:
- Device Idle Time
- Active (Frontmost) App
- Screen status (locked or unlocked)
- Full Disk Access of the active app
- Screen Recording permissions of the active app
- Accessibility (e.g., control other apps) permission of the active app
Threat hunters should note that these are somewhat noisily printed out to stdout
, so will appear in system logs.
The inclusion of the SystemIdleTime()
function is interesting and not something commonly seen in macOS malware. This may indicate the threat actor intends to establish a pattern of behavior as to when the user is inactive in order to time attacks. The function itself uses Apple’s IOServiceMatching()
api and the now deprecated IOHIDSystem class to query for the HIDIdleTime
value, a timer which tracks the last time the user interacted with the mouse, trackpad or keyboard, among other things.
At the time of writing, it’s not clear how the xcc
binary relates to the other components, other than that they have been observed together in both instances. xcc itself provides functionality for system discovery and it is likely there are further associated spyware and backdoor components that remain to be discovered.
Elastic observed xcc being executed by three different processes:
- /Applications/IntelliJ IDEA.app/Contents/MacOS/idea
- /Applications/iTerm.app/Contents/MacOS/iTerm2
- /Applications/Visual Studio Code.app/Contents/MacOS/Electron
The researchers suggest that initial access may have been provided via a malicious plugin or dependency that may have been trojanized in a similar way to QRLog mentioned above.
SentinelOne Detects JokerSpy
The SentinelOne agent protects customers from JokerSpy, QRLog and other malicious components identified in these attacks.
Security teams not protected by SentinelOne are advised to refer to the list of indicators below for threat hunting and detection.
Conclusion
The JokerSpy intrusions reveal a threat actor with the ability to write functional malware across several different languages – Python, Java, and Swift – and target multiple operating systems platforms. The relative sophistication of the multiple components suggests one or more developers devoting considerable effort to the project, and we can only surmise that further victims are out there.
There are still several pieces of the puzzle missing, but the intrusion into a large cryptocurrency exchange indicates a financially-motivated threat actor. SentinelOne continues to track this threat actor and will provide updates to this post as they become available.
Indicators of Compromise
Identifiers
com.apple.xprotectcheck
Communications
45[.]76[.]238[.]53
45[.]77].]123].]18
www[.]git-hub.me
app.influmarket[.]org
Files (SHA1)
1ed2c5ee95ab77f8e1c1f5e2bd246589526c6362 – xcc
1f99081affd7bef83d44e0072eb860d515893698 – SwiftBelt
21ffda8a6a05a007ef92088f99ab54485cfe473d – xcc
2234c9fc3c3d340f0367c49c6599379b96544b5a – QRCodeWriter.java
370a0bb4177eeebb2a75651a8addb0477b7d610b – xcc
76b790eb3bed4a625250b961a5dda86ca5cd3a11 – xcc
937a9811b3e5482eb8f96832454723d59229f945 – shared.dat
bd8626420ecfd1ab5f4576d83be35edecd8fa70e – sh.py
c304aef96a783a39aedf1af30de5d5f1c33c68ca – QRLog sample.zip
c7d6ede0f6ac9f060ae53bb1db40a4fbe96f9ceb – shared.dat
Paths
$TEMP/p.dat $TEMP/prefTmp.java ~/Public/Safari/sar.dat /Users/shared/sb /Users/shared/sb.log /Users/Shared/AppleAccount.tgz /Users/Shared/TempUser/AppleAccountAssistant.app