Detection rules › Elastic
Linux Powershell Egress Network Connection
Detects when Powershell (pwsh) on Linux makes an outbound network connection attempt. Powershell usage on Linux is rare, and leveraging Powershell to connect out to the internet may indicate malicious behavior.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution |
Rule body
[rule]
description = """
Detects when Powershell (pwsh) on Linux makes an outbound network connection attempt. Powershell usage on Linux is rare,
and leveraging Powershell to connect out to the internet may indicate malicious behavior.
"""
id = "1471cf36-7e5c-47cc-bf39-2234df0e676a"
license = "Elastic License v2"
name = "Linux Powershell Egress Network Connection"
os_list = ["linux"]
version = "1.0.14"
query = '''
sequence by process.entity_id with maxspan=5s
[process where event.type == "start" and event.action == "exec" and process.parent.name == "pwsh" and not (
process.name in ("kubectl", "helm", "pwsh", "yum", "dnf", "dotnet", "ansible-lint") or
process.executable like (
"/run/containerd/*python3", "/jenkins-data/docker/*python3", "/tmp/Download-References/DepotDownloader/DepotDownloader",
"/home/*/.local/bin/az", "/usr/libexec/platform-python*"
) or
process.parent.executable like ("/jenkins-data/docker*", "/var/run/docker/*", "/run/containerd/*") or
process.command_line == "/usr/bin/gh auth status" or
(process.name like "python*" and process.args == "azure.cli") or
process.working_directory like "/opt/azurevstsagent/agent*" or
process.args == "/bin/dnf" or
process.args like "/home/*/.local/bin/az"
)
]
[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"
) or
process.name == "ssh"
)
]
'''
min_endpoint_version = "7.15.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 = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[threat.technique.subtechnique]]
id = "T1059.001"
name = "PowerShell"
reference = "https://attack.mitre.org/techniques/T1059/001/"
[threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[threat]]
framework = "MITRE ATT&CK"
[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"
[[threat]]
framework = "MITRE ATT&CK"
[threat.tactic]
id = "TA0010"
name = "Exfiltration"
reference = "https://attack.mitre.org/tactics/TA0010/"
[[threat]]
framework = "MITRE ATT&CK"
[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 5s, correlated by process.entity_id.
Stage 1: process
[process where event.type == "start" and event.action == "exec" and process.parent.name == "pwsh" and not (
process.name in ("kubectl", "helm", "pwsh", "yum", "dnf", "dotnet", "ansible-lint") or
process.executable like (
"/run/containerd/*python3", "/jenkins-data/docker/*python3", "/tmp/Download-References/DepotDownloader/DepotDownloader",
"/home/*/.local/bin/az", "/usr/libexec/platform-python*"
) or
process.parent.executable like ("/jenkins-data/docker*", "/var/run/docker/*", "/run/containerd/*") or
process.command_line == "/usr/bin/gh auth status" or
(process.name like "python*" and process.args == "azure.cli") or
process.working_directory like "/opt/azurevstsagent/agent*" or
process.args == "/bin/dnf" or
process.args like "/home/*/.local/bin/az"
)
]
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"
) or
process.name == "ssh"
)
]
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
process.args | eq | azure.cli | excludes:process.args field:"process.args" value:"azure.cli" |
process.name | starts_with | python | excludes:process.name field:"process.name" value:"python" |
process.args | eq | /bin/dnf | excludes:process.args field:"process.args" value:"/bin/dnf" |
process.args | wildcard | /home/*/.local/bin/az | excludes:process.args field:"process.args" value:"/home/*/.local/bin/az" |
process.command_line | eq | /usr/bin/gh auth status | excludes:process.command_line field:"process.command_line" value:"/usr/bin/gh auth status" |
process.executable | wildcard | /run/containerd/*python3, /jenkins-data/docker/*python3, /tmp/Download-References/DepotDownloader/DepotDownloader, /home/*/.local/bin/az, /usr/libexec/platform-python* | excludes:process.executable |
process.name | in | ansible-lint, dnf, dotnet, helm, kubectl, pwsh, yum | excludes:process.name |
process.parent.executable | starts_with | /jenkins-data/docker, /var/run/docker/, /run/containerd/ | excludes:process.parent.executable field:"process.parent.executable" value:"/jenkins-data/docker" field:"process.parent.executable" value:"/var/run/docker/" field:"process.parent.executable" value:"/run/containerd/" |
process.working_directory | starts_with | /opt/azurevstsagent/agent | excludes:process.working_directory field:"process.working_directory" value:"/opt/azurevstsagent/agent" |
destination.ip | cidr_match | 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 | excludes:destination.ip |
destination.ip | eq | 0.0.0.0 | excludes:destination.ip field:"destination.ip" value:"0.0.0.0" |
destination.ip | is_null | excludes:destination.ip | |
process.name | eq | ssh | excludes:process.name field:"process.name" value:"ssh" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event.action | eq |
| field:"EventType" kind:eq |
event.type | eq |
| field:"event.type" kind:eq value:"start" |
process.parent.name | eq |
| field:"parent_process_name" kind:eq value:"pwsh" |