51500e40881f7a9c6c0a556af80e9c93d35dd0f08472dafa3bf8ce899769f0c8Unclassified Batch Self-Extract .NET Dropper: 51500e40 — Shipping-invoice BAT→PowerShell→ConfuserEx .NET chain with byte-reversed gzip payload
Executive Summary
A 2.4 MB batch-script dropper masquerading as a shipping-container arrival notice (Arrival_Notice_Invoice_for_Container_No_FBLU0089027.bat). The outer .bat uses Unicode Armenian/Cyrillic variable-name obfuscation and a copy /b /y self-extraction trick (renaming itself to .Seu) to hide a gzip+Base64-encoded .NET Framework 4.5 payload inside the script body. A PowerShell cradle decodes the payload, byte-reverses it, and reflectively loads the resulting PE. The inner PE is a ConfuserEx-obfuscated .NET assembly with two embedded encrypted resources, System.Web imports, and no recoverable C2 at static time. No CAPE detonation possible (text file). ^[file.txt] ^[strings.txt:1-50]
What It Is
| Field | Value |
|---|---|
| SHA-256 | 51500e40881f7a9c6c0a556af80e9c93d35dd0f08472dafa3bf8ce899769f0c8 |
| Filename | Arrival_Notice_Invoice_for_Container_No_FBLU0089027.bat |
| Size | 2,441,640 bytes (2.4 MB) |
| File type | Unicode text, UTF-8, very long lines (56,650 chars), CRLF |
| OpenCTI labels | bat, malware-bazaar |
| Family (preliminary) | unattributed |
| Compile timestamp | Sep 6 02:19:39 2024 (inner PE) |
The batch script is a polyglot: valid DOS batch syntax on top, a self-contained gzip archive appended below the exit command. The attacker reuses the container-shipping social-engineering theme (FBLU0089027 — a plausible container ID format).
How It Works
Stage 1: Self-Extraction (BAT)
The outer batch uses three tricks:
- Unicode variable-name obfuscation —
SETcommands use Armenian block characters (U+0530–U+058F) and Cyrillic extensions as variable names, making static reconstruction impossible without parsing the expansion. ^[strings.txt:1-30] - Archive self-attachment — The script copies itself to
%~0.Seu, creating a valid archive file (.Seuis interpreted as an extension, not an archive format per se; the payload lives after theexitline). ^[strings.txt:232-250] - Silent attribute flip —
attrib +s +hon the.Seucopy to hide it. ^[strings.txt:21-22]
Stage 2: PowerShell Cradle
A single-line %VARNAME% expansion reassembles into:
powershell.exe -WindowStyle Hidden -command "..."
The PowerShell payload:
- Reads the
.batfile from disk - Extracts everything after the
exitline (offset ~8886) - Base64-decodes the trailing string
- GZip-decompresses the result
- Byte-reverses the entire decompressed buffer (reversal detected: first byte
0x00, last byte0x4d, reversed →MZ\x90...) - Loads the resulting PE reflectively via
[System.Reflection.Assembly]::Load^[reconstructed from strings.txt:60-250]
Stage 3: Inner .NET Payload
After reversal, the payload is a valid PE32 .NET Framework 4.5 assembly:
| Property | Value |
|---|---|
| Module name | Arrival Notice Invoice for Container No FBLU0089027.exe |
| MVID | eb399d60-1f72-4ae7-05cc-fed47baee125 |
| Assembly version | 1.0.0.0 |
| Sections | .text (2,091,008 bytes), .rsrc (2,048 bytes), .reloc (512 bytes) |
| Imports | mscoree.dll!_CorExeMain only |
| Compile timestamp | 2024-09-06 02:19:39 UTC |
Obfuscation: ConfuserEx — method and type names are mangled to base64-like tokens (#=q…== not observed; instead the obfuscator uses plausible English semantic names like ImageResizer.Workers.TokenDatabaseWorker, ResolveWrapper, LoginWrapper, QueryWrapper, etc.). This is consistent with ConfuserEx's "rename to dictionary words" option rather than the classic #=q…== mangling. ^[dnfile]
Resources: Two embedded .NET manifest resources:
Qsskqqjy.Properties.Resources.resources— 1,625,306 bytes,.resourcesformat (magic0xBEEFCACE), containing 145 named entries (likely encrypted config / stage data). ^[dnfile](Unicode whitespace name) — 16,511 bytes, high-entropy, no recognizable header. Repeating bigram44 7dsuggests XOR or stream-cipher encryption. ^[dnfile]
Assembly references: mscorlib, System.Web, System, System.Configuration, System.Drawing, System.Xml, System.Core. The System.Web reference is notable for HTTP C2 or web-shell behaviors. ^[dnfile]
Decompiled Behavior
Ghidra / radare2 are not applicable here (scripted dropper, not a native PE). The decompilation of the inner .NET payload via dnfile reveals:
- No hardcoded C2 — all strings observed are framework / obfuscator artifacts. C2 is likely runtime-decrypted from the 16 KB encrypted resource.
- Web-facing surface —
System.Webnamespace imports (HttpException,HttpContext,HttpApplication,HttpRequest,HttpResponse,HttpRuntime,IHttpHandler,IHttpModule) indicate the payload may function as a hidden HTTP handler, web-shell, or C2 client. ^[dnfile] - No persistence hooks visible in static metadata. Persistence may be established by the .NET payload at runtime.
C2 Infrastructure
Not recoverable statically. No IP, domain, URL, mutex, or named pipe found in:
- Batch script strings (obfuscated via variable expansion)
- Inner .NET strings (encrypted at rest by ConfuserEx)
- Resource data (encrypted / compressed)
The 16,511-byte encrypted resource is the most likely C2 config carrier. Decryption would require runtime instrumentation or deobfuscation of the ConfuserEx layer.
Interesting Tidbits
- Container-ID lure —
FBLU0089027follows the ISO 6346 container-code format (4-letter owner code + 6-digit serial + 1 check digit). This is a high-effort social-engineering detail. ^[strings.txt:232-250] - Self-attaching archive — The payload is not fetched from the internet; it is embedded in the
.batitself. This makes the sample fully self-contained and operational offline. ^[reconstructed from strings.txt:232-250] - Byte reversal — The gzip-decompressed payload is stored backwards. This is an uncommon anti-signature trick: standard tools scanning for
MZat the start of a gzip stream will find nothing. ^[payload extraction] - 2010 copyright masquerade — VS_VERSIONINFO claims copyright
2010, product name matching the lure. ^[rabin2-info.txt] - Batch-to-.NET size ratio — The outer batch is 2.4 MB, the inner PE is 2.09 MB. The overhead is the obfuscated variable-assignment noise (~300 KB of
SETlines). ^[file.txt]
How To Mess With It (Homelab Replication)
- Build the chain
# Encode your payload $bytes = [IO.File]::ReadAllBytes("payload.exe") [Array]::Reverse($bytes) $gz = [Convert]::ToBase64String((New-Object IO.MemoryStream(,($bytes | ForEach-Object {$_}))).ToArray()) # ... then gzip-compress and base64-wrap - Embed in batch
- Write a
.batwith Armenian-variable SET assignments. - Append the gzip+Base64 payload after an
exitline. - Use
%~0.Seuself-copy to hide the archive copy.
- Write a
- Verify evasion
- Static string extraction on the
.batshould not surfacepowershell,FromBase64String, or the payload MZ header. - Only the expanded
%VAR%line (at runtime) reveals the cradle.
- Static string extraction on the
Deployable Signatures
YARA rule
rule Batch_GZip_Reversed_NET_Dropper {
meta:
description = "Batch self-extract dropper with gzip+reversed .NET payload"
author = "PacketPursuit SOC"
date = "2026-07-08"
sha256 = "51500e40881f7a9c6c0a556af80e9c93d35dd0f08472dafa3bf8ce899769f0c8"
strings:
$a = "%~0.Seu" ascii
$b = "attrib" ascii wide
$c = "H4sI" ascii wide // gzip magic in base64
$d = "powershell" ascii wide nocase
$e = "-WindowStyle Hidden" ascii wide nocase
$f = /set\s+"[\x{0530}-\x{058F}]+=/ wide
condition:
filesize > 1MB and
#a >= 1 and
#c >= 1 and
4 of them
}
Sigma rule
title: Batch Self-Extract PowerShell Reversed .NET Payload
logsource:
product: windows
category: process_creation
detection:
selection:
CommandLine|contains:
- 'powershell'
- '-WindowStyle Hidden'
ParentImage|endswith: '\cmd.exe'
ParentCommandLine|contains:
- '.bat'
- '.cmd'
condition: selection
falsepositives:
- Legitimate IT automation scripts
level: medium
IOC list
| Indicator | Type | Note |
|---|---|---|
Arrival_Notice_Invoice_for_Container_No_FBLU0089027.bat |
Filename | Lure |
Arrival_Notice_Invoice_for_Container_No_FBLU0089027.exe |
Internal module name | Inner PE |
51500e40881f7a9c6c0a556af80e9c93d35dd0f08472dafa3bf8ce899769f0c8 |
SHA-256 | Outer batch |
eb399d60-1f72-4ae7-05cc-fed47baee125 |
MVID | Inner .NET assembly |
~0.Seu |
File artifact | Self-extraction archive copy |
Behavioral fingerprint
This sample is a text-file dropper that spawns powershell.exe -WindowStyle Hidden with a command-line exceeding 56,000 characters (the expanded %VAR% chain). The PowerShell reads its own parent .bat from disk, extracts a gzip+Base64 payload after the exit line, decompresses it, byte-reverses the result, and reflectively loads a 2 MB .NET Framework 4.5 assembly. The inner assembly imports System.Web and carries two encrypted manifest resources totaling ~1.64 MB. No network indicators are visible statically.
Detection Signatures
| Capability | Evidence | ATT&CK |
|---|---|---|
| Batch script execution | cmd.exe running .bat file |
T1059.003 |
| PowerShell reflective execution | Assembly.Load(byte[]) in decoded PowerShell |
T1059.001 |
| Obfuscated command line | Unicode variable expansion >56K chars | T1027.010 |
| Self-extraction | copy /b /y %~0 %~0.Seu |
T1027.002 |
| In-memory payload loading | Reflective .NET assembly load | T1620 |
| Data encoding | GZip + Base64 + byte reversal | T1027 |
References
- Artifact ID:
52d21f0b-0b34-483b-b8b5-bc3ef9d3a9b8(OpenCTI) ^[metadata.json] - MalwareBazaar entry (if fetched via
mb-fetch.py) - Related wiki: unclassified-batch-selfextract-dotnet-dropper
Provenance
- Outer file type:
file(1)on batch script ^[file.txt] - Inner PE analysis:
rabin2 -I, dnfile, pefile on extracted reversed payload ^[rabin2-info.txt] - String extraction:
stringson both outer batch and inner PE ^[strings.txt] - Resource enumeration: dnfile
dn.net.resourcesanddn.net.mdtables.ManifestResource^[dnfile] - FLOSS: Not applicable (text file, not a PE) ^[floss.txt]
- CAPA: Not applicable ^[capa.txt]
- CAPE: Skipped — unsupported file type for detonation ^[dynamic-analysis.md]