Shell startup or logout script modified on Linux
Matches the file-modification leg of AN0059: an auditd PATH record naming one of the configuration scripts a login or interactive shell sources on its own, which is where this technique plants the command it wants re-executed at every logon. The path list is MITRE's `FilePathRegex` knob, populated here with the bash, sh and zsh per-user dotfiles plus their system-wide counterparts under /etc, and it is anchored on the filename rather than on an absolute path because auditd records `name=` exactly as it was handed to the syscall, so an editor run from inside the home directory logs a bare `.bashrc`. Three limits are structural. auditd emits PATH and SYSCALL as separate records for one event, and the writing process's `exe`, `uid` and `auid` live only on the SYSCALL side, so MITRE's `TargetUser` knob cannot be applied inside this selection at all; the analytic's second half — an unexpected binary executing shortly after shell startup, within MITRE's `TimeWindow` knob — is a cross-event correlation lib/sigma has no way to express; and the macOS arm AN0060 is not attempted, because its unifiedlog and EndpointSecurity sources have no standardised Sigma field names and inventing them would produce a rule that parses everywhere and matches nothing. Prerequisite: auditd watches none of these paths by default, so this rule returns zero rows until watches such as `-w /etc/profile -p wa` and a per-home `-w /home/<user>/.bashrc -p wa` are loaded, and zero rows reads as quiet when it actually means blind. The `wa` permission also matters for noise: with it, only writes and attribute changes are recorded, whereas a watch including `r` makes every shell login match. UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0020, not hand-written and not tested by its author. Any lab result is on this rule's own page.Full descriptionShow less
The detection
The 3 SIEM queries below are previews produced by Siemphony’s own translator, not pySigma, and none has been executed against a real backend — review before you deploy.
detection.yml
Splunk · SPL
Run this as a search.
index=* ((type="PATH" AND (name="*.bashrc" OR name="*.bash_profile" OR name="*.bash_login" OR name="*.bash_logout" OR name="*.bash_aliases" OR name="*.profile" OR name="*.zshrc" OR name="*.zshenv" OR name="*.zprofile" OR name="*.zlogin" OR name="*.zlogout" OR name="*/etc/profile" OR name="*/etc/bash.bashrc" OR name="*/etc/bashrc" OR name="*/etc/zsh/zshrc" OR name="*/etc/zsh/zshenv" OR name="*/etc/zsh/zprofile" OR name="*/etc/zsh/zlogin" OR name="*/etc/zsh/zlogout" OR name="*/etc/zshrc" OR name="*/etc/zshenv" OR name="*/etc/zprofile" OR name="*/etc/zlogin" OR name="*/etc/zlogout")) OR (type="PATH" AND name="*/etc/profile.d/*"))Elastic · ES|QL
Run this as a search.
FROM logs-*| WHERE ((TO_LOWER(type) == "path" AND (TO_LOWER(name) LIKE "*.bashrc" OR TO_LOWER(name) LIKE "*.bash_profile" OR TO_LOWER(name) LIKE "*.bash_login" OR TO_LOWER(name) LIKE "*.bash_logout" OR TO_LOWER(name) LIKE "*.bash_aliases" OR TO_LOWER(name) LIKE "*.profile" OR TO_LOWER(name) LIKE "*.zshrc" OR TO_LOWER(name) LIKE "*.zshenv" OR TO_LOWER(name) LIKE "*.zprofile" OR TO_LOWER(name) LIKE "*.zlogin" OR TO_LOWER(name) LIKE "*.zlogout" OR TO_LOWER(name) LIKE "*/etc/profile" OR TO_LOWER(name) LIKE "*/etc/bash.bashrc" OR TO_LOWER(name) LIKE "*/etc/bashrc" OR TO_LOWER(name) LIKE "*/etc/zsh/zshrc" OR TO_LOWER(name) LIKE "*/etc/zsh/zshenv" OR TO_LOWER(name) LIKE "*/etc/zsh/zprofile" OR TO_LOWER(name) LIKE "*/etc/zsh/zlogin" OR TO_LOWER(name) LIKE "*/etc/zsh/zlogout" OR TO_LOWER(name) LIKE "*/etc/zshrc" OR TO_LOWER(name) LIKE "*/etc/zshenv" OR TO_LOWER(name) LIKE "*/etc/zprofile" OR TO_LOWER(name) LIKE "*/etc/zlogin" OR TO_LOWER(name) LIKE "*/etc/zlogout")) OR (TO_LOWER(type) == "path" AND TO_LOWER(name) LIKE "*/etc/profile.d/*"))
Wazuh · XML rule
Deploy to your manager — this is a rule, not a search.
<group name="sigma,linux,"> <!-- Rule ids must be unique on your manager; 100000+ is the user range. --> <!-- 2 rules: the Sigma condition ORs across different fields, which one rule cannot express. Any one matching is a hit. --> <rule id="100000" level="5"> <!-- Set <if_sid> to the decoder/base rule for linux so this only evaluates relevant events. --> <field name="type" type="pcre2">(?i)^PATH$</field> <field name="name" type="pcre2">(?i)(\.bashrc$|\.bash_profile$|\.bash_login$|\.bash_logout$|\.bash_aliases$|\.profile$|\.zshrc$|\.zshenv$|\.zprofile$|\.zlogin$|\.zlogout$|/etc/profile$|/etc/bash\.bashrc$|/etc/bashrc$|/etc/zsh/zshrc$|/etc/zsh/zshenv$|/etc/zsh/zprofile$|/etc/zsh/zlogin$|/etc/zsh/zlogout$|/etc/zshrc$|/etc/zshenv$|/etc/zprofile$|/etc/zlogin$|/etc/zlogout$)</field> <description>Shell startup or logout script modified on Linux (1/2)</description> <mitre> <id>T1546.004</id> </mitre> </rule> <rule id="100001" level="5"> <!-- Set <if_sid> to the decoder/base rule for linux so this only evaluates relevant events. --> <field name="type" type="pcre2">(?i)^PATH$</field> <field name="name" type="pcre2">(?i)/etc/profile\.d/</field> <description>Shell startup or logout script modified on Linux (2/2)</description> <mitre> <id>T1546.004</id> </mitre> </rule></group>
Sentinel · KQL
Run this as a search.
Sentinel cannot express this construct. No Sentinel table is modelled for this logsource ({"product":"linux","service":"auditd"}), so there is nothing honest to query. Pick a logsource this translator maps, or write the KQL by hand. The Sigma source is on the first tab, unchanged.
Verdicts · reactions · comments
Community
Verdicts from engineers who actually deployed it, and the conversation around it.
Nobody has run this in a real environment and said what happened.
Verdicts from engineers who deployed it
0 castNo verdicts reported yet. The first one is worth more than the tenth — say what you ran it against.
Log in to report a verdict.
Log in to join the discussion.
No comments yet. Someone who deploys this will have something to say about it.