Detection rules › Elastic

Script Executed Through Unusual Parent Process

Source
github.com/elastic/protections-artifacts

This rule detects the execution of scripts by interpreters like Perl, Python, PHP, Ruby, and Lua, when the parent process is located in an unusual location, or the parent process is hidden. This behavior is often seen in malware that is trying to evade detection by executing scripts from temporary directories or hidden locations.

MITRE ATT&CK coverage

Rule body

[rule]
description = """
This rule detects the execution of scripts by interpreters like Perl, Python, PHP, Ruby, and Lua, when the parent
process is located in an unusual location, or the parent process is hidden. This behavior is often seen in malware that
is trying to evade detection by executing scripts from temporary directories or hidden locations.
"""
id = "133102a7-f906-4725-b382-09257a0209c2"
license = "Elastic License v2"
name = "Script Executed Through Unusual Parent Process"
os_list = ["linux"]
version = "1.0.10"

query = '''
process where event.type == "start" and event.action == "exec" and process.args_count == 1 and process.executable like (
   "/bin/perl*", "/usr/bin/perl*", "/usr/local/bin/perl*",
   "/bin/python*", "/usr/bin/python*", "/usr/local/bin/python*",
   "/bin/php*", "/usr/bin/php*", "/usr/local/bin/php*",
   "/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*",
   "/bin/lua*", "/usr/bin/lua*", "/usr/local/bin/lua*"
 ) and
 (process.parent.executable like ("/tmp/*", "/var/tmp/*", "/dev/shm/*", "./*", "/boot/*") or process.parent.name like ".*") and
 not (
   process.parent.executable like~ (
     "/tmp/newroot/*", "./merged/*", "/var/tmp/.mount_*/AppRun", "/tmp/.mount_cursor*/usr/bin//cursor",
     "/tmp/baum/easybuild/*/perl", "/var/tmp/buildah*", "/tmp/taddm/fileinfo*", "/tmp/wbrashear/easybuild/*",
     "/tmp/.mount_cursor*/usr/share/cursor/cursor"
   ) or
   process.parent.name in ("gogo", "nvim", "build-script-build", "jetbrains-toolbox", "runner") or
   process.parent.command_line in ("runc init", "/usr/local/bin/runc init") or
   (process.parent.args == "/usr/bin/crun" and process.working_directory == "/ansible")
)
'''

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

[[actions]]
action = "kill_process"
field = "process.parent.entity_id"
state = 0

[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[threat.technique.subtechnique]]
id = "T1059.004"
name = "Unix Shell"
reference = "https://attack.mitre.org/techniques/T1059/004/"



[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1071"
name = "Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1071/"


[threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"

[internal]
min_endpoint_version = "7.15.0"

Stages and Predicates

Stage 1: process

process where event.type == "start" and event.action == "exec" and process.args_count == 1 and process.executable like (
   "/bin/perl*", "/usr/bin/perl*", "/usr/local/bin/perl*",
   "/bin/python*", "/usr/bin/python*", "/usr/local/bin/python*",
   "/bin/php*", "/usr/bin/php*", "/usr/local/bin/php*",
   "/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*",
   "/bin/lua*", "/usr/bin/lua*", "/usr/local/bin/lua*"
 ) and
 (process.parent.executable like ("/tmp/*", "/var/tmp/*", "/dev/shm/*", "./*", "/boot/*") or process.parent.name like ".*") and
 not (
   process.parent.executable like~ (
     "/tmp/newroot/*", "./merged/*", "/var/tmp/.mount_*/AppRun", "/tmp/.mount_cursor*/usr/bin//cursor",
     "/tmp/baum/easybuild/*/perl", "/var/tmp/buildah*", "/tmp/taddm/fileinfo*", "/tmp/wbrashear/easybuild/*",
     "/tmp/.mount_cursor*/usr/share/cursor/cursor"
   ) or
   process.parent.name in ("gogo", "nvim", "build-script-build", "jetbrains-toolbox", "runner") or
   process.parent.command_line in ("runc init", "/usr/local/bin/runc init") or
   (process.parent.args == "/usr/bin/crun" and process.working_directory == "/ansible")
)

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.parent.argseq/usr/bin/crunexcludes:process.parent.args field:"process.parent.args" value:"/usr/bin/crun"
process.working_directoryeq/ansibleexcludes:process.working_directory field:"process.working_directory" value:"/ansible"
process.parent.command_linein/usr/local/bin/runc init, runc initexcludes:process.parent.command_line field:"process.parent.command_line" value:"/usr/local/bin/runc init" field:"process.parent.command_line" value:"runc init"
process.parent.executablewildcard/tmp/newroot/*, ./merged/*, /var/tmp/.mount_*/AppRun, /tmp/.mount_cursor*/usr/bin//cursor, /tmp/baum/easybuild/*/perl, /var/tmp/buildah*, /tmp/taddm/fileinfo*, /tmp/wbrashear/easybuild/*, /tmp/.mount_cursor*/usr/share/cursor/cursorexcludes:process.parent.executable
process.parent.nameinbuild-script-build, gogo, jetbrains-toolbox, nvim, runnerexcludes:process.parent.name

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event.actioneq
  • exec
field:"EventType" kind:eq value:"exec"
event.typeeq
  • start
field:"event.type" kind:eq value:"start"
process.args_counteq
  • 1 transforms: number
field:"process.args_count" kind:eq value:"1"
process.executablewildcard
  • /bin/lua*
  • /bin/perl*
  • /bin/php*
  • /bin/python*
  • /bin/ruby*
  • /usr/bin/lua*
  • /usr/bin/perl*
  • /usr/bin/php*
  • /usr/bin/python*
  • /usr/bin/ruby*
  • /usr/local/bin/lua*
  • /usr/local/bin/perl*
  • /usr/local/bin/php*
  • /usr/local/bin/python*
  • /usr/local/bin/ruby*
field:"Image" kind:wildcard
process.parent.executablewildcard
  • ./*
  • /boot/*
  • /dev/shm/*
  • /tmp/*
  • /var/tmp/*
field:"ParentImage" kind:wildcard
process.parent.namewildcard
  • .*
field:"parent_process_name" kind:wildcard value:".*"