2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9funclassified-js-s3-dropper: 2dbebbafe9d9 — XOR-obfuscated WScript→S3 HTTPS downloader sibling
Executive Summary
A 2.5 KB JScript file (sw.js) that is the second confirmed sibling of the unclassified-js-s3-dropper family. The entire payload is XOR-obfuscated with key 204 inside a numeric byte array (var d=[...];) and decoded at runtime via a tiny JS loop before eval(). When decoded, the inner script is byte-for-byte identical to the plaintext sibling 26afa8d1 — same S3 URL, same Utilify_ staging name, same COM object chain, same SSL cert bypass. The only delta is the obfuscation layer and file size. Medium-confidence family attribution (n=2).
What It Is
| Field | Value |
|---|---|
| SHA-256 | 2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f |
| Size | 2541 bytes ^[file.txt] |
| Type | ASCII text, single line, no terminators ^[file.txt] |
| Language | JScript (Windows Script Host) |
| Obfuscation | XOR byte-array with key 204 ^[strings.txt:1] |
| Packing / crypter | N/A |
| Anti-analysis | None observed (no sandbox gating, no debugger checks) |
| Signing | N/A |
| Family | unclassified-js-s3-dropper (n=2, medium confidence) |
How It Works
Execution chain (single stage, decoded at runtime):
- Obfuscated payload storage — the file body contains a single JavaScript statement declaring a numeric array
dand an XOR loop that builds a stringr, theneval(r). ^[strings.txt:1] - Decoding — each byte in
dis XORed with204(0xCC) and converted to a character, reassembling the inner JScript dropper. The decode is done in-place with no external key source; the key is hardcoded. ^[strings.txt:1] - Inner dropper — once decoded, the payload is identical to sibling
26afa8d1:- Expands
%TEMP%viaWScript.Shell^[decoded-payload] - Generates
Utilify_<random8>.exe^[decoded-payload] - Uses
MSXML2.ServerXMLHTTP.6.0withsetOption(2,13056)to disable SSL validation ^[decoded-payload] - Downloads
https://amazonbusketss-535659318049-us-west-1-an.s3.us-west-1.amazonaws.com/UtilifySetup.exe^[decoded-payload] - Writes via
ADODB.Streamwith a>=1024byte size gate ^[decoded-payload] - Executes hidden via
WScript.Shell.Run(...,0,false)^[decoded-payload]
- Expands
- Error suppression — the decoded script wraps the entire chain in a bare
try{...}catch(e){}block; failures are silent. ^[decoded-payload]
Decompiled Behavior
N/A — sample is an obfuscated plaintext JScript file, not a PE. floss and capa both errored on non-PE input. ^[floss.txt] ^[capa.txt]
C2 Infrastructure
| Indicator | Value | Notes |
|---|---|---|
| URL | https://amazonbusketss-535659318049-us-west-1-an.s3.us-west-1.amazonaws.com/UtilifySetup.exe |
Hardcoded; identical to sibling 26afa8d1 ^[decoded-payload] |
| Domain | amazonbusketss-535659318049-us-west-1-an.s3.us-west-1.amazonaws.com |
S3 virtual-hosted style; attacker-controlled bucket ^[decoded-payload] |
| Region | us-west-1 |
Hardcoded in endpoint ^[decoded-payload] |
| Downloaded filename | UtilifySetup.exe |
Masquerades as a utility installer ^[decoded-payload] |
| Local staging name | %TEMP%\Utilify_<random8>.exe |
Predictable prefix, random suffix ^[decoded-payload] |
| SSL validation | Disabled via setOption(2,13056) |
Accepts any server certificate ^[decoded-payload] |
No backup URLs, DGA, or fallback C2 observed. No network-level authentication, headers, or cookie gating.
Interesting Tidbits
- Zero-delta inner payload — after XOR decoding, the script is identical in every byte to the plaintext sibling
26afa8d1. This is not a new build; it is the same dropper wrapped in a different obfuscation skin. ^[decoded-payload] - Trivial key — XOR key
204(0xCC) is a common fill-byte value. The obfuscation is weak and falls to manual XOR or any string decoder that evaluates JavaScript. ^[strings.txt:1] - Filename is
.jsmasquerade — triage filename issw.js, suggesting it may be presented as a service-worker script or bundled with a web lure. The first sibling had no filename metadata in triage. ^[triage.json] - Size gate still minimal —
>=1024bytes is a rudimentary anti-honeypot check; any non-empty PE passes. ^[decoded-payload] - No persistence — one-shot execution; the downloaded PE must install its own persistence. ^[decoded-payload]
- Static tools fail gracefully —
filereports "ASCII text",binwalkfinds nothing,rabin2confirms non-PE. The threat is entirely in the evaluated script, not in any embedded binary payload. ^[file.txt] ^[binwalk.txt] ^[rabin2-info.txt]
How To Mess With It (Homelab Replication)
Goal: reproduce the XOR-obfuscated JS downloader and verify the decode.
Toolchain: Any text editor + Node.js or a browser console.
Working source snippet:
var payload = 'var w=new ActiveXObject("WScript.Shell");...'; // the inner dropper
var key = 204;
var d = [];
for (var i = 0; i < payload.length; i++) d.push(payload.charCodeAt(i) ^ key);
var enc = "var d=[" + d.join(",") + "];var k=" + key + ';var r="";for(var i=0;i<d.length;i++)r+=String.fromCharCode(d[i]^k);eval(r);';
console.log(enc);
Verification step:
- Save the encoded output to
sw.js. - Run
node sw.js(or paste into a browser console) — it should silently succeed and the innereval(r)should execute without error. - Replace
eval(r)withconsole.log(r)during testing to inspect the decoded payload. - Compare the decoded string against the known sibling
26afa8d1— they should be identical.
What you'll learn: how a single-byte XOR with a hardcoded key and eval() can turn a trivial script into something that bypasses naive static string matching, and why decoding the outer layer is always the first step.
Deployable Signatures
YARA rule
rule JS_S3_Downloader_XOR_Obfuscated {
meta:
description = "XOR-obfuscated WScript JS S3 downloader with byte-array eval"
author = "PacketPursuit"
date = "2026-06-23"
sha256 = "2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f"
strings:
$a = "var d=[" ascii wide
$b = "eval(r)" ascii wide
$c = "String.fromCharCode(d[i]^k)" ascii wide
$d = "MSXML2.ServerXMLHTTP.6.0" ascii wide
$e = "ADODB.Stream" ascii wide
$f = "setOption(2,13056)" ascii wide
$g = "Utilify_" ascii wide
$h = /\.s3\.[a-z0-9-]+\.amazonaws\.com\// ascii wide
condition:
filesize < 5KB and 5 of them
}
Sigma rule
Identical to sibling 26afa8d1 — the runtime behavior is the same. See the Sigma rule in /intel/analyses/26afa8d11ece77de51b54648010198884238cbddd4230cf9008903e2d4f1352f.html.
IOC list
| Type | Value |
|---|---|
| SHA-256 | 2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f |
| URL | https://amazonbusketss-535659318049-us-west-1-an.s3.us-west-1.amazonaws.com/UtilifySetup.exe |
| Filename pattern | Utilify_*.exe |
| Staging directory | %TEMP% |
| COM objects | MSXML2.ServerXMLHTTP.6.0, ADODB.Stream, WScript.Shell |
| XOR key (static) | 204 (0xCC) |
Behavioral fingerprint
An obfuscated JScript file under 3 KB, single line, containing a hardcoded numeric byte array and a tiny XOR loop with key 204 that decodes to a plaintext WScript dropper. The decoded payload instantiates WScript.Shell, MSXML2.ServerXMLHTTP.6.0, and ADODB.Stream, disables TLS certificate validation via setOption(2,13056), performs a synchronous HTTPS GET to an S3 virtual-hosted endpoint, writes the response body to %TEMP%\Utilify_<random8>.exe only if it exceeds 1024 bytes, then executes it hidden. All errors are silently swallowed in a bare catch(e){} block. No persistence, no sandbox checks.
Detection Signatures
N/A — capa does not analyse script files. ATT&CK mapping is inferred from static source inspection and documented below.
| Tactic | Technique | Evidence |
|---|---|---|
| Execution | T1059.005 (Visual Basic / JScript) | .js carrier executed by WScript/CScript ^[triage.json] |
| Defense Evasion | T1562.001 (Impair Defenses: Disable or Modify Tools) | SSL certificate validation disabled via setOption(2,13056) ^[decoded-payload] |
| Defense Evasion | T1027 (Obfuscated Files or Information) | XOR byte-array obfuscation with hardcoded key ^[strings.txt:1] |
| Command & Control | T1071.001 (Web Protocols) | HTTPS GET to S3 endpoint ^[decoded-payload] |
| Ingress Tool Transfer | T1105 (Tool Ingress) | Downloads remote PE to local disk ^[decoded-payload] |
References
- SHA-256:
2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f - Artifact ID:
90c17fac-75bb-4f33-a66f-272215b74033 - Source: MalwareBazaar via OpenCTI connector
- Sibling analysis:
26afa8d11ece77de51b54648010198884238cbddd4230cf9008903e2d4f1352f— plaintext variant, identical inner payload - Related entity: unclassified-js-s3-dropper
- Related concept: xor-string-decryption-loop
Provenance
Analysis based on:
file.txt—fileutility (identifies plaintext JS, single line) ^[file.txt]strings.txt—strings -n 6(full obfuscated payload recovered, line 1) ^[strings.txt:1]floss.txt— N/A (errored on non-PE input) ^[floss.txt]capa.txt— N/A (rejected non-PE input) ^[capa.txt]binwalk.txt— N/A (no embedded artefacts) ^[binwalk.txt]rabin2-info.txt— radare2rabin2 -I(confirms non-PE) ^[rabin2-info.txt]triage.json— triage metadata (filenamesw.js, no family) ^[triage.json]dynamic-analysis.md— CAPE skipped (unsupported binary class) ^[dynamic-analysis.md]- Decoded payload verified by local Python XOR decode (key 204) producing byte-for-byte match to sibling
26afa8d1strings.txt
All claims trace to ^[raw/analyses/2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f/<file>] markers inline above.