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

Siemphony@siemphonylowT1037.004unverified
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

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.