Skip to content

Conversation

@tomsonpl
Copy link
Contributor

@tomsonpl tomsonpl commented Nov 21, 2025

Startup Items Persistence Detection (Cross-Platform)

Advanced cross-platform queries for detecting malicious persistence mechanisms through startup items, autostart entries, and launch configurations. Implements a dual-detection approach combining signature-based filtering with Living off the Land (LotL) attack pattern recognition across Windows, macOS, and Linux systems.

Read https://p.elstc.co/paste/Bl5p6ffG#Ef0urSr4IAmt7C-qNrfaN1CHyYq0Ewxh2JIBn6cwAVx

Core Forensic Artifacts Coverage

# Artifact OS Query File Description
1 Startup Items Windows startup_items_windows_elastic d4e5f6a7 Dual-detection with LotL pattern recognition
2 Startup Items Linux startup_items_linux_elastic e5f6a7b8 Systemd, cron, XDG autostart with LotL detection
3 Startup Items macOS startup_items_darwin_elastic f6a7b8c9 LaunchAgents/Daemons with signature validation

Queries by Platform


🪟 Windows - Startup Items (Dual-Detection)

Description

Advanced dual-detection query combining signature-based filtering with Living off the Land (LotL) attack pattern recognition. Detects both non-whitelisted legitimate binaries AND abuse of legitimate Windows tools for malicious persistence. Filters out high-volume known-good tasks while flagging suspicious patterns regardless of code signature status.

Detection Focus:

  • Non-whitelisted startup items (filters Microsoft system paths and known updaters)
  • PowerShell encoded commands (-e, -enc, -EncodedCommand)
  • Download utilities abuse (certutil, bitsadmin, Invoke-WebRequest)
  • Suspicious file paths (Users\Public, ProgramData, Temp directories)
  • Script execution abuse (wscript, cscript, mshta, regsvr32, rundll32)
  • File hash and signature information for threat intelligence
  • Timestamp analysis for recent persistence creation

MITRE ATT&CK Mapping:

  • T1547.001 - Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder
  • T1059.001 - Command and Scripting Interpreter: PowerShell
  • T1105 - Ingress Tool Transfer

Result

Screenshot 2025-11-21 at 13 47 59

Query returns prioritized results with LotL indicators first, followed by non-whitelisted items. Each result includes detection method, detection reason, executable hashes, code signature information, and file metadata.

Platform

windows

Interval

3600 seconds (1 hour)

Query ID

startup_items_windows_elastic

ECS Field Mappings

  • process.namename
  • process.executablepath
  • file.pathpath
  • file.hash.sha256sha256
  • file.hash.sha1sha1
  • file.hash.md5md5
  • file.sizesize
  • file.mtimemtime
  • file.ctimectime
  • file.directorydirectory
  • user.nameusername
  • rule.categorytype
  • event.outcomestatus
  • registry.pathsource
  • code_signature.subject_namesubject_name
  • code_signature.statussignature_result
  • event.categorydetection_method
  • rule.descriptiondetection_reason

SQL Query

-- Dual-detection Windows startup items query:
-- 1. NON_WHITELISTED: Filters out known-good high-volume tasks, flags everything else
-- 2. LOTL_INDICATOR: Detects Living off the Land attack patterns (powershell -e, certutil, etc.)
-- MITRE ATT&CK: T1547.001, T1059.001, T1105

WITH non_whitelisted AS (
    SELECT
        si.name,
        si.path,
        si.type,
        si.status,
        si.source,
        si.args,
        si.username,
        'NON_WHITELISTED' AS detection_method,
        'Startup item not in known-good allowlist' AS detection_reason
    FROM startup_items AS si
    WHERE si.type IN ('Startup Item', 'Run Group Policy', 'RunOnce')
        AND si.path IS NOT NULL
        AND si.path != ''
        -- Filter 1a: Exclude Microsoft system tasks in System32 (unless LotL indicators present)
        AND NOT (
            si.source LIKE 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\%'
            AND si.path LIKE 'C:\Windows\System32\%'
            AND si.args NOT LIKE '%powershell% -e%'
            AND si.args NOT LIKE '% -enc %'
            AND si.args NOT LIKE '% -EncodedCommand %'
            AND si.args NOT LIKE '%Invoke-WebRequest%'
            AND si.args NOT LIKE '%IWR %'
            AND si.args NOT LIKE '%certutil% -urlcache%'
            AND si.args NOT LIKE '%bitsadmin%'
        )
        -- Filter 1b: Exclude specific known-good third-party updaters (name + path match required)
        AND NOT (
            si.name = 'GoogleUpdateTaskMachineUA'
            AND si.path LIKE '%GoogleUpdate.exe%'
        )
        AND NOT (
            si.name LIKE 'Adobe Acrobat Update Task%'
            AND si.path LIKE '%Adobe%'
        )
        AND NOT (
            si.source LIKE '%Microsoft\Office%'
            AND si.path LIKE 'C:\Program Files\Microsoft Office\%'
        )
),
lotl_indicators AS (
    SELECT
        si.name,
        si.path,
        si.type,
        si.status,
        si.source,
        si.args,
        si.username,
        'LOTL_INDICATOR' AS detection_method,
        CASE
            WHEN si.args LIKE '%powershell% -e%' OR si.args LIKE '% -enc %' OR si.args LIKE '% -EncodedCommand %' THEN 'PowerShell base64 encoded command'
            WHEN si.args LIKE '%Invoke-WebRequest%' OR si.args LIKE '%IWR %' OR si.args LIKE '%curl %' OR si.args LIKE '%wget %' THEN 'Download command detected'
            WHEN si.args LIKE '%certutil% -urlcache%' OR si.args LIKE '%certutil% -f%' THEN 'CertUtil download abuse'
            WHEN si.args LIKE '%bitsadmin% /transfer%' THEN 'BITSAdmin download abuse'
            WHEN si.path LIKE '%C:\Users\Public\%' OR si.path LIKE '%C:\ProgramData\%' THEN 'Suspicious file path (writable by low-priv users)'
            WHEN si.path LIKE '%\Temp\%' OR si.path LIKE '%\AppData\Local\Temp\%' THEN 'Execution from Temp directory'
            WHEN si.args LIKE '%wscript.exe%' OR si.args LIKE '%cscript.exe%' THEN 'Windows Script Host abuse'
            WHEN si.args LIKE '%mshta.exe%' THEN 'MSHTA.exe abuse'
            WHEN si.args LIKE '%regsvr32%' OR si.args LIKE '%rundll32%' THEN 'Proxy execution via regsvr32/rundll32'
            WHEN si.args LIKE '%.hta%' OR si.args LIKE '%.vbs%' OR si.args LIKE '%.js%' THEN 'Script file execution'
            ELSE 'Unknown LotL pattern'
        END AS detection_reason
    FROM startup_items AS si
    WHERE si.type IN ('Startup Item', 'Run Group Policy', 'RunOnce')
        AND si.path IS NOT NULL
        AND si.path != ''
        AND (
            -- PowerShell encoded commands (highest priority)
            si.args LIKE '%powershell% -e%'
            OR si.args LIKE '% -enc %'
            OR si.args LIKE '% -EncodedCommand %'
            -- Download utilities abuse
            OR si.args LIKE '%Invoke-WebRequest%'
            OR si.args LIKE '%IWR %'
            OR si.args LIKE '%curl %'
            OR si.args LIKE '%wget %'
            OR si.args LIKE '%certutil% -urlcache%'
            OR si.args LIKE '%certutil% -f%'
            OR si.args LIKE '%bitsadmin% /transfer%'
            -- Suspicious file paths
            OR si.path LIKE '%C:\Users\Public\%'
            OR si.path LIKE '%C:\ProgramData\%'
            OR si.path LIKE '%\Temp\%'
            OR si.path LIKE '%\AppData\Local\Temp\%'
            -- Script execution abuse
            OR si.args LIKE '%wscript.exe%'
            OR si.args LIKE '%cscript.exe%'
            OR si.args LIKE '%mshta.exe%'
            OR si.args LIKE '%regsvr32%'
            OR si.args LIKE '%rundll32%'
            OR si.args LIKE '%.hta%'
            OR si.args LIKE '%.vbs%'
            OR si.args LIKE '%.js%'
        )
),
combined AS (
    SELECT * FROM non_whitelisted
    UNION
    SELECT * FROM lotl_indicators
)
SELECT
    c.name,
    c.path,
    c.type,
    c.status,
    c.source,
    c.args,
    c.username,
    c.detection_method,
    c.detection_reason,
    a.subject_name,
    a.result AS signature_result,
    h.sha256,
    h.sha1,
    h.md5,
    f.size,
    f.mtime,
    f.ctime,
    f.directory
FROM combined AS c
LEFT JOIN authenticode AS a ON c.path = a.path
LEFT JOIN hash AS h ON c.path = h.path
LEFT JOIN file AS f ON c.path = f.path
ORDER BY
    CASE WHEN c.detection_method = 'LOTL_INDICATOR' THEN 0 ELSE 1 END,
    c.detection_reason,
    c.name

🐧 Linux - Startup Items (Dual-Detection)

Description

Comprehensive dual-detection query for Linux persistence mechanisms combining user-created configurations with Living off the Land attack pattern recognition. Detects systemd services, cron jobs, and XDG autostart entries while identifying malicious use of bash, curl, base64 decoding, and other legitimate tools. Maintains cross-distribution compatibility using location-based filtering.

Detection Focus:

  • User-created systemd services in /etc/systemd/system/
  • Cron @reboot jobs in user crontabs
  • User-specific XDG autostart entries
  • Shell command execution via -c flag abuse
  • Download and pipe to shell patterns (curl | bash, wget | sh)
  • Base64 decode for obfuscation
  • Execution from world-writable directories (/dev/shm, /tmp)
  • Reverse shell indicators (netcat, /dev/tcp/ redirection)
  • Background process persistence (nohup, disown)

MITRE ATT&CK Mapping:

  • T1543.002 - Create or Modify System Process: Systemd Service
  • T1053.003 - Scheduled Task/Job: Cron
  • T1547.013 - Boot or Logon Autostart Execution: XDG Autostart Entries
  • T1059.004 - Command and Scripting Interpreter: Unix Shell
  • T1105 - Ingress Tool Transfer

Result

Screenshot 2025-11-21 at 13 45 22

Query returns prioritized results with LotL indicators first, followed by non-whitelisted items. Includes detection method, detection reason, file hashes, ownership, permissions, and timestamps.

Platform

linux

Interval

3600 seconds (1 hour)

Query ID

startup_items_linux_elastic

ECS Field Mappings

  • process.namename
  • process.executablepath
  • process.command_lineargs
  • file.pathpath
  • file.hash.sha256sha256
  • file.hash.sha1sha1
  • file.hash.md5md5
  • file.sizesize
  • file.mtimemtime
  • file.ctimectime
  • file.uiduid
  • file.gidgid
  • file.modemode
  • user.nameusername
  • service.idservice_id
  • rule.categorytype
  • event.outcomestatus
  • registry.pathsource
  • event.categorydetection_method
  • rule.descriptiondetection_reason

SQL Query

-- Dual-detection Linux persistence query:
-- 1. NON_WHITELISTED: User-created systemd/cron/XDG autostart (location-based filtering)
-- 2. LOTL_INDICATOR: Living off the Land patterns (bash -c, curl | bash, base64 -d, etc.)
-- MITRE ATT&CK: T1543.002, T1053.003, T1547.013, T1059.004, T1105

WITH non_whitelisted_systemd AS (
    SELECT
        su.id AS name,
        su.id AS service_id,
        su.fragment_path AS path,
        su.fragment_path AS source,
        su.description AS args,
        su.user AS username,
        CASE
            WHEN su.unit_file_state = 'enabled' THEN 'enabled'
            WHEN su.unit_file_state = 'disabled' THEN 'disabled'
            ELSE su.unit_file_state
        END AS status,
        'Systemd Service (Custom)' AS type,
        'NON_WHITELISTED' AS detection_method,
        'User-created systemd service' AS detection_reason
    FROM systemd_units AS su
    WHERE su.fragment_path LIKE '/etc/systemd/system/%'
        AND su.id LIKE '%.service'
        AND su.unit_file_state IN ('enabled', 'static', 'linked')
        AND su.id NOT IN (
            'ssh.service',
            'sshd.service',
            'cron.service',
            'rsyslog.service',
            'systemd-timesyncd.service',
            'NetworkManager.service',
            'docker.service',
            'containerd.service',
            'snapd.service',
            'ufw.service',
            'firewalld.service',
            'auditd.service'
        )
        AND su.id NOT LIKE 'getty@%'
        AND su.id NOT LIKE 'dbus-%'
),
non_whitelisted_cron AS (
    SELECT
        SUBSTR(c.command, 1, 100) AS name,
        '' AS service_id,
        c.path,
        c.path AS source,
        c.command AS args,
        CASE
            WHEN c.path LIKE '/var/spool/cron/crontabs/%' THEN REPLACE(c.path, '/var/spool/cron/crontabs/', '')
            WHEN c.path LIKE '/var/spool/cron/%' THEN REPLACE(REPLACE(c.path, '/var/spool/cron/', ''), 'crontabs/', '')
            ELSE 'root'
        END AS username,
        'enabled' AS status,
        'Cron @reboot' AS type,
        'NON_WHITELISTED' AS detection_method,
        'Cron @reboot job' AS detection_reason
    FROM crontab AS c
    WHERE c.event = '@reboot'
),
non_whitelisted_xdg AS (
    SELECT
        REPLACE(f.filename, '.desktop', '') AS name,
        '' AS service_id,
        f.path,
        f.directory AS source,
        '' AS args,
        SUBSTR(SUBSTR(f.path, 7), 1, INSTR(SUBSTR(f.path, 7), '/') - 1) AS username,
        'enabled' AS status,
        'XDG Autostart (User)' AS type,
        'NON_WHITELISTED' AS detection_method,
        'User-specific XDG autostart entry' AS detection_reason
    FROM file AS f
    WHERE f.path LIKE '/home/%/.config/autostart/%.desktop'
),
lotl_systemd AS (
    SELECT
        su.id AS name,
        su.id AS service_id,
        su.fragment_path AS path,
        su.fragment_path AS source,
        su.description AS args,
        su.user AS username,
        CASE
            WHEN su.unit_file_state = 'enabled' THEN 'enabled'
            WHEN su.unit_file_state = 'disabled' THEN 'disabled'
            ELSE su.unit_file_state
        END AS status,
        'Systemd Service (LotL)' AS type,
        'LOTL_INDICATOR' AS detection_method,
        CASE
            WHEN su.description LIKE '%bash -c%' OR su.description LIKE '%sh -c%' THEN 'Shell command execution via -c flag'
            WHEN su.description LIKE '%curl%|%bash%' OR su.description LIKE '%wget%|%sh%' THEN 'Download and pipe to shell'
            WHEN su.description LIKE '%curl%http%' OR su.description LIKE '%wget%http%' THEN 'Download utility abuse'
            WHEN su.description LIKE '%base64 -d%' OR su.description LIKE '%base64 --decode%' THEN 'Base64 decode for obfuscation'
            WHEN su.description LIKE '%/dev/shm/%' OR su.description LIKE '%/tmp/%' THEN 'Execution from world-writable directory'
            WHEN su.description LIKE '%nc %' OR su.description LIKE '%netcat%' THEN 'Netcat reverse shell'
            WHEN su.description LIKE '%/dev/tcp/%' THEN 'Bash TCP socket redirection'
            WHEN su.description LIKE '%nohup%&%' OR su.description LIKE '%disown%' THEN 'Background process persistence'
            WHEN su.description LIKE '%.sh%' AND su.fragment_path LIKE '/tmp/%' THEN 'Shell script from temp directory'
            ELSE 'Unknown LotL pattern in systemd'
        END AS detection_reason
    FROM systemd_units AS su
    WHERE su.fragment_path IS NOT NULL
        AND su.id LIKE '%.service'
        AND su.unit_file_state IN ('enabled', 'static', 'linked')
        AND (
            su.description LIKE '%bash -c%'
            OR su.description LIKE '%sh -c%'
            OR su.description LIKE '%curl%|%bash%'
            OR su.description LIKE '%wget%|%sh%'
            OR su.description LIKE '%curl%http%'
            OR su.description LIKE '%wget%http%'
            OR su.description LIKE '%base64 -d%'
            OR su.description LIKE '%base64 --decode%'
            OR su.description LIKE '%/dev/shm/%'
            OR su.description LIKE '%/tmp/%'
            OR su.description LIKE '%nc %'
            OR su.description LIKE '%netcat%'
            OR su.description LIKE '%/dev/tcp/%'
            OR su.description LIKE '%nohup%&%'
            OR su.description LIKE '%disown%'
            OR (su.description LIKE '%.sh%' AND su.fragment_path LIKE '/tmp/%')
        )
),
lotl_cron AS (
    SELECT
        SUBSTR(c.command, 1, 100) AS name,
        '' AS service_id,
        c.path,
        c.path AS source,
        c.command AS args,
        CASE
            WHEN c.path LIKE '/var/spool/cron/crontabs/%' THEN REPLACE(c.path, '/var/spool/cron/crontabs/', '')
            WHEN c.path LIKE '/var/spool/cron/%' THEN REPLACE(REPLACE(c.path, '/var/spool/cron/', ''), 'crontabs/', '')
            ELSE 'root'
        END AS username,
        'enabled' AS status,
        'Cron (LotL)' AS type,
        'LOTL_INDICATOR' AS detection_method,
        CASE
            WHEN c.command LIKE '%bash -c%' OR c.command LIKE '%sh -c%' THEN 'Shell command execution via -c flag'
            WHEN c.command LIKE '%curl%|%bash%' OR c.command LIKE '%wget%|%sh%' THEN 'Download and pipe to shell'
            WHEN c.command LIKE '%curl%http%' OR c.command LIKE '%wget%http%' THEN 'Download utility abuse'
            WHEN c.command LIKE '%base64 -d%' OR c.command LIKE '%base64 --decode%' THEN 'Base64 decode for obfuscation'
            WHEN c.command LIKE '%/dev/shm/%' OR c.command LIKE '%/tmp/%' THEN 'Execution from world-writable directory'
            WHEN c.command LIKE '%nc %' OR c.command LIKE '%netcat%' THEN 'Netcat reverse shell'
            WHEN c.command LIKE '%/dev/tcp/%' THEN 'Bash TCP socket redirection'
            WHEN c.command LIKE '%nohup%&%' OR c.command LIKE '%disown%' THEN 'Background process persistence'
            ELSE 'Unknown LotL pattern in cron'
        END AS detection_reason
    FROM crontab AS c
    WHERE c.command IS NOT NULL
        AND (
            c.command LIKE '%bash -c%'
            OR c.command LIKE '%sh -c%'
            OR c.command LIKE '%curl%|%bash%'
            OR c.command LIKE '%wget%|%sh%'
            OR c.command LIKE '%curl%http%'
            OR c.command LIKE '%wget%http%'
            OR c.command LIKE '%base64 -d%'
            OR c.command LIKE '%base64 --decode%'
            OR c.command LIKE '%/dev/shm/%'
            OR c.command LIKE '%/tmp/%'
            OR c.command LIKE '%nc %'
            OR c.command LIKE '%netcat%'
            OR c.command LIKE '%/dev/tcp/%'
            OR c.command LIKE '%nohup%&%'
            OR c.command LIKE '%disown%'
        )
),
combined AS (
    SELECT * FROM non_whitelisted_systemd
    UNION ALL
    SELECT * FROM non_whitelisted_cron
    UNION ALL
    SELECT * FROM non_whitelisted_xdg
    UNION ALL
    SELECT * FROM lotl_systemd
    UNION ALL
    SELECT * FROM lotl_cron
)
SELECT
    c.name,
    c.service_id,
    c.path,
    c.type,
    c.status,
    c.source,
    c.args,
    c.username,
    c.detection_method,
    c.detection_reason,
    h.sha256,
    h.sha1,
    h.md5,
    f.size,
    f.mtime,
    f.ctime,
    f.uid,
    f.gid,
    f.mode
FROM combined AS c
LEFT JOIN hash AS h ON c.path = h.path
LEFT JOIN file AS f ON c.path = f.path
ORDER BY
    CASE WHEN c.detection_method = 'LOTL_INDICATOR' THEN 0 ELSE 1 END,
    c.detection_reason,
    c.type,
    c.name

🍎 macOS - Startup Items (Dual-Detection)

Description

Advanced dual-detection query for macOS persistence mechanisms combining signature validation with Living off the Land attack pattern recognition. Detects LaunchAgents, LaunchDaemons, and legacy startup/login items while identifying malicious use of bash, curl, osascript, and other legitimate macOS tools. Filters out Apple-signed system components while flagging suspicious patterns regardless of code signature status.

Note: macOS 10.13+ login items stored in backgrounditems.btm binary format may not be fully captured by the osquery startup_items table.

Detection Focus:

  • Non-Apple signed LaunchAgents and LaunchDaemons
  • Legacy startup items and login items outside Apple directories
  • Shell command execution via -c flag abuse
  • Download and pipe to shell patterns
  • AppleScript execution abuse (osascript -e)
  • Scripting language one-liners (Python, Perl with -c or -e)
  • Execution from temp directories (/tmp, /private/tmp)
  • Reverse shell indicators (netcat, /dev/tcp/ redirection)
  • Background process persistence
  • Code signature validation and bundle identifier analysis

MITRE ATT&CK Mapping:

  • T1543.001 - Create or Modify System Process: Launch Agent/Daemon
  • T1547.015 - Boot or Logon Autostart Execution: Login Items
  • T1059.004 - Command and Scripting Interpreter: Unix Shell
  • T1105 - Ingress Tool Transfer

Result

Screenshot 2025-11-21 at 13 46 29

Query returns prioritized results with LotL indicators first, then unsigned/non-Apple signed items. Includes detection method, detection reason, code signature status, file hashes, ownership, permissions, and timestamps.

Platform

darwin

Interval

3600 seconds (1 hour)

Query ID

startup_items_darwin_elastic

ECS Field Mappings

  • process.namename
  • process.executablepath
  • file.pathpath
  • file.hash.sha256sha256
  • file.hash.sha1sha1
  • file.hash.md5md5
  • file.sizesize
  • file.mtimemtime
  • file.ctimectime
  • file.uiduid
  • file.gidgid
  • file.modemode
  • user.nameusername
  • rule.categorytype
  • event.outcomestatus
  • code_signature.signedsigned
  • code_signature.subject_nameidentifier
  • registry.pathsource
  • event.categorydetection_method
  • rule.descriptiondetection_reason

SQL Query

-- Dual-detection macOS persistence query:
-- 1. NON_WHITELISTED: Non-Apple signed LaunchAgents/Daemons (signature-based filtering)
-- 2. LOTL_INDICATOR: Living off the Land patterns (bash -c, curl | bash, osascript, etc.)
-- MITRE ATT&CK: T1543.001, T1547.015, T1059.004, T1105

WITH non_whitelisted_launchd AS (
    SELECT
        l.label AS name,
        COALESCE(NULLIF(l.program, ''), l.program_arguments) AS path,
        l.path AS source,
        l.program_arguments AS args,
        l.username,
        CASE
            WHEN l.disabled = '1' OR l.disabled = 1 THEN 'disabled'
            WHEN l.run_at_load = 'true' OR l.run_at_load = '1' OR l.run_at_load = 1 THEN 'enabled'
            ELSE 'unknown'
        END AS status,
        'Launch Agent/Daemon' AS type,
        'NON_WHITELISTED' AS detection_method,
        'Non-Apple signed LaunchAgent/Daemon' AS detection_reason
    FROM launchd AS l
    WHERE (
        (l.program IS NOT NULL AND l.program != '')
        OR (l.program_arguments IS NOT NULL AND l.program_arguments != '')
    )
        AND l.path NOT LIKE '/System/Library/%'
        AND l.path NOT LIKE '/Library/Apple/%'
        AND (l.run_at_load = 'true' OR l.run_at_load = '1' OR l.run_at_load = 1 OR l.run_at_load IS NOT NULL)
),
non_whitelisted_startup AS (
    SELECT
        si.name,
        si.path,
        si.source,
        si.args,
        si.username,
        si.status,
        CASE
            WHEN si.type = 'Startup Item' THEN 'Legacy Startup Item'
            WHEN si.type = 'Login Item' THEN 'Login Item'
            ELSE si.type
        END AS type,
        'NON_WHITELISTED' AS detection_method,
        'Legacy startup/login item' AS detection_reason
    FROM startup_items AS si
    WHERE si.path IS NOT NULL
        AND si.path != ''
        AND si.path NOT LIKE '/System/Library/%'
        AND si.path NOT LIKE '/Library/Apple/%'
),
lotl_launchd AS (
    SELECT
        l.label AS name,
        COALESCE(NULLIF(l.program, ''), l.program_arguments) AS path,
        l.path AS source,
        l.program_arguments AS args,
        l.username,
        CASE
            WHEN l.disabled = '1' OR l.disabled = 1 THEN 'disabled'
            WHEN l.run_at_load = 'true' OR l.run_at_load = '1' OR l.run_at_load = 1 THEN 'enabled'
            ELSE 'unknown'
        END AS status,
        'Launch Agent/Daemon (LotL)' AS type,
        'LOTL_INDICATOR' AS detection_method,
        CASE
            WHEN l.program_arguments LIKE '%bash -c%' OR l.program_arguments LIKE '%sh -c%' THEN 'Shell command execution via -c flag'
            WHEN l.program_arguments LIKE '%curl%|%bash%' OR l.program_arguments LIKE '%curl%|%sh%' THEN 'Download and pipe to shell'
            WHEN l.program_arguments LIKE '%curl%http%' OR l.program_arguments LIKE '%wget%http%' THEN 'Download utility abuse'
            WHEN l.program_arguments LIKE '%base64 -D%' OR l.program_arguments LIKE '%base64 --decode%' THEN 'Base64 decode for obfuscation'
            WHEN l.program_arguments LIKE '%osascript%' AND l.program_arguments LIKE '%-e%' THEN 'AppleScript execution abuse'
            WHEN l.program_arguments LIKE '%python%-%c%' OR l.program_arguments LIKE '%perl%-%e%' THEN 'Scripting language one-liner'
            WHEN l.program_arguments LIKE '%/tmp/%' OR l.program_arguments LIKE '%/private/tmp/%' THEN 'Execution from temp directory'
            WHEN l.program_arguments LIKE '%/dev/tcp/%' THEN 'Bash TCP socket redirection'
            WHEN l.program_arguments LIKE '%nc %' OR l.program_arguments LIKE '%netcat%' THEN 'Netcat reverse shell'
            WHEN l.program_arguments LIKE '%nohup%&%' OR l.program_arguments LIKE '%disown%' THEN 'Background process persistence'
            WHEN l.program_arguments LIKE '%.sh%' AND (COALESCE(NULLIF(l.program, ''), l.program_arguments) LIKE '/tmp/%' OR COALESCE(NULLIF(l.program, ''), l.program_arguments) LIKE '/private/tmp/%') THEN 'Shell script from temp directory'
            ELSE 'Unknown LotL pattern in LaunchAgent'
        END AS detection_reason
    FROM launchd AS l
    WHERE (
        (l.program IS NOT NULL AND l.program != '')
        OR (l.program_arguments IS NOT NULL AND l.program_arguments != '')
    )
        AND (l.run_at_load = 'true' OR l.run_at_load = '1' OR l.run_at_load = 1 OR l.run_at_load IS NOT NULL)
        AND (
            l.program_arguments LIKE '%bash -c%'
            OR l.program_arguments LIKE '%sh -c%'
            OR l.program_arguments LIKE '%curl%|%bash%'
            OR l.program_arguments LIKE '%curl%|%sh%'
            OR l.program_arguments LIKE '%curl%http%'
            OR l.program_arguments LIKE '%wget%http%'
            OR l.program_arguments LIKE '%base64 -D%'
            OR l.program_arguments LIKE '%base64 --decode%'
            OR (l.program_arguments LIKE '%osascript%' AND l.program_arguments LIKE '%-e%')
            OR l.program_arguments LIKE '%python%-%c%'
            OR l.program_arguments LIKE '%perl%-%e%'
            OR l.program_arguments LIKE '%/tmp/%'
            OR l.program_arguments LIKE '%/private/tmp/%'
            OR l.program_arguments LIKE '%/dev/tcp/%'
            OR l.program_arguments LIKE '%nc %'
            OR l.program_arguments LIKE '%netcat%'
            OR l.program_arguments LIKE '%nohup%&%'
            OR l.program_arguments LIKE '%disown%'
            OR (l.program_arguments LIKE '%.sh%' AND (COALESCE(NULLIF(l.program, ''), l.program_arguments) LIKE '/tmp/%' OR COALESCE(NULLIF(l.program, ''), l.program_arguments) LIKE '/private/tmp/%'))
        )
),
combined AS (
    SELECT * FROM non_whitelisted_launchd
    UNION ALL
    SELECT * FROM non_whitelisted_startup
    UNION ALL
    SELECT * FROM lotl_launchd
)
SELECT
    c.name,
    c.path,
    c.type,
    c.status,
    c.source,
    c.args,
    c.username,
    c.detection_method,
    c.detection_reason,
    s.signed,
    s.identifier,
    h.sha256,
    h.sha1,
    h.md5,
    f.size,
    f.mtime,
    f.ctime,
    f.uid,
    f.gid,
    f.mode
FROM combined AS c
LEFT JOIN signature AS s ON c.path = s.path
LEFT JOIN hash AS h ON c.path = h.path
LEFT JOIN file AS f ON c.path = f.path
WHERE (
    c.detection_method = 'LOTL_INDICATOR'
    OR s.signed IS NULL
    OR s.signed = 0
    OR (
        s.identifier IS NOT NULL
        AND s.identifier NOT LIKE 'com.apple.%'
        AND s.identifier NOT LIKE 'Apple Inc.%'
    )
)
ORDER BY
    CASE WHEN c.detection_method = 'LOTL_INDICATOR' THEN 0 ELSE 1 END,
    CASE WHEN s.signed = 0 OR s.signed IS NULL THEN 0 ELSE 1 END,
    c.detection_reason,
    c.name

Detection Value Proposition

Why These Queries Matter:

  1. Persistence is a Critical Detection Point: Adversaries must establish persistence to maintain access. These queries detect the most common persistence mechanisms across all major platforms.

  2. Dual-Detection Approach: Combines two complementary detection strategies:

    • Signature-based filtering: Catches unknown/untrusted executables
    • LotL pattern recognition: Detects abuse of legitimate tools, which often bypasses signature-based defenses
  3. Cross-Platform Coverage: Unified detection approach across Windows, macOS, and Linux enables consistent threat hunting workflows.

  4. Actionable Context: Each detection includes the specific reason (e.g., "PowerShell base64 encoded command", "Download and pipe to shell"), enabling rapid analyst triage.

  5. MITRE ATT&CK Alignment: Direct mapping to persistence techniques enables threat-informed defense and ATT&CK Navigator integration.

References

This PR was AI assisted with Claude Code

@tomsonpl tomsonpl self-assigned this Nov 21, 2025
@tomsonpl tomsonpl added documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:osquery_manager Osquery Manager labels Nov 21, 2025
@tomsonpl tomsonpl marked this pull request as ready for review November 21, 2025 12:48
@tomsonpl tomsonpl requested a review from a team as a code owner November 21, 2025 12:48
@tomsonpl tomsonpl requested review from ashokaditya and szwarckonrad and removed request for a team November 21, 2025 12:48
@elasticmachine
Copy link

💚 Build Succeeded

cc @tomsonpl

@raqueltabuyo
Copy link

I can see you have used startup_items for Windows and MacOS but not Linux, what was the reason for that? Are we confident that there is no data missing using another table that it is not startup_items?

@tomsonpl
Copy link
Contributor Author

I can see you have used startup_items for Windows and MacOS but not Linux, what was the reason for that? Are we confident that there is no data missing using another table that it is not startup_items?

From my investigation:

  1. Limited Linux coverage: The startup_items table on Linux primarily exposes systemd units, but with less granularity
    than querying systemd_units directly
  2. Missing persistence mechanisms: startup_items doesn't capture:
    - Cron @reboot jobs
    - XDG autostart entries (~/.config/autostart/*.desktop)
    - User-specific systemd services in detail
  3. Dual-detection: We needed fine-grained access to systemd_units.fragment_path and
    systemd_units.description for LotL pattern detection, which startup_items doesn't provide

However we might add this table anyway, and just use UNION to gather more results.

Is this what you'd prefer @raqueltabuyo ?

@andrewkroh andrewkroh added the Team:Defend Workflows Security team for Endpoint and OSQuery workflows [elastic/security-defend-workflows] label Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:osquery_manager Osquery Manager Team:Defend Workflows Security team for Endpoint and OSQuery workflows [elastic/security-defend-workflows]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants