SOCLIFE
SOCLIFE

Evidence-led security analysis

Published knowledge

Search SOC//LIFE

HuntsHUNT-010

Hypothesis-led threat hunting

Hunt for MacSync Collection and Chunked Exfiltration

Hunts MacSync behavior across shell retrieval, AppleScript, credential collection, temporary staging, chunked curl upload, and post-transfer cleanup.

Question

Hunt goal

One or more managed Macs may have executed a ClickFix-style shell chain that collected credentials and sensitive files, staged them under temporary paths, and exfiltrated chunked data through rotating web infrastructure.

Why this hunt

Microsoft connected more than thirty domains by requiring multiple endpoint and network behaviors to align. The hunt follows the same behavior-first model rather than starting from a static IOC list.

Data sources

Where to look

  • EndpointDevice inventory used to restrict analytics to current macOS endpoints.
  • ProcessEndpoint process creation telemetry with stable process identity, path, command line, parent, and user context.
  • FileEndpoint file telemetry used to scope temporary staging, archive creation, and cleanup.
  • NetworkEndpoint network telemetry with destination URL, port, initiating process, user, and stable process identity.

Search path

Hunt steps

Each search broadens the view from patient zero to related users, devices, infrastructure, and follow-on activity.
  1. Step 1First search

    Inventory MacSync request-shape pivots

    Finding

    The initial search groups retrieval, check-in, and upload request-shape pivots across rotating destinations.

    Multiple aligned request traits are more useful than a domain match by itself.

    View query
    Q-01First search

    Inventory MacSync request-shape pivots

    What this checks

    Identify macOS curl network activity carrying recurring retrieval, check-in, or chunked upload request shapes across all domains.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId, OSPlatform;
    DeviceNetworkEvents
    | where Timestamp >= ago(30d)
    | where InitiatingProcessFileName =~ "curl"
    | where RemoteUrl has_any ("/curl/", "/dynamic?txd=", "/gate?buildtxd=", "upload_id=", "chunk_index=", "total_chunks=")
    | join kind=inner mac_devices on DeviceId
    | extend Pivot=case(
        RemoteUrl has "/gate?buildtxd=" or RemoteUrl has "upload_id=", "chunked-upload",
        RemoteUrl has "/dynamic?txd=", "check-in",
        RemoteUrl has "/curl/", "payload-retrieval",
        "other"
    )
    | summarize
        FirstSeen=min(Timestamp),
        LastSeen=max(Timestamp),
        Connections=count(),
        Pivots=make_set(Pivot,10),
        Destinations=make_set(RemoteUrl,100),
        RemoteIPs=make_set(RemoteIP,50),
        Commands=make_set(InitiatingProcessCommandLine,50),
        Users=make_set(InitiatingProcessAccountUpn,20)
        by DeviceId,DeviceName,OSPlatform
    | order by Connections desc
    SPL
    (
        index=<endpoint_network_index> sourcetype=<endpoint_network_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        os=coalesce(os,OSPlatform),
        process_name=lower(coalesce(process_name,InitiatingProcessFileName)),
        remote_url=coalesce(remote_url,RemoteUrl),
        cmd=coalesce(cmd,InitiatingProcessCommandLine),
        pivot=case(
            like(remote_url,"%/gate?buildtxd=%") OR like(remote_url,"%upload_id=%"),"chunked-upload",
            like(remote_url,"%/dynamic?txd=%"),"check-in",
            like(remote_url,"%/curl/%"),"payload-retrieval",
            true(),"other"
        )
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%")
        AND process_name="curl"
        AND pivot!="other"
    | stats min(_time) as first_seen max(_time) as last_seen count as connections
            values(pivot) as pivots values(remote_url) as destinations
            values(RemoteIP) as remote_ips values(cmd) as commands values(InitiatingProcessAccountUpn) as users
      by device_id device os_platform
    | convert ctime(first_seen) ctime(last_seen)
    | sort - connections
    What to look for

    A ranked set of Macs and destinations matching one or more durable request-shape pivots.

    Technical details
    Tested signal

    curl network activity with recurring MacSync URI paths or upload parameters.

    Assumptions
    • DeviceInfo and DeviceNetworkEvents are available for at least thirty days.
    • The query intentionally treats domains as enrichment rather than the primary selector.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    network

    Endpoint network telemetry with destination URL, port, initiating process, user, and stable process identity.

    • Timestamp
    • DeviceId
    • DeviceName
    • RemoteUrl
    • RemoteIP
    • RemotePort
    • Protocol
    • LocalIP
    • LocalPort
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    • InitiatingProcessUniqueId
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Legitimate applications can use curl and individual URI fragments; multiple aligned traits raise confidence.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  2. Step 2Pivot

    Find interactive shell payload retrieval

    Finding

    Shell-launched curl and native decode/unpack tools identify the initial user-execution path.

    The combination is more suspicious on ordinary users than on development or administration systems.

    View query
    Q-02Pivot

    Find interactive shell payload retrieval

    What this checks

    Hunt macOS Unix-shell activity that launches curl retrieval and native decode or unpack utilities.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    DeviceProcessEvents
    | where Timestamp >= ago(30d)
    | where FileName in~ ("zsh","sh","bash","curl","base64","gunzip")
    | join kind=inner mac_devices on DeviceId
    | where
        FileName in~ ("zsh","sh","bash")
        and ProcessCommandLine has_any ("curl ", "base64", "gunzip")
        or
        FileName =~ "curl" and ProcessCommandLine has "/curl/"
    | project Timestamp,DeviceName,AccountName,AccountUpn,FileName,FolderPath,
              ProcessCommandLine,ProcessUniqueId,InitiatingProcessFileName,
              InitiatingProcessCommandLine
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        os=coalesce(os,OSPlatform),
        process_name=lower(coalesce(process_name,FileName)),
        cmd=coalesce(cmd,ProcessCommandLine)
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%")
        AND process_name IN ("zsh","sh","bash","curl","base64","gunzip")
        AND (
            (process_name IN ("zsh","sh","bash") AND
                (like(lower(cmd),"%curl %") OR like(lower(cmd),"%base64%") OR like(lower(cmd),"%gunzip%")))
            OR (process_name="curl" AND like(cmd,"%/curl/%"))
        )
    | table _time device AccountName AccountUpn process_name cmd ProcessUniqueId InitiatingProcessFileName InitiatingProcessCommandLine
    | sort - _time
    What to look for

    User-facing shell sessions that retrieve and decode or unpack content shortly before further execution.

    Technical details
    Tested signal

    zsh/sh/bash plus curl, base64, or gunzip in a compressed execution window.

    Assumptions
    • Process telemetry covers the macOS fleet.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Developers and administrators legitimately use these native utilities.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  3. Step 3Pivot

    Hunt AppleScript-assisted native tool chains

    Finding

    osascript activity links macOS automation with shell, retrieval, staging, or cleanup utilities.

    AppleScript is legitimate; sequence and user/application ownership decide the finding.

    View query
    Q-03Pivot

    Hunt AppleScript-assisted native tool chains

    What this checks

    Find osascript commands chaining shell, copy, removal, retrieval, directory creation, process termination, or directory-service queries.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    DeviceProcessEvents
    | where Timestamp >= ago(30d)
    | where FileName =~ "osascript"
    | where ProcessCommandLine has_any ("sh -c", "cp ", "rm ", "curl ", "mkdir ", "killall", "dscl")
    | join kind=inner mac_devices on DeviceId
    | project Timestamp,DeviceName,AccountName,AccountUpn,FileName,FolderPath,
              ProcessCommandLine,ProcessUniqueId,InitiatingProcessFileName,
              InitiatingProcessCommandLine
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        process_name=lower(coalesce(process_name,FileName)),
        cmd=coalesce(cmd,ProcessCommandLine)
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%") AND process_name="osascript"
        AND (
            like(lower(cmd),"%sh -c%") OR like(lower(cmd),"%cp %") OR
            like(lower(cmd),"%rm %") OR like(lower(cmd),"%curl %") OR
            like(lower(cmd),"%mkdir %") OR like(lower(cmd),"%killall%") OR
            like(lower(cmd),"%dscl%")
        )
    | table _time device AccountName AccountUpn process_name cmd InitiatingProcessFileName InitiatingProcessCommandLine
    | sort - _time
    What to look for

    AppleScript-assisted command chains that connect execution with staging, network access, or cleanup.

    Technical details
    Tested signal

    osascript driving native shell utilities in suspicious combinations.

    Assumptions
    • Process telemetry covers macOS endpoints.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Enterprise automation and user workflows can legitimately use osascript.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  4. Step 4Pivot

    Hunt credential and sensitive-file collection commands

    Finding

    Commands referencing Keychain, browser, SSH, cloud, Kubernetes, or sensitive user data show collection intent.

    Multiple unrelated credential stores accessed by an unexpected process materially raise confidence.

    View query
    Q-04Pivot

    Hunt credential and sensitive-file collection commands

    What this checks

    Search macOS command lines for Keychain, browser profile, SSH, cloud credential, Kubernetes, and sensitive-user-file targeting.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    DeviceProcessEvents
    | where Timestamp >= ago(30d)
    | join kind=inner mac_devices on DeviceId
    | where ProcessCommandLine has_any (
        "Keychains",
        "Login Data",
        "Cookies",
        "Local State",
        "Safe Storage",
        "/.ssh/",
        "/.aws/",
        "/.kube/",
        "Library/Safari",
        "Library/Group Containers/group.com.apple.notes",
        "Ledger",
        "Trezor"
    )
    | project Timestamp,DeviceName,AccountName,AccountUpn,FileName,FolderPath,
              ProcessCommandLine,InitiatingProcessFileName,InitiatingProcessCommandLine
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        cmd=coalesce(cmd,ProcessCommandLine)
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%")
        AND (
            like(cmd,"%Keychains%") OR like(cmd,"%Login Data%") OR
            like(cmd,"%Cookies%") OR like(cmd,"%Local State%") OR
            like(cmd,"%Safe Storage%") OR like(cmd,"%/.ssh/%") OR
            like(cmd,"%/.aws/%") OR like(cmd,"%/.kube/%") OR
            like(cmd,"%Library/Safari%") OR
            like(cmd,"%Library/Group Containers/group.com.apple.notes%") OR
            like(cmd,"%Ledger%") OR like(cmd,"%Trezor%")
        )
    | table _time device AccountName AccountUpn FileName FolderPath cmd InitiatingProcessFileName InitiatingProcessCommandLine
    | sort - _time
    What to look for

    A non-admin or unexpected process enumerating several credential stores or sensitive paths before staging.

    Technical details
    Tested signal

    Native utilities or shell commands referencing high-value local credential and user-data locations.

    Assumptions
    • Process telemetry records command-line access paths.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Developers, backup tools, and migration utilities can legitimately access some of these paths.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  5. Step 5Pivot

    Hunt temporary staging and compression

    Finding

    Temporary sync staging and archive creation identify the pre-exfiltration preparation phase.

    Archive behavior should be correlated with the earlier collection and later upload sequence.

    View query
    Q-05Pivot

    Hunt temporary staging and compression

    What this checks

    Identify collection staging under temporary sync paths followed by archive creation before outbound upload.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    let archive_processes =
        DeviceProcessEvents
        | where Timestamp >= ago(30d)
        | where FileName in~ ("zip","ditto","tar","gzip")
        | where ProcessCommandLine has "/tmp/"
        | project Timestamp,DeviceId,DeviceName,Signal="archive-process",FileName,
                  FolderPath,ProcessCommandLine,AccountName,
                  InitiatingProcessFileName,InitiatingProcessCommandLine;
    let staged_files =
        DeviceFileEvents
        | where Timestamp >= ago(30d)
        | where FolderPath startswith "/tmp/sync"
            or (FolderPath startswith "/tmp/" and FileName endswith ".zip")
        | project Timestamp,DeviceId,DeviceName,Signal="staged-file",FileName,
                  FolderPath,ProcessCommandLine=InitiatingProcessCommandLine,
                  AccountName=InitiatingProcessAccountName,
                  InitiatingProcessFileName,InitiatingProcessCommandLine;
    union archive_processes, staged_files
    | join kind=inner mac_devices on DeviceId
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<endpoint_file_index> sourcetype=<file_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        process_name=lower(coalesce(process_name,FileName,InitiatingProcessFileName)),
        folder=coalesce(folder,FolderPath),
        cmd=coalesce(cmd,ProcessCommandLine,InitiatingProcessCommandLine),
        signal=case(
            process_name IN ("zip","ditto","tar","gzip") AND like(cmd,"%/tmp/%"),"archive-process",
            like(folder,"/tmp/sync%"),"staged-file",
            like(folder,"/tmp/%") AND like(lower(FileName),"%.zip"),"staged-file",
            true(),"other"
        )
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%") AND signal!="other"
    | table _time device signal process_name folder FileName cmd AccountName InitiatingProcessFileName
    | sort - _time
    What to look for

    A Mac staging files in temporary sync directories and creating a temporary archive soon afterward.

    Technical details
    Tested signal

    Temporary sync staging plus archive utility or temporary ZIP creation.

    Assumptions
    • Process and file telemetry cover the collection window.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    file

    Endpoint file telemetry used to scope temporary staging, archive creation, and cleanup.

    • Timestamp
    • DeviceId
    • DeviceName
    • ActionType
    • FileName
    • FolderPath
    • SHA1
    • SHA256
    • FileSize
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    • InitiatingProcessUniqueId
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Software packaging, browser updates, and developer workflows can create temporary archives.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  6. Step 6Pivot

    Hunt chunked curl exfiltration

    Finding

    Binary PUT plus chunk parameters confirms an active data-transfer pattern consistent with MacSync exfiltration.

    Destination rotation does not weaken the behavior when request shape remains stable.

    View query
    Q-06Pivot

    Hunt chunked curl exfiltration

    What this checks

    Search macOS curl processes and network events for binary HTTP PUT uploads with upload session and chunk parameters.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    DeviceNetworkEvents
    | where Timestamp >= ago(30d)
    | where InitiatingProcessFileName =~ "curl"
    | where InitiatingProcessCommandLine has_all ("-X PUT","--data-binary")
    | where RemoteUrl has_any ("/gate?buildtxd=","upload_id=","chunk_index=","total_chunks=")
    | join kind=inner mac_devices on DeviceId
    | project Timestamp,DeviceName,RemoteUrl,RemoteIP,RemotePort,Protocol,
              InitiatingProcessCommandLine,InitiatingProcessAccountUpn,
              InitiatingProcessUniqueId
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_network_index> sourcetype=<endpoint_network_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        process_name=lower(coalesce(process_name,InitiatingProcessFileName)),
        cmd=coalesce(cmd,InitiatingProcessCommandLine),
        remote_url=coalesce(remote_url,RemoteUrl)
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%")
        AND process_name="curl"
        AND like(cmd,"%-X PUT%")
        AND like(cmd,"%--data-binary%")
        AND (
            like(remote_url,"%/gate?buildtxd=%") OR
            like(remote_url,"%upload_id=%") OR
            like(remote_url,"%chunk_index=%") OR
            like(remote_url,"%total_chunks=%")
        )
    | table _time device InitiatingProcessAccountUpn cmd remote_url RemoteIP RemotePort InitiatingProcessUniqueId
    | sort - _time
    What to look for

    A Mac performing chunked binary upload behavior consistent with active data exfiltration.

    Technical details
    Tested signal

    curl PUT with binary body and recurring chunked upload semantics.

    Assumptions
    • Process and network telemetry share stable process identity where available.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    network

    Endpoint network telemetry with destination URL, port, initiating process, user, and stable process identity.

    • Timestamp
    • DeviceId
    • DeviceName
    • RemoteUrl
    • RemoteIP
    • RemotePort
    • Protocol
    • LocalIP
    • LocalPort
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    • InitiatingProcessUniqueId
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Some APIs and backup workflows legitimately chunk uploads.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

  7. Step 7Pivot

    Hunt post-upload cleanup

    Finding

    Post-transfer deletion of temporary staging, archive, or lock artifacts reinforces the end-to-end chain.

    Cleanup is supporting evidence because many legitimate scripts also remove temporary files.

    View query
    Q-07Pivot

    Hunt post-upload cleanup

    What this checks

    Identify deletion commands and temporary artifact removal after staging or chunked transfer.

    KQL
    let mac_devices =
        DeviceInfo
        | where Timestamp >= ago(7d)
        | summarize arg_max(Timestamp, DeviceName, OSPlatform) by DeviceId
        | where OSPlatform startswith "macOS"
        | project DeviceId;
    DeviceProcessEvents
    | where Timestamp >= ago(30d)
    | where FileName =~ "rm"
        or ProcessCommandLine has "rm "
    | where ProcessCommandLine has_any ("/tmp/sync", "/tmp/")
    | where ProcessCommandLine has_any (".zip", ".lock", "sync")
    | join kind=inner mac_devices on DeviceId
    | project Timestamp,DeviceName,AccountName,AccountUpn,FileName,FolderPath,
              ProcessCommandLine,InitiatingProcessFileName,InitiatingProcessCommandLine
    | order by Timestamp desc
    SPL
    (
        index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d
    )
    OR
    (
        index=<device_inventory_index> sourcetype=<device_info_sourcetype> earliest=-7d
    )
    | eval
        device_id=coalesce(device_id,DeviceId),
        device=coalesce(device,DeviceName,host),
        process_name=lower(coalesce(process_name,FileName)),
        cmd=coalesce(cmd,ProcessCommandLine)
    | eventstats latest(OSPlatform) as os_platform by device_id
    | where like(lower(os_platform),"macos%")
        AND (process_name="rm" OR like(lower(cmd),"%rm %"))
        AND (like(cmd,"%/tmp/sync%") OR like(cmd,"%/tmp/%"))
        AND (like(lower(cmd),"%.zip%") OR like(lower(cmd),"%.lock%") OR like(lower(cmd),"%sync%"))
    | table _time device AccountName AccountUpn process_name cmd InitiatingProcessFileName InitiatingProcessCommandLine
    | sort - _time
    What to look for

    A Mac deleting temporary staging or archive artifacts shortly after suspicious transfer behavior.

    Technical details
    Tested signal

    rm-based cleanup of temporary sync, archive, or lock artifacts after upload.

    Assumptions
    • Process telemetry covers the post-exfiltration window.
    Data requirements and relevant fields
    endpoint

    Device inventory used to restrict analytics to current macOS endpoints.

    • Timestamp
    • DeviceId
    • DeviceName
    • OSPlatform
    process

    Endpoint process creation telemetry with stable process identity, path, command line, parent, and user context.

    • Timestamp
    • DeviceId
    • DeviceName
    • FileName
    • FolderPath
    • ProcessId
    • ProcessUniqueId
    • ProcessCommandLine
    • AccountName
    • AccountUpn
    • SHA1
    • SHA256
    • InitiatingProcessFileName
    • InitiatingProcessFolderPath
    • InitiatingProcessCommandLine
    • InitiatingProcessId
    • InitiatingProcessUniqueId
    • InitiatingProcessAccountName
    • InitiatingProcessAccountUpn
    KQL schema

    Validate Defender for Endpoint coverage on macOS, table availability, field population, and retention before operational use.

    SPL schema

    Replace index/sourcetype placeholders and map device, process, file, and network fields to local telemetry.

    Limitations
    • Installers, update frameworks, and scripts commonly clean temporary files.

    KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized raw-event scaffold and requires local field mapping.

Blast radius

Wider-compromise pivots

  • Baseline Terminal, zsh, curl, and osascript by user role and device population.
  • Search for repeated Keychain, browser, SSH, cloud, and Kubernetes credential-store access by the same process tree.
  • Review temporary archive creation immediately before unusual outbound PUT traffic.
  • Track newly observed domains only after behavior matches, then use them for retrospective fleet scoping.
  • Prioritize Macs used for administration, development, cryptocurrency, or cloud access because they can expose high-value credentials.
  • Review platform controls that interrupt suspicious Terminal paste-and-run workflows.

Evidence threshold

What would increase confidence

  • Interactive shell activity launches curl retrieval from an unexpected user context.
  • osascript chains shell/native utilities into network, staging, or cleanup activity.
  • Multiple credential stores or sensitive user-data paths are accessed.
  • Temporary sync staging and archive creation occur before transfer.
  • curl performs binary HTTP PUT with upload session and chunk parameters.
  • The destination is new or behaviorally related to known MacSync infrastructure.
  • Temporary staging or archive artifacts are removed after upload.
  • No approved automation, development, backup, or support workflow explains the chain.

Conclusion

Result and next action

The hunt turns a rotating macOS infostealer campaign into durable endpoint and network pivots based on execution, collection, staging, upload shape, and cleanup.

  • Isolate confirmed Macs and terminate malicious processes.
  • Preserve staging, archive, process, and network evidence.
  • Rotate exposed Keychain, browser, SSH, cloud, and local credentials as appropriate.
  • Search all managed Macs using request-shape and process-chain pivots before IOC-only searches.
  • Block confirmed malicious destinations and continue behavior-based monitoring for replacements.
  • Review Terminal paste protections, web/network controls, and user awareness for macOS ClickFix lures.

This hunt begins with request shape instead of a domain list. It then walks backward and forward through the same Mac: interactive shell retrieval, AppleScript-assisted native tooling, sensitive-data collection, temporary staging, chunked upload, and cleanup.

The intent is to make infrastructure rotation a scoping problem rather than a detection failure.

Context

ATT&CK and limits

Behavior mapping

MITRE ATT&CK

This mapping describes the valid-account behavior examined by the Hunt. It does not prove token theft, attribution, or technique-wide coverage.

Review boundary

Sources and limits

The conclusion stays bounded to the stated scope and available logs.