typeanalysisfamilyunclassified-js-s3-dropperconfidencemediumcreated2026-06-23updated2026-06-23scriptdropperc2loaderdefense-evasionobfuscation
SHA-256: 2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f

unclassified-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):

  1. Obfuscated payload storage — the file body contains a single JavaScript statement declaring a numeric array d and an XOR loop that builds a string r, then eval(r). ^[strings.txt:1]
  2. Decoding — each byte in d is XORed with 204 (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]
  3. Inner dropper — once decoded, the payload is identical to sibling 26afa8d1:
    • Expands %TEMP% via WScript.Shell ^[decoded-payload]
    • Generates Utilify_<random8>.exe ^[decoded-payload]
    • Uses MSXML2.ServerXMLHTTP.6.0 with setOption(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.Stream with a >=1024 byte size gate ^[decoded-payload]
    • Executes hidden via WScript.Shell.Run(...,0,false) ^[decoded-payload]
  4. 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 .js masquerade — triage filename is sw.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>=1024 bytes 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 gracefullyfile reports "ASCII text", binwalk finds nothing, rabin2 confirms 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:

  1. Save the encoded output to sw.js.
  2. Run node sw.js (or paste into a browser console) — it should silently succeed and the inner eval(r) should execute without error.
  3. Replace eval(r) with console.log(r) during testing to inspect the decoded payload.
  4. 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.txtfile utility (identifies plaintext JS, single line) ^[file.txt]
  • strings.txtstrings -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 — radare2 rabin2 -I (confirms non-PE) ^[rabin2-info.txt]
  • triage.json — triage metadata (filename sw.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 26afa8d1 strings.txt

All claims trace to ^[raw/analyses/2dbebbafe9d931b6a9ed9401aaf06acb31d341413f77adecb7c7e4e0e904de9f/<file>] markers inline above.