Detection rules › Elastic

Suspicious Ruby Command Execution

Source
github.com/elastic/protections-artifacts

This rule monitors for suspicious Ruby command executions by detecting the start of a Ruby process with a command line argument that contains keywords commonly used by attackers to execute malicious code. These command line arguments include operations to execute code, create subprocesses, and encode or decode data.

MITRE ATT&CK coverage

Rule body

[rule]
description = """
This rule monitors for suspicious Ruby command executions by detecting the start of a Ruby process with a command line
argument that contains keywords commonly used by attackers to execute malicious code. These command line arguments
include operations to execute code, create subprocesses, and encode or decode data.
"""
id = "a3a3b49c-c135-4959-8a1b-33392bb60991"
license = "Elastic License v2"
name = "Suspicious Ruby Command Execution"
os_list = ["linux"]
version = "1.0.9"

query = '''
process where event.type == "start" and event.action == "exec" and process.parent.executable != null and
process.executable like~ ("/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*") and
process.args like "-e*" and process.command_line like~ (
  "*system(*", "*exec(*", "*IO.popen(*", "*Open3.popen3(*", "*spawn(*", "*eval(*", "*load(*",
  "*Marshal.load(*", "*Fiddle.dlopen(*", "*Fiddle::Function.new(*", "*base64*", "*zlib*", 
  "*net/http*", "*socket*", "*open-uri*", "*pack(*", "*unpack(*"
) and
not (
  process.working_directory like~ ("/etc/puppet/rack", "/builds/*", "/var/tmp/portage/*") or
  process.command_line like ("*rails_env*", "*pid*Process.spawn*ssh*StrictHostKeyChecking*ServerAliveInterval*ServerAliveCountMax*") or
  process.command_line == "ruby -e require \"yaml\"; YAML.safe_load(File.read(\".gitlab-ci.yml\"), aliases: true)" or
  process.parent.args like "/home/*/.vscode-server/cli/servers/Stable-*" or
  process.parent.command_line in ("emacs --daemon", "runc init") or
  process.parent.name in ("emacs-gtk", "mmonit", "make") or
  (process.name == "ruby" and process.parent.name == "ruby") or
  process.parent.executable in ("/opt/gitlab/embedded/bin/gitaly", "/usr/bin/runc") or
  (
    process.working_directory == "/workspace" and
    process.parent.executable like ("/home/*/dev/*/rollcage", "/tmp/rollcage-target/debug/rollcage")
  )
)
'''

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.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"

[internal]
min_endpoint_version = "7.15.0"

Stages and Predicates

Stage 1: process

process where event.type == "start" and event.action == "exec" and process.parent.executable != null and
process.executable like~ ("/bin/ruby*", "/usr/bin/ruby*", "/usr/local/bin/ruby*") and
process.args like "-e*" and process.command_line like~ (
  "*system(*", "*exec(*", "*IO.popen(*", "*Open3.popen3(*", "*spawn(*", "*eval(*", "*load(*",
  "*Marshal.load(*", "*Fiddle.dlopen(*", "*Fiddle::Function.new(*", "*base64*", "*zlib*", 
  "*net/http*", "*socket*", "*open-uri*", "*pack(*", "*unpack(*"
) and
not (
  process.working_directory like~ ("/etc/puppet/rack", "/builds/*", "/var/tmp/portage/*") or
  process.command_line like ("*rails_env*", "*pid*Process.spawn*ssh*StrictHostKeyChecking*ServerAliveInterval*ServerAliveCountMax*") or
  process.command_line == "ruby -e require \"yaml\"; YAML.safe_load(File.read(\".gitlab-ci.yml\"), aliases: true)" or
  process.parent.args like "/home/*/.vscode-server/cli/servers/Stable-*" or
  process.parent.command_line in ("emacs --daemon", "runc init") or
  process.parent.name in ("emacs-gtk", "mmonit", "make") or
  (process.name == "ruby" and process.parent.name == "ruby") or
  process.parent.executable in ("/opt/gitlab/embedded/bin/gitaly", "/usr/bin/runc") or
  (
    process.working_directory == "/workspace" and
    process.parent.executable like ("/home/*/dev/*/rollcage", "/tmp/rollcage-target/debug/rollcage")
  )
)

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.nameeqrubyexcludes:process.name field:"process.name" value:"ruby"
process.parent.nameeqrubyexcludes:process.parent.name field:"process.parent.name" value:"ruby"
process.parent.executablewildcard/home/*/dev/*/rollcage, /tmp/rollcage-target/debug/rollcageexcludes:process.parent.executable field:"process.parent.executable" value:"/home/*/dev/*/rollcage" field:"process.parent.executable" value:"/tmp/rollcage-target/debug/rollcage"
process.working_directoryeq/workspaceexcludes:process.working_directory field:"process.working_directory" value:"/workspace"
process.command_lineeqruby -e require "yaml"; YAML.safe_load(File.read(".gitlab-ci.yml"), aliases: true)excludes:process.command_line
process.command_linewildcard*rails_env*, *pid*Process.spawn*ssh*StrictHostKeyChecking*ServerAliveInterval*ServerAliveCountMax*excludes:process.command_line field:"process.command_line" value:"*rails_env*" field:"process.command_line" value:"*pid*Process.spawn*ssh*StrictHostKeyChecking*ServerAliveInterval*ServerAliveCountMax*"
process.parent.argswildcard/home/*/.vscode-server/cli/servers/Stable-*excludes:process.parent.args field:"process.parent.args" value:"/home/*/.vscode-server/cli/servers/Stable-*"
process.parent.command_lineinemacs --daemon, runc initexcludes:process.parent.command_line field:"process.parent.command_line" value:"emacs --daemon" field:"process.parent.command_line" value:"runc init"
process.parent.executablein/opt/gitlab/embedded/bin/gitaly, /usr/bin/runcexcludes:process.parent.executable field:"process.parent.executable" value:"/opt/gitlab/embedded/bin/gitaly" field:"process.parent.executable" value:"/usr/bin/runc"
process.parent.nameinemacs-gtk, make, mmonitexcludes:process.parent.name field:"process.parent.name" value:"emacs-gtk" field:"process.parent.name" value:"make" field:"process.parent.name" value:"mmonit"
process.working_directorywildcard/etc/puppet/rack, /builds/*, /var/tmp/portage/*excludes:process.working_directory field:"process.working_directory" value:"/etc/puppet/rack" field:"process.working_directory" value:"/builds/*" field:"process.working_directory" value:"/var/tmp/portage/*"

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.argswildcard
  • -e*
field:"process.args" kind:wildcard value:"-e*"
process.command_linewildcard
  • *Fiddle.dlopen(*
  • *Fiddle::Function.new(*
  • *IO.popen(*
  • *Marshal.load(*
  • *Open3.popen3(*
  • *base64*
  • *eval(*
  • *exec(*
  • *load(*
  • *net/http*
  • *open-uri*
  • *pack(*
  • *socket*
  • *spawn(*
  • *system(*
  • *unpack(*
  • *zlib*
field:"CommandLine" kind:wildcard
process.executablewildcard
  • /bin/ruby*
  • /usr/bin/ruby*
  • /usr/local/bin/ruby*
field:"Image" kind:wildcard
process.parent.executableis_not_null
  • (no value, null check)
field:"ParentImage" kind:is_not_null