Detection rules › Elastic

Potential Persistence via Direct Crontab Modification

Source
github.com/elastic/protections-artifacts

Detects the modification of the crontab file. Attackers can modify the crontab file to execute commands at specific times or intervals to maintain persistence on the system. Modifying the crontab directly is uncommon, and abused by attackers to automate persistence.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

[rule]
description = """
Detects the modification of the crontab file. Attackers can modify the crontab file to execute commands at specific
times or intervals to maintain persistence on the system. Modifying the crontab directly is uncommon, and abused by
attackers to automate persistence.
"""
id = "b3bcbab6-e216-4d70-bdee-2b69affbb386"
license = "Elastic License v2"
name = "Potential Persistence via Direct Crontab Modification"
os_list = ["linux", "macos"]
version = "1.0.12"

query = '''
process where event.type == "start" and event.action == "exec" and process.name == "crontab" and process.args == "-" and
process.parent.executable like (
  "./*", "/dev/shm/*", "/tmp/*", "/var/tmp/*", "/boot/*", "/etc/cron*", "/etc/init.d/*", "/etc/update-motd.d/*",
  "/srv/*", "/var/log/*", "/var/www/*", "/home/*/.*"
) and not (
  process.parent.executable in (
    "/var/www/html/admin/modules/iotserver/bin/check_license.php",
    "/tmp/newroot/opt/puppetlabs/puppet/bin/puppet",
    "/tmp/package/install.sh",
    "/tmp/newroot/usr/sbin/veeamworker",
    "/tmp/newroot/usr/sbin/veeamservice"
  ) or
  process.parent.command_line in (
    "/bin/bash +x ./ninja-deb-uninstall.sh", "./update-cronjobs.sh", "/bin/bash ./leip.sh", "/bin/bash ./2leip.sh"
  ) or
  process.parent.name == "bundle" or
  process.working_directory == "/opt/microsoft/mdatp/conf" or
  process.parent.args like "/var/lib/dpkg/*" or
  process.env_vars == "LD_LIBRARY_PATH=/opt/bmc/bladelogic/RSCD/lib" or
  process.parent.executable like (
    "/home/*/.local/share/uv/python/cpython-*-linux-x86_64-gnu/bin/python*",
    "/home/*/.rbenv/versions/*/bin/ruby"
  )
)
'''

min_endpoint_version = "8.7.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0

[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1053"
name = "Scheduled Task/Job"
reference = "https://attack.mitre.org/techniques/T1053/"
[[threat.technique.subtechnique]]
id = "T1053.003"
name = "Cron"
reference = "https://attack.mitre.org/techniques/T1053/003/"



[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1053"
name = "Scheduled Task/Job"
reference = "https://attack.mitre.org/techniques/T1053/"
[[threat.technique.subtechnique]]
id = "T1053.003"
name = "Cron"
reference = "https://attack.mitre.org/techniques/T1053/003/"



[threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1053"
name = "Scheduled Task/Job"
reference = "https://attack.mitre.org/techniques/T1053/"
[[threat.technique.subtechnique]]
id = "T1053.003"
name = "Cron"
reference = "https://attack.mitre.org/techniques/T1053/003/"



[threat.tactic]
id = "TA0004"
name = "Privilege Escalation"
reference = "https://attack.mitre.org/tactics/TA0004/"

[internal]
min_endpoint_version = "8.7.0"

Stages and Predicates

Stage 1: process

process where event.type == "start" and event.action == "exec" and process.name == "crontab" and process.args == "-" and
process.parent.executable like (
  "./*", "/dev/shm/*", "/tmp/*", "/var/tmp/*", "/boot/*", "/etc/cron*", "/etc/init.d/*", "/etc/update-motd.d/*",
  "/srv/*", "/var/log/*", "/var/www/*", "/home/*/.*"
) and not (
  process.parent.executable in (
    "/var/www/html/admin/modules/iotserver/bin/check_license.php",
    "/tmp/newroot/opt/puppetlabs/puppet/bin/puppet",
    "/tmp/package/install.sh",
    "/tmp/newroot/usr/sbin/veeamworker",
    "/tmp/newroot/usr/sbin/veeamservice"
  ) or
  process.parent.command_line in (
    "/bin/bash +x ./ninja-deb-uninstall.sh", "./update-cronjobs.sh", "/bin/bash ./leip.sh", "/bin/bash ./2leip.sh"
  ) or
  process.parent.name == "bundle" or
  process.working_directory == "/opt/microsoft/mdatp/conf" or
  process.parent.args like "/var/lib/dpkg/*" or
  process.env_vars == "LD_LIBRARY_PATH=/opt/bmc/bladelogic/RSCD/lib" or
  process.parent.executable like (
    "/home/*/.local/share/uv/python/cpython-*-linux-x86_64-gnu/bin/python*",
    "/home/*/.rbenv/versions/*/bin/ruby"
  )
)

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.env_varseqLD_LIBRARY_PATH=/opt/bmc/bladelogic/RSCD/libexcludes:process.env_vars field:"process.env_vars" value:"LD_LIBRARY_PATH=/opt/bmc/bladelogic/RSCD/lib"
process.parent.argsstarts_with/var/lib/dpkg/excludes:process.parent.args field:"process.parent.args" value:"/var/lib/dpkg/"
process.parent.command_linein./update-cronjobs.sh, /bin/bash +x ./ninja-deb-uninstall.sh, /bin/bash ./2leip.sh, /bin/bash ./leip.shexcludes:process.parent.command_line
process.parent.executablein/tmp/newroot/opt/puppetlabs/puppet/bin/puppet, /tmp/newroot/usr/sbin/veeamservice, /tmp/newroot/usr/sbin/veeamworker, /tmp/package/install.sh, /var/www/html/admin/modules/iotserver/bin/check_license.phpexcludes:process.parent.executable
process.parent.executablewildcard/home/*/.local/share/uv/python/cpython-*-linux-x86_64-gnu/bin/python*, /home/*/.rbenv/versions/*/bin/rubyexcludes:process.parent.executable field:"process.parent.executable" value:"/home/*/.local/share/uv/python/cpython-*-linux-x86_64-gnu/bin/python*" field:"process.parent.executable" value:"/home/*/.rbenv/versions/*/bin/ruby"
process.parent.nameeqbundleexcludes:process.parent.name field:"process.parent.name" value:"bundle"
process.working_directoryeq/opt/microsoft/mdatp/confexcludes:process.working_directory field:"process.working_directory" value:"/opt/microsoft/mdatp/conf"

Indicators

These rows show field, operator, and value matches.