Skip to content

Siemphony is in beta and still being built. How a rule earns its badge.

Siemphony’s repertoire

Startup RC or init script edited by a file-writing tool

AN0658 pairs modification of /etc/rc.local or an /etc/init.d script with the suspicious execution that follows at the next boot. Only the modification half is a single event: the boot half needs MITRE's `time_window` knob to link a write to a reboot minutes or days later, and lib/sigma has no timeframe and no cross-event join. So this rule matches the edit itself — a process whose command line names one of the RC script locations, launched either as a file-writing or editing utility (tee, sed, cp, install, chmod, an editor) or with a shell redirect aimed at one of those paths. The two forms are ORed because they are the same act reached two ways: `vi /etc/rc.local` and `sh -c 'echo /tmp/x >> /etc/rc.local'` both plant the persistence, but in the second the executable is a shell and only the redirect distinguishes it. The redirect arm matches the operator immediately followed by an RC path (`> /etc/init.d/` and `>/etc/init.d/`, which also cover the `>>` append form) rather than the operator anywhere on the line — an unanchored `>>` would fire on `/etc/init.d/foo start >> /var/log/foo.log` and on `cat /etc/rc.local >> /tmp/out`, neither of which writes the script. Shells are deliberately absent from the tool list: systemd's rc-local.service runs the script at every boot as `/bin/sh /etc/rc.local`, which would otherwise match once per boot on every host and match nothing an adversary did. The editor entries carry the Debian alternatives targets (vim.basic, vim.tiny, vim.nox) alongside `/vi` and `/vim`, because the exec record names the resolved binary and `vi` on a Debian-family host resolves to one of those. MITRE's `script_path` knob is what the path list implements, populated here with the Debian, RHEL, BSD-style and ESXi locations rather than taken from MITRE; dropping `/etc/init.d/` from it removes this rule's loudest false positive and would justify a higher level. Its `user_context` and `file_permission` knobs are not applied — root is the expected context for every legitimate match here as well as every malicious one. Vocabulary and limits. The brief maps `auditd:SYSCALL::execve` onto the Sigma `process_creation` category, which is Sysmon-for-Linux-shaped (`Image`, `CommandLine`); raw auditd splits the same execution across a SYSCALL record carrying `exe` and an EXECVE record carrying `a0`, `a1`, … , so that feed needs a field mapping before this rule can match on it. Nothing that writes the file without exec'ing a helper is visible: a Python or Perl implant that opens /etc/rc.local directly, or an interactive shell where the redirect is performed by the already-running shell and creates no new process, leaves no matching event. The brief's second source, `linux:syslog` boot logs, is not used — it has no standardised Sigma field vocabulary and boot messages name no script path. AN0659 (macOS) offers only `macos:unifiedlog`, which likewise has no standardised field names, so /etc/rc.common and the StartupItems trees are out of reach here even though the path list includes rc.common. ESXi's /etc/rc.local.d/local.sh is listed for completeness, but ESXi ships neither auditd nor Sysmon for Linux, so that entry only fires on a Linux host that uses the path. Prerequisite: neither feed exists by default. Sysmon for Linux is a separate agent no distribution installs, and stock auditd records no execve until a rule such as `-a always,exit -F arch=b64 -S execve -k exec` is loaded — until then this rule returns zero rows, and zero rows here means blind, not quiet. UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0237, not hand-written and not tested by its author. Any lab result is on this rule's own page.Full description

The detection

The 4 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

title: Startup RC or init script edited by a file-writing toolid: aaa7ee56-b105-4e44-a364-cc3c5cb25ad5status: experimentaldescription: |  AN0658 pairs modification of /etc/rc.local or an /etc/init.d script with the  suspicious execution that follows at the next boot. Only the modification half  is a single event: the boot half needs MITRE's `time_window` knob to link a  write to a reboot minutes or days later, and lib/sigma has no timeframe and no  cross-event join. So this rule matches the edit itself — a process whose  command line names one of the RC script locations, launched either as a  file-writing or editing utility (tee, sed, cp, install, chmod, an editor) or  with a shell redirect aimed at one of those paths. The two forms are ORed  because they are the same act reached two ways: `vi /etc/rc.local` and  `sh -c 'echo /tmp/x >> /etc/rc.local'` both plant the persistence, but in the  second the executable is a shell and only the redirect distinguishes it. The  redirect arm matches the operator immediately followed by an RC path  (`> /etc/init.d/` and `>/etc/init.d/`, which also cover the `>>` append form)  rather than the operator anywhere on the line — an unanchored `>>` would fire  on `/etc/init.d/foo start >> /var/log/foo.log` and on  `cat /etc/rc.local >> /tmp/out`, neither of which writes the script. Shells  are deliberately absent from the tool list: systemd's rc-local.service runs the  script at every boot as `/bin/sh /etc/rc.local`, which would otherwise match  once per boot on every host and match nothing an adversary did. The editor  entries carry the Debian alternatives targets (vim.basic, vim.tiny, vim.nox)  alongside `/vi` and `/vim`, because the exec record names the resolved binary  and `vi` on a Debian-family host resolves to one of those. MITRE's  `script_path` knob is what the path list implements, populated here with the  Debian, RHEL, BSD-style and ESXi locations rather than taken from MITRE;  dropping `/etc/init.d/` from it removes this rule's loudest false positive and  would justify a higher level. Its `user_context` and `file_permission` knobs  are not applied — root is the expected context for every legitimate match here  as well as every malicious one.  Vocabulary and limits. The brief maps `auditd:SYSCALL::execve` onto the Sigma  `process_creation` category, which is Sysmon-for-Linux-shaped (`Image`,  `CommandLine`); raw auditd splits the same execution across a SYSCALL record  carrying `exe` and an EXECVE record carrying `a0`, `a1`, … , so that feed needs  a field mapping before this rule can match on it. Nothing that writes the file  without exec'ing a helper is visible: a Python or Perl implant that opens  /etc/rc.local directly, or an interactive shell where the redirect is performed  by the already-running shell and creates no new process, leaves no matching  event. The brief's second source, `linux:syslog` boot logs, is not used — it  has no standardised Sigma field vocabulary and boot messages name no script  path. AN0659 (macOS) offers only `macos:unifiedlog`, which likewise has no  standardised field names, so /etc/rc.common and the StartupItems trees are out  of reach here even though the path list includes rc.common. ESXi's  /etc/rc.local.d/local.sh is listed for completeness, but ESXi ships neither  auditd nor Sysmon for Linux, so that entry only fires on a Linux host that uses  the path. Prerequisite: neither feed exists by default. Sysmon for Linux is a  separate agent no distribution installs, and stock auditd records no execve  until a rule such as `-a always,exit -F arch=b64 -S execve -k exec` is loaded —  until then this rule returns zero rows, and zero rows here means blind, not  quiet.  UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0237, not hand-written and not tested by its author. Any lab result is on this rule's own page.references:  - https://attack.mitre.org/techniques/T1037/004  - https://attack.mitre.org/detectionstrategies/DET0237author: Siemphony pipeline (machine-derived from MITRE ATT&CK v19.2)date: 2026-08-17tags:  - attack.persistence  - attack.privilege-escalation  - attack.t1037.004logsource:  category: process_creation  product: linuxdetection:  selection_rc_path:    CommandLine|contains:      - '/etc/rc.local'      - '/etc/rc.common'      - '/etc/rc.d/rc.local'      - '/etc/rc.local.d/'      - '/etc/init.d/'      - '/etc/rc.d/init.d/'  selection_write_tool:    Image|endswith:      - '/tee'      - '/sed'      - '/cp'      - '/mv'      - '/ln'      - '/install'      - '/chmod'      - '/chown'      - '/dd'      - '/patch'      - '/truncate'      - '/ed'      - '/vi'      - '/vim'      - '/vim.basic'      - '/vim.tiny'      - '/vim.nox'      - '/nvim'      - '/nano'      - '/pico'      - '/emacs'      - '/gedit'  selection_redirect_to_rc:    CommandLine|contains:      - '> /etc/rc.local'      - '>/etc/rc.local'      - '> /etc/rc.common'      - '>/etc/rc.common'      - '> /etc/rc.d/rc.local'      - '>/etc/rc.d/rc.local'      - '> /etc/rc.local.d/'      - '>/etc/rc.local.d/'      - '> /etc/init.d/'      - '>/etc/init.d/'      - '> /etc/rc.d/init.d/'      - '>/etc/rc.d/init.d/'  condition: selection_rc_path and (selection_write_tool or selection_redirect_to_rc)falsepositives:  - "Package management. Installing, upgrading or removing any package that still ships a SysV init script makes the dpkg or rpm maintainer script run cp, install, ln or chmod against /etc/init.d/<name>, so a single patch window produces matching events on every host in the fleet. This is the rule's highest-volume source by a wide margin and is why the level is low rather than medium."  - "Configuration management reapplying startup files on every convergence run — a Puppet or Chef exec resource, a Salt cmd.run, or an Ansible shell or command task doing cp, sed -i or chmod against /etc/rc.local or an init script — which fires on schedule whether or not the file content actually changed."  - "Image build and provisioning steps: kickstart and preseed %post sections, cloud-init runcmd, Packer shell provisioners and Dockerfile RUN lines that append a startup command to /etc/rc.local or chmod +x an init script, producing a burst of matches for every image built."  - "An administrator legitimately adding a boot-time command by hand, opening /etc/rc.local in vi or nano or appending to it with tee -a. This remains a normal way to schedule work on appliances, embedded builds and hosts that predate systemd, and the event is indistinguishable from the malicious form apart from the account and the change record."level: low

Sentinel · KQL

Run this as a search.

DeviceProcessEvents| where ((ProcessCommandLine contains "/etc/rc.local" or ProcessCommandLine contains "/etc/rc.common" or ProcessCommandLine contains "/etc/rc.d/rc.local" or ProcessCommandLine contains "/etc/rc.local.d/" or ProcessCommandLine contains "/etc/init.d/" or ProcessCommandLine contains "/etc/rc.d/init.d/") and ((FolderPath endswith "/tee" or FolderPath endswith "/sed" or FolderPath endswith "/cp" or FolderPath endswith "/mv" or FolderPath endswith "/ln" or FolderPath endswith "/install" or FolderPath endswith "/chmod" or FolderPath endswith "/chown" or FolderPath endswith "/dd" or FolderPath endswith "/patch" or FolderPath endswith "/truncate" or FolderPath endswith "/ed" or FolderPath endswith "/vi" or FolderPath endswith "/vim" or FolderPath endswith "/vim.basic" or FolderPath endswith "/vim.tiny" or FolderPath endswith "/vim.nox" or FolderPath endswith "/nvim" or FolderPath endswith "/nano" or FolderPath endswith "/pico" or FolderPath endswith "/emacs" or FolderPath endswith "/gedit") or (ProcessCommandLine contains "> /etc/rc.local" or ProcessCommandLine contains ">/etc/rc.local" or ProcessCommandLine contains "> /etc/rc.common" or ProcessCommandLine contains ">/etc/rc.common" or ProcessCommandLine contains "> /etc/rc.d/rc.local" or ProcessCommandLine contains ">/etc/rc.d/rc.local" or ProcessCommandLine contains "> /etc/rc.local.d/" or ProcessCommandLine contains ">/etc/rc.local.d/" or ProcessCommandLine contains "> /etc/init.d/" or ProcessCommandLine contains ">/etc/init.d/" or ProcessCommandLine contains "> /etc/rc.d/init.d/" or ProcessCommandLine contains ">/etc/rc.d/init.d/")))

Splunk · SPL

Run this as a search.

index=* ((CommandLine="*/etc/rc.local*" OR CommandLine="*/etc/rc.common*" OR CommandLine="*/etc/rc.d/rc.local*" OR CommandLine="*/etc/rc.local.d/*" OR CommandLine="*/etc/init.d/*" OR CommandLine="*/etc/rc.d/init.d/*") AND ((Image="*/tee" OR Image="*/sed" OR Image="*/cp" OR Image="*/mv" OR Image="*/ln" OR Image="*/install" OR Image="*/chmod" OR Image="*/chown" OR Image="*/dd" OR Image="*/patch" OR Image="*/truncate" OR Image="*/ed" OR Image="*/vi" OR Image="*/vim" OR Image="*/vim.basic" OR Image="*/vim.tiny" OR Image="*/vim.nox" OR Image="*/nvim" OR Image="*/nano" OR Image="*/pico" OR Image="*/emacs" OR Image="*/gedit") OR (CommandLine="*> /etc/rc.local*" OR CommandLine="*>/etc/rc.local*" OR CommandLine="*> /etc/rc.common*" OR CommandLine="*>/etc/rc.common*" OR CommandLine="*> /etc/rc.d/rc.local*" OR CommandLine="*>/etc/rc.d/rc.local*" OR CommandLine="*> /etc/rc.local.d/*" OR CommandLine="*>/etc/rc.local.d/*" OR CommandLine="*> /etc/init.d/*" OR CommandLine="*>/etc/init.d/*" OR CommandLine="*> /etc/rc.d/init.d/*" OR CommandLine="*>/etc/rc.d/init.d/*")))

Elastic · ES|QL

Run this as a search.

FROM logs-*| WHERE ((TO_LOWER(process.command_line) LIKE "*/etc/rc.local*" OR TO_LOWER(process.command_line) LIKE "*/etc/rc.common*" OR TO_LOWER(process.command_line) LIKE "*/etc/rc.d/rc.local*" OR TO_LOWER(process.command_line) LIKE "*/etc/rc.local.d/*" OR TO_LOWER(process.command_line) LIKE "*/etc/init.d/*" OR TO_LOWER(process.command_line) LIKE "*/etc/rc.d/init.d/*") AND ((TO_LOWER(process.executable) LIKE "*/tee" OR TO_LOWER(process.executable) LIKE "*/sed" OR TO_LOWER(process.executable) LIKE "*/cp" OR TO_LOWER(process.executable) LIKE "*/mv" OR TO_LOWER(process.executable) LIKE "*/ln" OR TO_LOWER(process.executable) LIKE "*/install" OR TO_LOWER(process.executable) LIKE "*/chmod" OR TO_LOWER(process.executable) LIKE "*/chown" OR TO_LOWER(process.executable) LIKE "*/dd" OR TO_LOWER(process.executable) LIKE "*/patch" OR TO_LOWER(process.executable) LIKE "*/truncate" OR TO_LOWER(process.executable) LIKE "*/ed" OR TO_LOWER(process.executable) LIKE "*/vi" OR TO_LOWER(process.executable) LIKE "*/vim" OR TO_LOWER(process.executable) LIKE "*/vim.basic" OR TO_LOWER(process.executable) LIKE "*/vim.tiny" OR TO_LOWER(process.executable) LIKE "*/vim.nox" OR TO_LOWER(process.executable) LIKE "*/nvim" OR TO_LOWER(process.executable) LIKE "*/nano" OR TO_LOWER(process.executable) LIKE "*/pico" OR TO_LOWER(process.executable) LIKE "*/emacs" OR TO_LOWER(process.executable) LIKE "*/gedit") OR (TO_LOWER(process.command_line) LIKE "*> /etc/rc.local*" OR TO_LOWER(process.command_line) LIKE "*>/etc/rc.local*" OR TO_LOWER(process.command_line) LIKE "*> /etc/rc.common*" OR TO_LOWER(process.command_line) LIKE "*>/etc/rc.common*" OR TO_LOWER(process.command_line) LIKE "*> /etc/rc.d/rc.local*" OR TO_LOWER(process.command_line) LIKE "*>/etc/rc.d/rc.local*" OR TO_LOWER(process.command_line) LIKE "*> /etc/rc.local.d/*" OR TO_LOWER(process.command_line) LIKE "*>/etc/rc.local.d/*" OR TO_LOWER(process.command_line) LIKE "*> /etc/init.d/*" OR TO_LOWER(process.command_line) LIKE "*>/etc/init.d/*" OR TO_LOWER(process.command_line) LIKE "*> /etc/rc.d/init.d/*" OR TO_LOWER(process.command_line) LIKE "*>/etc/rc.d/init.d/*")))

Wazuh · XML rule

Deploy to your manager — this is a rule, not a search.

<group name="sigma,linux,process_creation,">  <!-- 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="CommandLine" type="pcre2">(?i)(/etc/rc\.local|/etc/rc\.common|/etc/rc\.d/rc\.local|/etc/rc\.local\.d/|/etc/init\.d/|/etc/rc\.d/init\.d/)</field>    <field name="Image" type="pcre2">(?i)(/tee$|/sed$|/cp$|/mv$|/ln$|/install$|/chmod$|/chown$|/dd$|/patch$|/truncate$|/ed$|/vi$|/vim$|/vim\.basic$|/vim\.tiny$|/vim\.nox$|/nvim$|/nano$|/pico$|/emacs$|/gedit$)</field>    <description>Startup RC or init script edited by a file-writing tool (1/2)</description>    <mitre>      <id>T1037.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="CommandLine" type="pcre2">(?i)(/etc/rc\.local|/etc/rc\.common|/etc/rc\.d/rc\.local|/etc/rc\.local\.d/|/etc/init\.d/|/etc/rc\.d/init\.d/)</field>    <field name="CommandLine" type="pcre2">(?i)(&gt; /etc/rc\.local|&gt;/etc/rc\.local|&gt; /etc/rc\.common|&gt;/etc/rc\.common|&gt; /etc/rc\.d/rc\.local|&gt;/etc/rc\.d/rc\.local|&gt; /etc/rc\.local\.d/|&gt;/etc/rc\.local\.d/|&gt; /etc/init\.d/|&gt;/etc/init\.d/|&gt; /etc/rc\.d/init\.d/|&gt;/etc/rc\.d/init\.d/)</field>    <description>Startup RC or init script edited by a file-writing tool (2/2)</description>    <mitre>      <id>T1037.004</id>    </mitre>  </rule></group>

Verdicts · reactions · comments

Community

Verdicts from engineers who actually deployed it, and the conversation around it.

Log in to react
Not yet reported on

Nobody has run this in a real environment and said what happened.

Verdicts from engineers who deployed it

0 cast

No 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.