Skip to content

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

Siemphony’s repertoire

Detect a hand-rolled character-table encoder in a script block

Matches PowerShell script-block logging where the recorded script both declares a literal character alphabet — a hand-rolled translation table, since .NET already ships Base64 and hex — and performs a per-character index or bit transform, which is the encode loop AN0927 describes. ScriptBlockText was chosen over the analytic's process_creation and network_connection sources because it is the only field in AN0927 that shows the encoder itself rather than its side effects. The analytic's real observable is a correlation: the encode routine, then egress with an asymmetric bytes_out:bytes_in ratio or fixed-size beacons inside MITRE's TimeWindow. Sigma expresses no ratio, no standard deviation and no join window, so this rule is the single-event precursor only, and the EntropyThreshold and TokenLengthThreshold knobs are left entirely to the analyst. UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0326, 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: Detect a hand-rolled character-table encoder in a script blockid: c2dbc459-235f-4f9f-a464-6bb60fc3fa88status: experimentaldescription: |  Matches PowerShell script-block logging where the recorded script both declares  a literal character alphabet — a hand-rolled translation table, since .NET  already ships Base64 and hex — and performs a per-character index or bit  transform, which is the encode loop AN0927 describes. ScriptBlockText was  chosen over the analytic's process_creation and network_connection sources  because it is the only field in AN0927 that shows the encoder itself rather  than its side effects. The analytic's real observable is a correlation:  the encode routine, then egress with an asymmetric bytes_out:bytes_in ratio or  fixed-size beacons inside MITRE's TimeWindow. Sigma expresses no ratio, no  standard deviation and no join window, so this rule is the single-event  precursor only, and the EntropyThreshold and TokenLengthThreshold knobs are  left entirely to the analyst.  UNVERIFIED AS AUTHORED — derived from MITRE ATT&CK DET0326, 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/T1132/002  - https://attack.mitre.org/detectionstrategies/DET0326author: Siemphony pipeline (machine-derived from MITRE ATT&CK v19.2)date: 2026-08-16tags:  - attack.command-and-control  - attack.t1132.002logsource:  product: windows  service: powershelldetection:  script_block:    EventID: 4104  custom_alphabet:    ScriptBlockText|contains:      - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'      - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'      - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'      - '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'      - '0123456789abcdefghijklmnopqrstuvwxyz'  transform_loop:    ScriptBlockText|contains:      - '-bxor'      - '-band'      - '-shr'      - '-shl'      - '.IndexOf('      - 'ToCharArray()'  condition: script_block and custom_alphabet and transform_loopfalsepositives:  - "In-house scripts that hand-roll base32 or base36 for licence keys, short-URL slugs or record-ID obfuscation. They declare exactly this kind of alphabet and index into it, and MITRE's KnownLegitEncoders knob exists for precisely these — suppress by script Path or ScriptBlockId rather than by weakening the alphabet list."  - "Password and passphrase generators, and provisioning tooling that builds random tokens. They carry a full alphabet literal and call ToCharArray(), so all three selections are satisfied; without MITRE's EntropyThreshold and TokenLengthThreshold there is nothing inside a single 4104 event that separates a 16-character password from a 4 KB encoded payload."  - "Checksum, CRC and simple integrity routines inside signed third-party modules, whose script blocks are logged verbatim when the module is dot- sourced. These use `-bxor` and `-shr` against a lookup table and will match if the table happens to be alphabetic."level: medium

Sentinel · KQL

Run this as a search.

Event| where ((EventID == 4104 and (ScriptBlockText contains "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" or ScriptBlockText contains "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" or ScriptBlockText contains "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" or ScriptBlockText contains "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" or ScriptBlockText contains "0123456789abcdefghijklmnopqrstuvwxyz")) and (ScriptBlockText contains "-bxor" or ScriptBlockText contains "-band" or ScriptBlockText contains "-shr" or ScriptBlockText contains "-shl" or ScriptBlockText contains ".IndexOf(" or ScriptBlockText contains "ToCharArray()"))

Splunk · SPL

Run this as a search.

index=* ((EventID="4104" AND (ScriptBlockText="*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*" OR ScriptBlockText="*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*" OR ScriptBlockText="*ABCDEFGHIJKLMNOPQRSTUVWXYZ234567*" OR ScriptBlockText="*0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*" OR ScriptBlockText="*0123456789abcdefghijklmnopqrstuvwxyz*")) AND (ScriptBlockText="*-bxor*" OR ScriptBlockText="*-band*" OR ScriptBlockText="*-shr*" OR ScriptBlockText="*-shl*" OR ScriptBlockText="*.IndexOf(*" OR ScriptBlockText="*ToCharArray()*"))

Elastic · ES|QL

Run this as a search.

FROM logs-*| WHERE ((event.code == 4104 AND (TO_LOWER(powershell.file.script_block_text) LIKE "*abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*abcdefghijklmnopqrstuvwxyz234567*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*0123456789abcdefghijklmnopqrstuvwxyz*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*0123456789abcdefghijklmnopqrstuvwxyz*")) AND (TO_LOWER(powershell.file.script_block_text) LIKE "*-bxor*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*-band*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*-shr*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*-shl*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*.indexof(*" OR TO_LOWER(powershell.file.script_block_text) LIKE "*tochararray()*"))

Wazuh · XML rule

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

<group name="sigma,windows,">  <!-- Rule ids must be unique on your manager; 100000+ is the user range. -->  <rule id="100000" level="7">    <!-- Set <if_sid> to the decoder/base rule for windows so this only evaluates relevant events. -->    <field name="EventID" type="pcre2">(?i)^4104$</field>    <field name="ScriptBlockText" type="pcre2">(?i)(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz|abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ|0123456789abcdefghijklmnopqrstuvwxyz)</field>    <field name="ScriptBlockText" type="pcre2">(?i)(-bxor|-band|-shr|-shl|\.IndexOf\(|ToCharArray\(\))</field>    <description>Detect a hand-rolled character-table encoder in a script block</description>    <mitre>      <id>T1132.002</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.