Detection rules › Elastic

DNS Request to Dynamic DNS via Suspicious Executable

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

This rule detects DNS queries to dynamic DNS services via living-off-the-land executables or executables in world/user-writable directories. Malware authors may use these requests to communicate with command and control infrastructure or to exfiltrate data from the target system.

MITRE ATT&CK coverage

Rule body

[rule]
description = """
This rule detects DNS queries to dynamic DNS services via living-off-the-land executables or executables in
world/user-writable directories. Malware authors may use these requests to communicate with command and control
infrastructure or to exfiltrate data from the target system.
"""
id = "b85d016e-3a28-43bd-8fbf-cbb19b09dc46"
license = "Elastic License v2"
name = "DNS Request to Dynamic DNS via Suspicious Executable"
os_list = ["linux"]
reference = ["https://www.rapid7.com/blog/post/tr-new-whitepaper-stealthy-bpfdoor-variants/"]
version = "1.0.5"

query = '''
sequence by process.entity_id with maxspan=10s
  [process where event.type == "start" and event.action == "exec" and (
    process.name in ("curl", "wget", "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox", "timeout", "env") or
    process.name like (".*", "python*", "perl*", "php*", "ruby*", "lua*", "node", "deno") or
    process.executable like (
      "./*", "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/run/*", "/var/run/*", "/boot/*", "/sys/*",
      "/lost+found/*", "/proc/*", "/var/mail/*", "/var/www/*", "/home/*/*", "/root/*"
    )
  ) and
  not (
    (
      process.parent.name in ("bash", "node") and
      (
        process.working_directory in ("/usr/local/meshcentral", "/opt/meshcentral/meshcentral", "/usr/local/mesh_services/meshagent") or
        process.parent.args in ("/usr/local/meshcentral/node_modules/meshcentral", "/home/periodic/dyndns-noip.sh")
      )
    ) or
    (
      process.command_line == "python3 -m app.run_scheduled_update" and
      process.parent.args == "./workflow_unified.sh"
    ) or
    process.executable == "/usr/bin/qbittorrent-nox" or
    process.executable like "/snap/firefox/*/usr/lib/firefox/firefox" or
    (process.executable like "/usr/bin/php*" and process.args == "/var/tools/koalaping/bin/ping.php")
  )]
  [dns where event.action == "lookup_result" and dns.question.name like~ (
    "*.no-ip.com", "*.no-ip.org", "*.no-ip.biz", "*.no-ip.info", "*.noip.com", "*.afraid.org", "*.changeip.com",
    "*.ddns.net", "*.dyndns.org", "*.hopto.org", "*.zapto.org", "*.servehttp.com", "*.sytes.net", "*.myftp.biz",
    "*.myftp.org", "*.ddnsfree.com", "*.duckdns.org", "*.000webhostapp.com", "*.myddns.me", "*.dlinkddns.com",
    "*.chickenkiller.com", "*.thddns.net", "*.linkpc.net", "*.gotdns.ch", "*.dynv6.net", "*.dns.army",
    "*.dns.navy", "*.v6.army", "*.v6.navy", "*.v6.rocks", "*.dyndns-office.com", "*.myvnc.com", "*.is-certified.com",
    "*.instanthq.com", "*.ddnsgeek.com", "*.ygto.com", "*.casacam.com"
  )]
'''

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

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

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

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

[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1071"
name = "Application Layer Protocol"
reference = "https://attack.mitre.org/techniques/T1071/"
[[threat.technique.subtechnique]]
id = "T1071.004"
name = "DNS"
reference = "https://attack.mitre.org/techniques/T1071/004/"


[[threat.technique]]
id = "T1102"
name = "Web Service"
reference = "https://attack.mitre.org/techniques/T1102/"


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

[internal]
min_endpoint_version = "9.3.0"

Stages and Predicates

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

Stage 1: process

[process where event.type == "start" and event.action == "exec" and (
    process.name in ("curl", "wget", "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox", "timeout", "env") or
    process.name like (".*", "python*", "perl*", "php*", "ruby*", "lua*", "node", "deno") or
    process.executable like (
      "./*", "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/run/*", "/var/run/*", "/boot/*", "/sys/*",
      "/lost+found/*", "/proc/*", "/var/mail/*", "/var/www/*", "/home/*/*", "/root/*"
    )
  ) and
  not (
    (
      process.parent.name in ("bash", "node") and
      (
        process.working_directory in ("/usr/local/meshcentral", "/opt/meshcentral/meshcentral", "/usr/local/mesh_services/meshagent") or
        process.parent.args in ("/usr/local/meshcentral/node_modules/meshcentral", "/home/periodic/dyndns-noip.sh")
      )
    ) or
    (
      process.command_line == "python3 -m app.run_scheduled_update" and
      process.parent.args == "./workflow_unified.sh"
    ) or
    process.executable == "/usr/bin/qbittorrent-nox" or
    process.executable like "/snap/firefox/*/usr/lib/firefox/firefox" or
    (process.executable like "/usr/bin/php*" and process.args == "/var/tools/koalaping/bin/ping.php")
  )]

Stage 2: dns

[dns where event.action == "lookup_result" and dns.question.name like~ (
    "*.no-ip.com", "*.no-ip.org", "*.no-ip.biz", "*.no-ip.info", "*.noip.com", "*.afraid.org", "*.changeip.com",
    "*.ddns.net", "*.dyndns.org", "*.hopto.org", "*.zapto.org", "*.servehttp.com", "*.sytes.net", "*.myftp.biz",
    "*.myftp.org", "*.ddnsfree.com", "*.duckdns.org", "*.000webhostapp.com", "*.myddns.me", "*.dlinkddns.com",
    "*.chickenkiller.com", "*.thddns.net", "*.linkpc.net", "*.gotdns.ch", "*.dynv6.net", "*.dns.army",
    "*.dns.navy", "*.v6.army", "*.v6.navy", "*.v6.rocks", "*.dyndns-office.com", "*.myvnc.com", "*.is-certified.com",
    "*.instanthq.com", "*.ddnsgeek.com", "*.ygto.com", "*.casacam.com"
  )]

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
process.parent.argsin/home/periodic/dyndns-noip.sh, /usr/local/meshcentral/node_modules/meshcentralexcludes:process.parent.args field:"process.parent.args" value:"/home/periodic/dyndns-noip.sh" field:"process.parent.args" value:"/usr/local/meshcentral/node_modules/meshcentral"
process.working_directoryin/opt/meshcentral/meshcentral, /usr/local/mesh_services/meshagent, /usr/local/meshcentralexcludes:process.working_directory field:"process.working_directory" value:"/opt/meshcentral/meshcentral" field:"process.working_directory" value:"/usr/local/mesh_services/meshagent" field:"process.working_directory" value:"/usr/local/meshcentral"
process.parent.nameinbash, nodeexcludes:process.parent.name field:"process.parent.name" value:"bash" field:"process.parent.name" value:"node"
process.argseq/var/tools/koalaping/bin/ping.phpexcludes:process.args field:"process.args" value:"/var/tools/koalaping/bin/ping.php"
process.executablestarts_with/usr/bin/phpexcludes:process.executable field:"process.executable" value:"/usr/bin/php"
process.command_lineeqpython3 -m app.run_scheduled_updateexcludes:process.command_line field:"process.command_line" value:"python3 -m app.run_scheduled_update"
process.parent.argseq./workflow_unified.shexcludes:process.parent.args field:"process.parent.args" value:"./workflow_unified.sh"
process.executableeq/usr/bin/qbittorrent-noxexcludes:process.executable field:"process.executable" value:"/usr/bin/qbittorrent-nox"
process.executablewildcard/snap/firefox/*/usr/lib/firefox/firefoxexcludes:process.executable field:"process.executable" value:"/snap/firefox/*/usr/lib/firefox/firefox"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
dns.question.namewildcard
  • *.000webhostapp.com
  • *.afraid.org
  • *.casacam.com
  • *.changeip.com
  • *.chickenkiller.com
  • *.ddns.net
  • *.ddnsfree.com
  • *.ddnsgeek.com
  • *.dlinkddns.com
  • *.dns.army
  • *.dns.navy
  • *.duckdns.org
  • *.dyndns-office.com
  • *.dyndns.org
  • *.dynv6.net
  • *.gotdns.ch
  • *.hopto.org
  • *.instanthq.com
  • *.is-certified.com
  • *.linkpc.net
  • *.myddns.me
  • *.myftp.biz
  • *.myftp.org
  • *.myvnc.com
  • *.no-ip.biz
  • *.no-ip.com
  • *.no-ip.info
  • *.no-ip.org
  • *.noip.com
  • *.servehttp.com
  • *.sytes.net
  • *.thddns.net
  • *.v6.army
  • *.v6.navy
  • *.v6.rocks
  • *.ygto.com
  • *.zapto.org
field:"QueryName" kind:wildcard
event.actioneq
  • exec
  • lookup_result
field:"EventType" kind:eq
event.typeeq
  • start
field:"event.type" kind:eq value:"start"
process.executablewildcard
  • ./*
  • /boot/*
  • /dev/shm/*
  • /home/*/*
  • /lost+found/*
  • /proc/*
  • /root/*
  • /run/*
  • /sys/*
  • /tmp/*
  • /var/mail/*
  • /var/run/*
  • /var/tmp/*
  • /var/www/*
field:"Image" kind:wildcard
process.namein
  • bash
  • busybox
  • csh
  • curl
  • dash
  • env
  • fish
  • ksh
  • sh
  • tcsh
  • timeout
  • wget
  • zsh
field:"process_name" kind:in
process.namewildcard
  • .*
  • deno
  • lua*
  • node
  • perl*
  • php*
  • python*
  • ruby*
field:"process_name" kind:wildcard