Detection rules › Elastic

Udev Execution Followed by Egress Network Connection

Time window
3s
Sequence by
process.entity_id
Source
github.com/elastic/protections-artifacts

This rule detects a process execution by udev followed by a network connection. Udev is a device manager for the Linux kernel that manages device nodes in /dev. Udev is responsible for creating and removing device nodes in /dev when devices are added or removed from the system. Udev executes scripts when devices are added or removed from the system. An attacker may abuse udev to execute malicious scripts to establish a network connection to a command and control server.

MITRE ATT&CK coverage

Rule body

[rule]
description = """
This rule detects a process execution by udev followed by a network connection. Udev is a device manager for the Linux
kernel that manages device nodes in /dev. Udev is responsible for creating and removing device nodes in /dev when
devices are added or removed from the system. Udev executes scripts when devices are added or removed from the system.
An attacker may abuse udev to execute malicious scripts to establish a network connection to a command and control
server.
"""
id = "21984abc-9efa-4de1-b1ad-bf797a7acec9"
license = "Elastic License v2"
name = "Udev Execution Followed by Egress Network Connection"
os_list = ["linux"]
reference = [
    "https://ch4ik0.github.io/en/posts/leveraging-Linux-udev-for-persistence/",
    "https://www.elastic.co/security-labs/sequel-on-persistence-mechanisms",
]
version = "1.0.12"

query = '''
sequence by process.entity_id with maxspan=3s
  [process where event.type == "start" and event.action == "exec" and
   descendant of [process where event.action == "exec" and process.name == "udevadm"] and not (
     process.parent.executable == "/etc/telegraf/get-service-status.sh" or
     process.args == "/sbin/vz-motd" or
     process.command_line like "*petalinux.xilinx.com*"
   )
  ]
  [network where event.type == "start" and event.action == "connection_attempted" and not (
     destination.ip == null or
     destination.ip == "0.0.0.0" or
     cidrmatch(
     destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29",
     "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24",
     "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10",
     "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10",
     "FF00::/8", "172.31.0.0/16"
     ) or
     process.name == "go" or
     process.executable like (
       "/var/lib/docker/overlay2/*gitlab-runner-helper", "/opt/tm/tools/go/usr/bin/go*", "/var/lib/docker/overlay2/*/aws_signing_helper",
       "/home/*/cpython/*/python3", "/var/opt/gitlab/*", "/home/*/core3/src/plz-out/*/usr/python3.10/bin/python3*"
     ) or
     process.executable in (
       "/usr/local/bin/rclone", "/usr/lib/git/git-remote-https", "/usr/lib/apt/methods/https", "/usr/lib/apt/methods/http",
       "/usr/sbin/send_nsca", "/usr/libexec/git-core/git-remote-http"
     )
   )
  ]
'''

min_endpoint_version = "7.15.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.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 = "T1037"
name = "Boot or Logon Initialization Scripts"
reference = "https://attack.mitre.org/techniques/T1037/"


[threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[[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

Ordered sequence: each step below must occur in order within 3s, correlated by process.entity_id.

Stage 1: process

[process where event.type == "start" and event.action == "exec" and
   descendant of [process where event.action == "exec" and process.name == "udevadm"] and not (
     process.parent.executable == "/etc/telegraf/get-service-status.sh" or
     process.args == "/sbin/vz-motd" or
     process.command_line like "*petalinux.xilinx.com*"
   )
  ]

Stage 2: network

[network where event.type == "start" and event.action == "connection_attempted" and not (
     destination.ip == null or
     destination.ip == "0.0.0.0" or
     cidrmatch(
     destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29",
     "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24",
     "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10",
     "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10",
     "FF00::/8", "172.31.0.0/16"
     ) or
     process.name == "go" or
     process.executable like (
       "/var/lib/docker/overlay2/*gitlab-runner-helper", "/opt/tm/tools/go/usr/bin/go*", "/var/lib/docker/overlay2/*/aws_signing_helper",
       "/home/*/cpython/*/python3", "/var/opt/gitlab/*", "/home/*/core3/src/plz-out/*/usr/python3.10/bin/python3*"
     ) or
     process.executable in (
       "/usr/local/bin/rclone", "/usr/lib/git/git-remote-https", "/usr/lib/apt/methods/https", "/usr/lib/apt/methods/http",
       "/usr/sbin/send_nsca", "/usr/libexec/git-core/git-remote-http"
     )
   )
  ]

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.argseq/sbin/vz-motdexcludes:process.args field:"process.args" value:"/sbin/vz-motd"
process.command_linematchpetalinux.xilinx.comexcludes:process.command_line field:"process.command_line" value:"petalinux.xilinx.com"
process.parent.executableeq/etc/telegraf/get-service-status.shexcludes:process.parent.executable field:"process.parent.executable" value:"/etc/telegraf/get-service-status.sh"
destination.ipcidr_match10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.0.0/29, 192.0.0.8/32, 192.0.0.9/32, 192.0.0.10/32, 192.0.0.170/32, 192.0.0.171/32, 192.0.2.0/24, 192.31.196.0/24, 192.52.193.0/24, 192.168.0.0/16, 192.88.99.0/24, 224.0.0.0/4, 100.64.0.0/10, 192.175.48.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::1, FE80::/10, FF00::/8, 172.31.0.0/16excludes:destination.ip
destination.ipeq0.0.0.0excludes:destination.ip field:"destination.ip" value:"0.0.0.0"
destination.ipis_null(no value, null check)excludes:destination.ip
process.executablein/usr/lib/apt/methods/http, /usr/lib/apt/methods/https, /usr/lib/git/git-remote-https, /usr/libexec/git-core/git-remote-http, /usr/local/bin/rclone, /usr/sbin/send_nscaexcludes:process.executable
process.executablewildcard/var/lib/docker/overlay2/*gitlab-runner-helper, /opt/tm/tools/go/usr/bin/go*, /var/lib/docker/overlay2/*/aws_signing_helper, /home/*/cpython/*/python3, /var/opt/gitlab/*, /home/*/core3/src/plz-out/*/usr/python3.10/bin/python3*excludes:process.executable
process.nameeqgoexcludes:process.name field:"process.name" value:"go"

Indicators

These rows show field, operator, and value matches.