Skip to main content

Blog-0xahmetcan

DETECTION ENGINEERING • BLUE TEAM • SIGMA & YARA

CyberDefenders Detection Engineering Labs Sigma & YARA Rule Development

A four-lab deep dive into practical detection engineering — from Windows event-log clearing and lateral-movement telemetry to malware unpacking and multi-variant YARA signatures. Every rule in this write-up was authored, broken, debugged and validated against real artifact corpora.

Author Ahmet Can Aytekin
Category Detection Engineering
Platform CyberDefenders
Labs Covered 4 (Easy → Medium)
Sigma YARA Chainsaw Sysmon DIE FLOSS MITRE ATT&CK
LAB SERIES CASE FILE

Detection Engineering Track

COMPLETED
CASE ID DE-2026-004
LAB 01 SigmaPredator — T1070.001
LAB 02 Sigma 101 — Lateral Movement
LAB 03 Yara Wizards — SFX Loader
LAB 04 Yara101 — Ransomware & Stealers
ANALYST ROLE Detection Engineer
DETECTION ENGINEERING WORKFLOW

From Adversary TTPs to Validated Detections

Every lab in this series follows the same engineering loop: research the technique, analyze the artifacts it leaves behind, author detection logic, validate it against a historical corpus, and tune until the rule matches exactly what it should — nothing more, nothing less.

01 Research Adversary TTPs
→
02 Analyze Logs & Samples
→
03 Author Sigma / YARA
→
04 Validate Chainsaw / Validators
→
05 Tune Feedback Loop
→
06 Detect Production-Ready Logic
01 — OVERVIEW

Why Detection Engineering Labs?

Writing a detection rule that compiles is easy. Writing one that matches exactly the malicious events in a corpus of hundreds of event logs — or all variants of a malware family across thousands of files — is a different discipline entirely.

This write-up covers four labs from the CyberDefenders Detection Engineering track. Two labs focus on Sigma rules against Windows event-log telemetry; two focus on YARA rules against malware samples and their variants.

◎
SERIES OBJECTIVE

Turn adversary tradecraft into validated detection logic

Research the technique, find the forensic residue it leaves, express that residue as a rule, and prove the rule works against real historical data — including the false positives that naive rules would generate.

The Four Labs

LAB 01 — EASY

SigmaPredator

Deconstruct Windows Event Log Clearing (T1070.001) across CLI, WMI and PowerShell, then validate Sigma rules with Chainsaw against 333 historical EVTX files.

LAB 02 — MEDIUM

Sigma 101

Analyze three suspicious log sets — a masqueraded VBScript, a process-hollowing chain and a PowerShell CLM bypass — and write Sigma rules that match them exactly.

LAB 03 + 04 — MEDIUM

Yara Wizards & Yara101

Statically analyze an SFX/CAB loader, LockBit ransomware and a family of .NET stealers, then author YARA rules that detect every variant with zero false positives.

Honest Write-Up Policy

This article documents the real workflow — including the rules that failed, the silent parser rejections, and the debugging that led to working detections. Detection engineering is an iterative craft, and the dead ends are where the lessons live.

02 — LAB ENVIRONMENTS

Environments & Toolset

The four labs run on three different environments: two Windows Server machines for the Sigma and Yara Wizards labs, and an Ubuntu analysis box for Yara101. All analysis was performed inside the isolated lab VMs.

analyst@detection-lab
$ labs --environment

SigmaPredator   : Windows Server · Chainsaw v2.9.2 · 333 EVTX corpus
Sigma 101       : Windows Server · Local Sigma web compiler · 3 EVTX levels
Yara Wizards    : Windows Server 2016 · DIE · strings · YaraValidator
Yara101         : Ubuntu · strings / flarestrings · yara · verify (4,178-file corpus)

Core Tools

01

Chainsaw

WithSecure's fast EVTX hunting engine. Loads Sigma rules through a field-mapping file and runs them against entire event-log corpora in seconds.

02

Sigma

The vendor-agnostic detection rule format for log telemetry: logsource + detection + condition, convertible to any SIEM backend.

03

YARA + Validators

Pattern matching over files and memory. Lab-provided validators (YaraValidator, verify) score rules against variant corpora and release the flag only on exact coverage.

04

DIE / strings / FLOSS

Static triage: packer and entropy analysis with Detect It Easy, ASCII/UTF-16 string extraction, and ML-ranked string relevance with Stringsifter.

A detection rule is a hypothesis about forensic residue. Validation against a real corpus is the experiment that proves or falsifies it.
FIRST LAB SigmaPredator — Windows Event Log Clearing
↓
03 — SIGMAPREDATOR · TECHNIQUE RESEARCH

Deconstructing Windows Event Log Clearing

SigmaPredator places you inside the CyberPredator Enterprise as a Detection & Hunting Engineer. The target technique is Indicator Removal: Clear Windows Event Logs (T1070.001) — observed in campaigns attributed to APT28, APT41 and Aquatic Panda, and used to degrade investigative visibility after compromise.

The first phase maps the full attacker toolset for clearing logs, together with the telemetry each method leaves behind.

SigmaPredator lab machine with Historical Logs and Tools folders Figure 1 — The lab workstation: a 333-file Historical Logs corpus and the Chainsaw toolset.

Clearing Methods & Their Telemetry

Research across Microsoft Learn and the MITRE ATT&CK technique page produced a complete map of the tradecraft:

Vector Attacker Tooling Telemetry Source
Native CLI wevtutil cl / clear-log Process creation (Sysmon 1 / 4688)
WMI wmic nteventlog ... call ClearEventLog Process creation — the nteventlog alias of Win32_NTEventlogFile appears in the command line
PowerShell cmdlets Clear-EventLog, Remove-EventLog PowerShell Script Block Logging — Event ID 4104
.NET APIs EventLogSession.ClearLog, EventLog.Clear Script Block Logging (unless Constrained Language Mode blocks them)
Residual audit events — (generated by Windows itself) 1102 (Security log cleared) · 104 (System/other log cleared)
KEY RESEARCH FINDING

Log clearing is self-incriminating.

Whatever tool the attacker uses, Windows writes a "log was cleared" record — Event ID 1102 into Security, Event ID 104 into System — the moment the wipe completes. These residual events became the backbone of the highest-fidelity rule in this lab.

Answer-Mask Driven Research

Several research questions enforce strict answer formats (e.g. a 10-character mask rejecting Win32_NTEventlogFile but accepting its WMIC alias nteventlog). Reading the mask before answering saves a surprising amount of time — the format often tells you which representation of the fact the lab wants.

04 — SIGMAPREDATOR · CHAINSAW VALIDATION

Debugging "No Valid Detection Rules"

The Rule Development phase validates every Sigma rule with Chainsaw against the 333-file EVTX corpus. This is where the lab stopped being easy: for a long stretch, Chainsaw v2.9.2 rejected every single rule with the same two messages.

Chainsaw — The Two Failure Modes
[x] No valid detection rules were found in the provided paths

[!] : failed to parse sigma rule
[+] Validated 0 detection rules out of 1
Chainsaw rejecting Sigma rules Figure 2 — Chainsaw silently rejecting a syntactically valid Sigma rule.

Systematic Elimination

Instead of guessing, every variable was isolated and tested independently:

✓ Encoding — Format-Hex confirmed clean ASCII/UTF-8, no BOM, LF and CRLF both tested.
✓ Indentation — spaces only, verified by replacing every space/tab with visible markers.
✓ Mapping internals — sigma-event-logs-all.yml dissected with Select-String: it maps rules by logsource.category / logsource.service preconditions, so an unmapped logsource is silently dropped.
✓ CLI syntax — chainsaw hunt [OPTIONS] [RULES] [PATH]...; -s/--sigma + --mapping, full absolute paths for logs, rules and mapping.
✓ Lint oracle — chainsaw lint --kind sigma <rule> reproduces the parser verdict without touching the corpus.
PowerShell — Dissecting the Mapping File
Select-String -Path "mappings\sigma-event-logs-all.yml" -Pattern "service:|category:"
Get-Content "mappings\sigma-event-logs-all.yml" -TotalCount 30
Chainsaw mapping file logsource categories Figure 3 — The mapping file's supported logsource categories and services, extracted line by line.

Root Cause

The breakthrough came from rebuilding the rule with the complete Sigma metadata skeleton — including the fields that feel optional. The moment description, author, date, modified, tags and falsepositives were present, Chainsaw loaded the rule and the corpus lit up.

ROOT CAUSE

Chainsaw v2.9.2 drops Sigma rules with incomplete metadata — without telling you which field is missing.

A minimal title / logsource / detection / condition rule parses fine in other tooling but is reported here only as "failed to parse sigma rule". Always author rules with the full skeleton, and keep lint --kind sigma in the loop as a fast pre-flight check.

Chainsaw — Working Invocation
chainsaw.exe hunt "C:\Users\Administrator\Desktop\Start Here\Historical Logs" `
  --sigma "C:\Users\Administrator\Desktop\rules\rule.yaml" `
  --mapping "C:\...\chainsaw\mappings\sigma-event-logs-all.yml"
05 — SIGMAPREDATOR · RULE DEVELOPMENT

Three Detection Layers, Three Rules

The lab asks for three Sigma rules, one per telemetry layer, each validated for a specific timestamp in the corpus.

Rule 1 — PowerShell Script Block Logging (4104)

The scenario notes that PowerShell runs in Constrained Language Mode, so the rule deliberately targets only the native cmdlet family and ignores .NET API strings that CLM would block anyway.

rule.yaml — ScriptBlock Detection
title: Suspicious PowerShell Event Log Tampering via Script Block Logging
id: cc36992a-4671-4f21-a91d-6c2b72a2edf5
status: stable
description: >
  Detects PowerShell Script Block Logging events (Event ID 4104) containing
  cmdlets commonly used to clear Windows Event Logs.
author: Ahmet Can Aytekin
date: 2026-10-05
modified: 2026-10-05
tags:
  - attack.defense-evasion
  - attack.t1070.001
logsource:
  product: windows
  service: microsoft-windows-powershell/operational
detection:
  selection:
    EventID: 4104
    ScriptBlockText|contains:
      - 'Clear-EventLog'
      - 'Remove-EventLog'
      - 'Limit-EventLog'
      - 'Clear-WinEvent'
  condition: selection
falsepositives:
  - Legitimate administrative maintenance scripts
level: high
Chainsaw detecting Clear-EventLog in ScriptBlockText Figure 4 — One detection across 333 artifacts: the earliest ScriptBlock match.
MATCHED SCRIPTBLOCK Clear-EventLog -LogName application, system -confirm
EARLIEST DETECTION 2021-10-25 18:04 · FS03.offsec.lan

Rule 2 — Native CLI Clearing via Process Creation

The second rule is built around two anchors that make it resilient against evasion: binary identity (OriginalFileName, so a renamed copy of wevtutil is still caught) and command-line intent (the destructive sub-commands: cl, clear-log, plus the config-tampering sl/set-log and lfn:). Two OR'd selections cover both telemetry sources — Sysmon EID 1 and native Security EID 4688:

rule2.yaml — Wevtutil Detection (Sysmon + 4688)
title: Suspicious EventLog Clearing or Configuration Change Activity
id: cc36992a-4671-4f21-a91d-6c2b72a2edf6
status: stable
description: >
  Detects wevtutil usage to clear or reconfigure event logs via Sysmon (EID 1)
  or Windows Security process creation events (EID 4688).
author: Ahmet Can Aytekin
date: 2026-10-05
modified: 2026-10-05
tags:
  - attack.defense-evasion
  - attack.t1070.001
logsource:
  product: windows
detection:
  selection_sysmon:
    EventID: 1
    Image|endswith: '\wevtutil.exe'
    OriginalFileName: 'wevtutil.exe'
    CommandLine|contains:
      - 'clear-log '
      - 'cl '
      - 'set-log '
      - 'sl '
      - 'lfn:'
  selection_security:
    EventID: 4688
    NewProcessName|endswith: '\wevtutil.exe'
    CommandLine|contains:
      - 'clear-log '
      - 'cl '
      - 'set-log '
      - 'sl '
      - 'lfn:'
  condition: selection_sysmon or selection_security
falsepositives:
  - Legitimate administrative log maintenance
  - Automated log-rotation or archival processes
level: high

The rule returns 15 detections across both telemetry sources, with zero false positives from routine maintenance. The question asks for the latest match this time — sorting the Chainsaw table by timestamp descending gives the answer.

Chainsaw wevtutil process creation matches Figure 5 — 15 wevtutil detections across Sysmon and Security telemetry; the most recent row answers the question.
LATEST MATCH 2025-04-28 08:58 · 15 detections · EID 1 + 4688

Rule 3 — Residual Audit Events (1102 / 104)

The first attempt — service: security with Event ID 1102 only — returned zero hits, and a 104-only variant surfaced 115 events polluted by RemoteDesktopServices-RdpCoreTS noise (RDP's own, unrelated Event ID 104). The final rule pins the provider and covers both IDs:

rule3.yaml — Log Cleared Audit Events
title: Windows Event Log Cleared
id: cc36992a-4671-4f21-a91d-6c2b72a2edf7
status: stable
description: >
  Detects native audit events generated when a Windows Event Log is cleared:
  1102 (Security) and 104 (System), scoped to the genuine Eventlog provider.
author: Ahmet Can Aytekin
date: 2026-10-05
modified: 2026-10-05
tags:
  - attack.defense-evasion
  - attack.t1070.001
logsource:
  product: windows
detection:
  selection_cleared:
    Provider_Name:
      - 'Microsoft-Windows-Eventlog'
      - 'Microsoft-Windows-Security-Auditing'
    EventID:
      - 104
      - 1102
  condition: selection_cleared
falsepositives:
  - Legitimate administrative log clearing
level: high
Rule Iteration Detections Verdict
1102 only (service: security) 0 Logsource too narrow
104 only 115 RdpCoreTS false positives
1102 + 104, provider-scoped 132 Clean coverage
EARLIEST MATCH 2019-01-20 07:00 · 1102 · WIN-77LTAPHIQ1R.example.corp
TUNING LESSON

Event ID alone is not an identity.

Event ID 104 exists in multiple providers with completely different meanings. Scoping on Provider_Name: Microsoft-Windows-Eventlog eliminated an entire class of RDP false positives — and turned a wrong answer into the correct earliest timestamp, which came from a 1102 record the 104-only rule could never see.

06 — SIGMA 101 · LEVEL 1

Masqueraded VBScript Spawning PowerShell

Sigma 101 changes the format: three small EVTX files, one per level, and a local web-based Sigma compiler (http://127.0.0.1:5500/). You pick a level, paste a rule, press Run — and the backend tells you whether the rule matches exactly the right events.

Level 1's log holds three Sysmon Event ID 1 records. Dumping their EventData with PowerShell exposes the malicious one immediately:

PowerShell — Dumping Sysmon EventData from EVTX
Get-WinEvent -Path ".\Levels\1\1.evtx" | ForEach-Object {
  $x = [xml]$_.ToXml()
  $d = @{}; $x.Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
  [pscustomobject]@{
    Time        = $_.TimeCreated
    Image       = $d['Image']
    CommandLine = $d['CommandLine']
    Parent      = $d['ParentImage']
  }
} | Format-List
★
MALICIOUS PROCESS wscript.exe /E:vbs c:\windows\temp\icon.ico "powershell -exec bypass -c IEX(FromBase64String(...))"

A .ico file forced to execute as VBScript via /E:vbs, which in turn launches a Base64-obfuscated PowerShell stage that decodes a second payload from c:\windows\temp\picture.jpg. Classic extension masquerading.

Sigma 101 local web compiler Figure 6 — The local Sigma compiler: one rule per level, instant match feedback.
Level 1 — Sigma Rule
title: Level 1
id: bbce11dd-64ac-4656-96b8-753097833492
status: experimental
description: Detect Malicious PowerShell Script Execution via wscript.exe
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        Image|endswith: '\wscript.exe'
        ParentImage|endswith: '\explorer.exe'
        CommandLine|contains:
            - 'powershell -exec bypass'
            - 'IEX'
    condition: selection

Compiler Pedantry

The web compiler is strict about formatting: 4-space indentation and straight quotes. A semantically identical rule with 2-space indentation returned "No hits found" — the parser failed silently rather than reporting a syntax error.

07 — SIGMA 101 · LEVEL 2

Process Hollowing — Matching a Three-Event Chain

Level 2's EVTX tells a complete process-hollowing story across three Sysmon event types:

EID 1 rundll32 winfire.dll,DllRegisterServer spawns wermgr.exe
EID 10 ProcessAccess rundll32 → wermgr · GrantedAccess 0x1fffff
EID 12 RegistryEvent Hollowed wermgr touches Internet Settings

GrantedAccess 0x1fffff is PROCESS_ALL_ACCESS — exactly what a hollowing loader requests before rewriting the target's memory. The interesting part of this level is the compiler's feedback loop:

Rule Attempt Compiler Response
Single-event rule (EID 1 parent/child only) "Not enough matches — 1 event out of 3"
Broad keyword on wermgr.exe "Your rule is very generic and matches 5 events"
Three event-specific selections, OR'd Exact 3/3 — Level 2 flag
Level 2 — Final Sigma Rule
title: Process Hollowing Via Rundll32
id: 7c0e2a84-5bd3-4e26-9f41-8b3f2a6d4c11
status: experimental
description: Detects the full process hollowing chain where rundll32 hollows wermgr.exe
logsource:
    product: windows
    service: sysmon
detection:
    selection1:
        Image|endswith: '\wermgr.exe'
        ParentImage|endswith: '\rundll32.exe'
    selection2:
        SourceImage|endswith: '\rundll32.exe'
        TargetImage|endswith: '\wermgr.exe'
    selection3:
        Image|endswith: '\wermgr.exe'
        TargetObject|contains: 'Internet Settings'
    condition: selection1 or selection2 or selection3
TOO NARROW

1 / 3

Misses the ProcessAccess and Registry stages

Incomplete behavioral coverage
VS
TOO BROAD

5 events

Sweeps in benign wermgr activity

False-positive generator
DETECTION ENGINEERING LESSON

Each selection must carry an event-unique discriminator.

Pairing every image match with a second field that only the intended event possesses — the rundll32 parent, the Source/Target pair, the registry path — is what collapsed 5 matches down to exactly 3.

08 — SIGMA 101 · LEVEL 3

Defense Evasion — PowerShell CLM Bypass

Level 3 contains a single Sysmon Event ID 12 record, and its own RuleName field spells out the technique: "Defense Evasion — PowerShell CLM Setting Changed".

★
REGISTRY EVENT · DeleteValue HKLM\System\CurrentControlSet\Control\SESSION MANAGER\Environment\__PSLockdownPolicy

powershell.exe deletes the __PSLockdownPolicy value — the environment flag that forces Constrained Language Mode. Removing it returns PowerShell to Full Language Mode, re-enabling .NET invocation for follow-on tooling.

Level 3 — Sigma Rule
title: PowerShell Lockdown Policy Removal
id: 7c0e2a84-5bd3-4e26-9f41-8b3f2a6d4c13
status: experimental
description: Detects deletion of the PSLockdownPolicy value to bypass Constrained Language Mode
logsource:
    product: windows
    service: sysmon
detection:
    selection:
        Image|endswith: '\powershell.exe'
        TargetObject|contains: '__PSLockdownPolicy'
    condition: selection

One event, two discriminating fields, an exact 1/1 match — and the Level 3 flag closes the lab.

NEXT From Logs to Binaries — the YARA Labs
↓
09 — YARA WIZARDS · STATIC TRIAGE

An SFX Cabinet With 99% Packed Entropy

Yara Wizards hands you a single MalwareSample.exe and a validator that only releases the flag when your YARA rule matches multiple variants of the same family. First step: understand what the sample actually is.

Detect It Easy

DIE identifies the sample in one scan: a 2.54 MiB PE32 built with Visual Studio 2022, flagged as a Sfx: Microsoft Cabinet — a self-extracting archive that unpacks and installs itself with no external extraction program, carrying an embedded CAB (LZX, 38.7%, 7 files).

Detect It Easy identifying the SFX Microsoft Cabinet packer Figure 7 — DIE: SFX Microsoft Cabinet with an embedded 7-file LZX archive.

Entropy Analysis

TOTAL FILE ENTROPY 7.98612 · packed (99%)

The entropy diagram makes the structure obvious: a tiny low-entropy PE stub (.text at 6.27, .data at 4.97) followed by a near-8.0 plateau — the compressed cabinet that makes up almost the entire file.

DIE entropy graph showing 7.98612 packed Figure 8 — Entropy 7.98612: a thin extractor stub fronting a wall of compressed data.

Why Entropy Matters for YARA

At 7.99 entropy, almost nothing inside the payload is string-matchable in its packed form. Any useful signature must target the stub, the CAB structure, or the extracted contents — which is exactly where the analysis went next.

10 — YARA WIZARDS · UNPACKING THE CHAIN

Carving the Cabinet, Reading the Batch

expand refuses to read the CAB through the SFX stub, so the cabinet was carved manually: locate the MSCF magic, write everything from that offset into a standalone .cab, then expand it.

PowerShell — Carving the Embedded CAB
$b = [System.IO.File]::ReadAllBytes("...\MalwareSample.exe")
for ($i=0; $i -lt $b.Length-4; $i++) {
  if ($b[$i] -eq 0x4D -and $b[$i+1] -eq 0x53 -and
      $b[$i+2] -eq 0x43 -and $b[$i+3] -eq 0x46) {
    "MSCF offset: $i"; $off = $i; break
  }
}
# → MSCF offset: 141424
[System.IO.File]::WriteAllBytes("C:\extracted\embedded.cab", $b[$off..($b.Length-1)])
expand -F:* C:\extracted\embedded.cab C:\extracted
Carving the MSCF cabinet and expanding seven files Figure 9 — The seven extracted cabinet files: one batch script, four split payload parts and two .dat companions.

The Dropper Logic — Three Lines of Batch

bqwybceocy.bat — Extracted, Never Executed
rem 11747112
copy /b eqnyiodbs.dat + eqnyiodbs.dat.1 + eqnyiodbs.dat.2 + eqnyiodbs.dat.3 fjlpexyjauf.exe
fjlpexyjauf.exe lknidtnqmg.dat %1%

The chain is now fully reconstructed — statically, without running a single malicious byte:

01 SFX Stub Extracts CAB to %TEMP%
→
02 RUNPROGRAM cmd.exe /d /c bat + key
→
03 copy /b 4 .dat parts → final EXE
→
04 fjlpexyjauf.exe Loads encrypted payload
Artifact Value
Dropper batch file bqwybceocy.bat
RUNPROGRAM command line (from stub strings) cmd.exe /d /c bqwybceocy.bat 3991425476
Reassembled final executable fjlpexyjauf.exe
Encrypted payload argument lknidtnqmg.dat + numeric key via %1%
Drop path (session-aware Temp) C:\Users\Administrator\AppData\Local\Temp\2\IXP000.TMP
FORENSIC DETAIL

IXP000.TMP — and the Terminal Server twist.

The wextract-style stub always unpacks into an IXP000.TMP directory under the user's Temp — but on this Server 2016 host, the RDP session inserts a numeric session folder first. Listing %LOCALAPPDATA%\Temp revealed a single directory named 2, completing the full path the lab's answer mask demanded.

11 — YARA WIZARDS · YARA RULE

From Entropy Heuristics to the Lu0Bot Flag

The validated rule combines the two strongest observations from the analysis: the near-8.0 entropy of the packed body, and the execution-chain strings — the batch launcher command plus the split .dat fragment extensions that every variant of this loader reassembles with copy /b.

Yara_Rule.yar — Validated Rule
import "math"

rule yara_rule
{
    meta:
        author = "CyberDefenders"
        date   = "2025-01-01"

    strings:
        $str   = "cmd.exe /d /c bqwybceocy.bat"
        $dat_1 = ".dat"
        $dat_2 = ".dat.1"
        $dat_3 = ".dat.2"
        $dat_4 = ".dat.3"
        $bat   = ".bat" ascii

    condition:
        math.entropy(0, filesize) > 7 and
        any of ( $str, $bat ) and
        all of ( $dat_1, $dat_2, $dat_3, $dat_4 )
}
math.entropy > 7

Gates on the packed/encrypted body

all of ($dat_*)

The split-payload reassembly fingerprint

any of ($str, $bat)

The batch-launcher execution chain

YaraValidator detecting 28 samples and releasing the Lu0Bot flag Figure 10 — YaraValidator (-e): 28 variants detected, and the flag finally names the family.
VALIDATOR RESULT 28 DETECTED · 10 FALSE POSITIVES

Flag{Lu0Bot_Detected}

The flag reveals what static analysis alone could not name: this CAB-SFX loader chain is Lu0Bot, a Node.js-based bot known for exactly this delivery pattern — split .dat fragments reassembled by a randomly-named batch script.

TUNING TAKEAWAY

28 hits came with 10 false positives — and that is the lesson.

Generic anchors like .bat and bare .dat buy variant coverage but leak precision. A hardened iteration would swap them for structural anchors that benign software rarely combines: uint16(0) == 0x5A4D, the embedded MSCF cabinet magic, the cmd.exe /d /c launcher prefix and the IXP000.TMP staging directory. Structure generalizes across variants; random filenames and generic extensions do not discriminate.

12 — YARA101 · LEVEL 1

LockBit With a Broken MZ Header

Yara101 moves to Ubuntu and raises the stakes: the verify command scans your rule against a 4,178-file corpus and releases the flag only on exact coverage. Level 1 provides a single sample that file stubbornly calls "data".

xxd — The 12-Byte Sabotage
00000000: 2d2d 2d2d 2d2d 2d2d 2d2d 2d0a 4d5a 9000  -----------.MZ..
                                        ^^^^
                       MZ header pushed to offset 0x0C

Eleven dashes and a newline prepend the PE — enough to break file, most carvers, and any YARA rule that starts with uint16(0) == 0x5A4D. The strings underneath leave no doubt about the family:

✓ All your files are encrypted by LockBit
✓ LockBit Ransom · Restore-My-Files.txt
✓ Tor payment portal: http://lockbitks2tvnmwk.onion
✓ Anti-recovery wiping: fsutil file setZeroData ... & Del /f /q
level1.yar
rule LockBit_Ransomware
{
    meta:
        description = "Detects LockBit ransomware variants"
        author      = "Ahmet Can Aytekin"

    strings:
        $s1 = "All your files are encrypted by LockBit" ascii wide
        $s2 = "Restore-My-Files.txt" ascii wide
        $s3 = "lockbitks2tvnmwk.onion" ascii wide
        $s4 = "LockBit Ransom" ascii wide

    condition:
        2 of them
}

Why There Is No MZ Check Here

The corrupted header is the trap. Adding uint16(0) == 0x5A4D — normally best practice — would make the rule miss its own target sample. Level 1 rewards reading the hex dump before reaching for the standard rule template.

verify scanning 4178 files and returning the Level 1 flag Figure 11 — verify: 4,178 files scanned, exactly one match, zero false positives.
VALIDATOR RESULT 1 / 4178 — EXACT

Level 1 flag: yara_level_1_completed_4de1e9160

The 2 of them condition hit the target and nothing else across the entire corpus — the precision/recall balance a production rule needs.

13 — YARA101 · LEVEL 2

Four .NET Stealers, One Rule

Level 2 supplies four PE32 Mono/.NET assemblies. FLOSS + Stringsifter triage paints an unmistakable infostealer profile:

Capability Evidence Present In
Victim fingerprinting api.ipify.org · api.ip.sb · ipinfo.io · "Total of RAM" All 4
Credential decryption bEncryptedData · <encrypted_key>k__BackingField · bcrypt.dll All 4
C2 channel net.tcp:// (RedLine-style WCF transport) All 4
FTP credential theft {0}\FileZilla\recentservers.xml · sitemanager.xml (UTF-16) sample_1/3/4 ASCII; sample_2 Unicode-only
Crypto-wallet targeting Base64 blob of 30+ extensionID|WalletName pairs (Metamask, TronLink, Phantom, Coinbase…) sample_2
Bash — Decoding the Wallet-Extension Blob
strings -el sample_2 | grep '^ZmZuYmVs' | base64 -d | head
# ffnbelfdoeiohenkjibnmadjiehjhajb|YoroiWallet
# ibnejdfjmmkpcnlpebklmnkoeoihofec|Tronlink
# nkbihfbeogaeaoehlefnkodbefgpgknn|Metamask
# ...
FLOSS and strings output across the four stealer samples Figure 12 — Ranked strings across the four samples: IP-check services, encrypted-key fields and wallet targets.

The Final Rule — Strings + Offset Condition

The level explicitly requires a string-offset condition. Unlike Level 1, all four samples here carry intact MZ headers — so $mz at 0 both satisfies the requirement and, elegantly, excludes the header-corrupted LockBit sample from this family's rule.

level2.yar
rule DotNet_Stealer_Variants
{
    meta:
        description = "Detects .NET stealer variants targeting browsers, FTP clients and crypto-wallet extensions"
        author      = "Ahmet Can Aytekin"

    strings:
        $mz = { 4D 5A }
        $s1 = "bEncryptedData" ascii
        $s2 = "k__BackingField" ascii
        $s3 = "api.ip.sb" ascii wide
        $s4 = "net.tcp://" ascii wide

    condition:
        $mz at 0 and 2 of ($s*)
}
$mz at 0

The required offset condition — PE anchored at byte zero

$s1 / $s2

Compiler-generated property names shared by every variant

2 of ($s*)

Catches all four, tolerates per-variant string stripping

VARIANT-ANALYSIS LESSON

The common denominator is rarely the obvious string.

"FileZilla" looked like the perfect anchor — until sample_2 turned out to carry it only as a UTF-16 path template, invisible to a default ASCII scan. The strings that actually spanned all four variants were the unglamorous .NET internals: bEncryptedData and the backing-field name the compiler generates for the stealer's key property.

14 — LESSONS LEARNED

What Four Labs Teach About Detection Engineering

01

Validators are silent until they aren't

Chainsaw dropped metadata-incomplete rules without naming the missing field; the Sigma compiler swallowed indentation errors as "no hits". Build a lint step into the loop before trusting any zero-match result.

02

Author rules with the full skeleton

description, author, date, tags, falsepositives — treat the "optional" Sigma fields as mandatory. Tooling in the wild (and in these labs) assumes they exist.

03

Field + discriminator, never field alone

Event ID 104 belongs to multiple providers; wermgr.exe appears in benign telemetry. Pairing every match with a second event-unique field is what separates exact detection from noise.

04

Sign structure, not randomness

Per-build random filenames die with the build. Format magics, launcher syntax, staging paths and compiler-generated .NET internals are what survive across variants.

05

Scan ASCII and UTF-16 — always

The FileZilla paths and the wallet blob lived only in wide strings. A default strings run would have missed both the IOCs and a wrong-answer trap.

06

Read the bytes before the template

One hex dump revealed the shifted MZ header that would have broken every textbook YARA rule. Ten seconds of xxd beat an hour of condition debugging.

15 — MITRE ATT&CK

Techniques Covered Across the Series

DEFENSE EVASION T1070.001

Clear Windows Event Logs

SigmaPredator's entire arc: wevtutil, WMI, PowerShell cmdlets and the residual 1102/104 audit events.

DETECTED — 3 SIGMA RULES
DEFENSE EVASION T1055.012

Process Hollowing

rundll32 → wermgr.exe with PROCESS_ALL_ACCESS, reconstructed across Sysmon 1/10/12 in Sigma 101.

DETECTED — 3-SELECTION RULE
DEFENSE EVASION T1036 / T1562.001

Masquerading & Impairing Defenses

A .ico executed as VBScript, and deletion of __PSLockdownPolicy to escape Constrained Language Mode.

DETECTED — SIGMA 101 L1/L3
CREDENTIAL ACCESS / IMPACT T1555 / T1486

Credential Theft & Data Encryption

.NET stealers harvesting browser, FTP and wallet credentials; LockBit encryption with Tor-based ransom workflow — both signed with multi-variant YARA rules.

DETECTED — YARA101 L1/L2
16 — CONCLUSION

From Tradecraft to Signatures That Hold

Across four labs, the same loop repeated itself: research the technique, find its residue, express it as a rule — and then let a validator break that rule until it matched reality instead of assumptions.

The finished detections — three Sigma rules for event-log clearing, three for a lateral-movement chain, and multi-variant YARA signatures for an SFX loader, LockBit and a .NET stealer family — are less valuable than the debugging scars behind them. Silent parser rejections, provider-ambiguous Event IDs, Unicode-only strings and a sabotaged MZ header are precisely the obstacles production detection engineering is made of.

Research
→
Analyze
→
Author
→
Validate
→
Tune
→
Detect
A rule that merely compiles describes your intent. A rule that survives validation describes the adversary.
PROJECT AUTHOR

Ahmet Can Aytekin

Cyber Security • SOC Analysis • Detection Engineering • Sigma & YARA