T1569.001 IBM QRadar · QRadar

Detect Launchctl in IBM QRadar

Adversaries may abuse launchctl to execute commands or programs on macOS. Launchctl interfaces with launchd, the macOS service management framework, and supports subcommands including load, unload, start, stop, and kickstart. Adversaries use launchctl to execute payloads as Launch Agents (per-user persistence in ~/Library/LaunchAgents/ or /Library/LaunchAgents/) or Launch Daemons (system-level persistence in /Library/LaunchDaemons/). Common attack patterns include loading malicious plist files from world-writable directories such as /tmp, using the -w flag to force-enable disabled services, and invoking launchctl from scripting engines after initial access. Real-world threat actors using this technique include LoudMiner (QEMU-based cryptominer), Cuckoo Stealer, AppleJeus (North Korean cryptocurrency theft), macOS.OSAMiner, XCSSET (Xcode project infection), and Calisto spyware.

MITRE ATT&CK

Tactic
Execution
Technique
T1569 System Services
Sub-technique
T1569.001 Launchctl
Canonical reference
https://attack.mitre.org/techniques/T1569/001/

QRadar Detection Query

IBM QRadar (QRadar)
sql
SELECT
  DATEFORMAT(starttime, 'YYYY-MM-dd HH:mm:ss') AS event_time,
  logsourcename(logsourceid) AS log_source,
  sourceip,
  username,
  "processname",
  "processcmdline",
  "parentprocesspath",
  CASE
    WHEN "processcmdline" IMATCHES '%/tmp/%' OR "processcmdline" IMATCHES '%/private/tmp/%'
      OR "processcmdline" IMATCHES '%/var/tmp/%' OR "processcmdline" IMATCHES '%/var/folders/%'
      OR "processcmdline" IMATCHES '%/Users/Shared/%' THEN 1 ELSE 0
  END AS load_from_temp,
  CASE
    WHEN "processcmdline" IMATCHES '%launchctl load -w%' THEN 1 ELSE 0
  END AS force_load,
  CASE
    WHEN "processcmdline" IMATCHES '%launchctl kickstart%' THEN 1 ELSE 0
  END AS kickstart_cmd,
  CASE
    WHEN "parentprocesspath" IMATCHES '%(bash|sh|zsh|ksh|python|ruby|perl|osascript|curl|wget|node|npm)' THEN 1 ELSE 0
  END AS scripting_parent
FROM events
WHERE
  LOGSOURCETYPEID IN (SELECT id FROM SensorDeviceType WHERE name ILIKE '%osquery%' OR name ILIKE '%carbon black%' OR name ILIKE '%falcon%')
  AND "processname" ILIKE '%launchctl%'
  AND ("processcmdline" IMATCHES '%(load|start|kickstart|bootstrap)%')
  AND starttime > NOW() - 86400000
HAVING
  load_from_temp = 1
  OR scripting_parent = 1
  OR (force_load = 1 AND "processcmdline" IMATCHES '%/Users/%/Library/LaunchAgents/%')
ORDER BY event_time DESC
LIMIT 500
high severity medium confidence

QRadar AQL detection for T1569.001 launchctl abuse on macOS endpoints. Queries process execution events from endpoint telemetry log sources (osquery, Carbon Black, Falcon) to identify launchctl invocations loading from temporary/world-writable directories, forced service loads, kickstart commands, and those initiated by scripting engines or network download utilities.

Data Sources

IBM QRadar SIEMosquery macOS log sourceCrowdStrike Falcon log sourceCarbon Black log source

Required Tables

events

False Positives & Tuning

  • Enterprise software deployment systems (Jamf Pro, Kandji) that use launchctl to register managed configurations and may invoke it from shell wrapper scripts
  • Security tools and EDR agents that use launchctl for self-installation or service registration from temporary extraction paths
  • Developer workstations running automated test harnesses that bootstrap launchctl services as part of local testing pipelines using scripting environments
Download portable Sigma rule (.yml)

Other platforms for T1569.001


Testing Methodology

Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Load LaunchAgent from /tmp (Malware Staging Pattern)

    Expected signal: Process creation: launchctl with ProcessCommandLine containing 'load /tmp/com.df00tech.atomictest.plist'; parent process is the executing shell. Secondary process creation: /bin/sh spawned by launchd executing the RunAtLoad ProgramArguments. File creation: /tmp/launchctl_test_output.txt written by the loaded agent. macOS Unified Log entry for com.df00tech.atomictest service start under the current user's launchd domain.

  2. Test 2Load LaunchDaemon with Force-Enable Flag (-w) — XCSSET and LoudMiner Technique

    Expected signal: Process creation: sudo followed by launchctl with ProcessCommandLine containing 'load -w /Library/LaunchDaemons/com.df00tech.daemontest.plist'. File creation event in /Library/LaunchDaemons/ directory (anomalous outside MDM-managed deployments). launchd override database updated at /var/db/launchd.db/. macOS Unified Log records bootstrap of com.df00tech.daemontest in the system launchd domain.

  3. Test 3Enable Screen Sharing via Launchctl — Calisto Spyware Technique

    Expected signal: Process creation: launchctl with ProcessCommandLine 'load -w /System/Library/LaunchDaemons/com.apple.screensharing.plist'. Parent process is sudo/shell. macOS Unified Log records screensharing daemon activation. System Preferences -> Sharing would show Screen Sharing enabled. VNC listener appears on TCP port 5900 (detectable via network telemetry). launchd override database records screensharing as enabled.

  4. Test 4Launchctl Invoked from Python Dropper (Staged Execution Chain)

    Expected signal: Process creation chain: python3 spawning /bin/launchctl as a child process. ProcessCommandLine for launchctl: 'load /tmp/com.df00tech.pytest.plist'. InitiatingProcessFileName: python3. This specific parent-child relationship (python3 → launchctl) is the key detection signal. Secondary process creation: /bin/sh running the ProgramArguments payload, spawned by launchd.

Unlock Pro Content

Get the full detection package for T1569.001 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections