0e4141aac553fa9b2e3a224ad54ce65ba61ddbf9c1e856d363b59cad111ef0d4unclassified-js-dropper: 0e4141aa — WScript→PowerShell→.NET assembly loader with debugger/sandbox gate
Executive Summary
A Portuguese-language WScript dropper (ykqtogmy.js) designed to run from the user's Temp/Downloads directory. It self-copies to C:\Users\Public\nswls.js, launches via wscript.exe, and emits a layered PowerShell payload that: checks internet connectivity, enumerates debugger/sandbox processes, downloads a .NET assembly byte array from a Brazilian HostGator domain, reflectively loads it via System.Reflection.Assembly, and invokes method ClassLibrary3.Class1::prFVI with C2 arguments including a secondary download URL. ^[strings.txt:39;^strings.txt:52;^strings.txt:55]
What It Is
- Type: UTF-16LE Windows Script Host (WScript)
.jsfile (not PE) ^[file.txt] - Size: 41,218 bytes (41 KB) ^[metadata.json]
- Origin: Labeled
ykqtogmy.jsby MalwareBazaar / OpenCTI. Artifact IDcb212459-9a29-4924-8903-9301e0f27779^[metadata.json] - Language / Platform: JScript for Windows Script Host (WScript), targeting Windows environments
- Packer / Obfuscator: Manual obfuscation — dead functions (
ZaYEL,CTQLO,RGrIv,WehKV,PuoEh,fcUyb, etc.), Unicode garbage strings (CJK, Arabic, emoji, Cyrillic), repeated no-op assignments, semicolon noise. No commercial packer (e.g., JScript-Obfuscator, ConfuserEx) observed. ^[sample_utf8.js:1-470]
How It Works
Stage 1 — Environment Relocation
At top-level, the script checks WScript.ScriptFullName for "Temp" or "Downloads" in the path. ^[sample_utf8.js:41]
If matched, it:
- Copies itself to
C:\Users\Public\nswls.jsusingScripting.FileSystemObject.CopyFile. ^[sample_utf8.js:52-53] - Launches the copy via
Shell.Application.ShellExecute("wscript.exe", "//nologo \"...nswls.js\"", "", "open", 0). ^[sample_utf8.js:56] - Calls
WScript.Quit()to end the original process. ^[sample_utf8.js:58]
This ensures the active copy is staged outside of the browser-download quarantine directories.
Stage 2 — PowerShell String Generation
The payload string PoQct is built across multiple concatenated double-quoted fragments (~7,400 chars total). ^[sample_utf8.js:342]
Obfuscation layers:
- Fragment concatenation: Single characters and short strings joined via
+inside the JS string literal. ^[sample_utf8.js:342] - Noise insertion: Characters
'A'and'9'are replaced with expanded patterns" + A + "/" + 9 + ", then later stripped by PowerShellreplacestatements. ^[sample_utf8.js:426-427;^sample_utf8.js:441-443] - Quote stripping: PowerShell script removes all single quotes (
''),+, and spaces at runtime before base64-decoding. ^[sample_utf8.js:441-443]
The cleaned string is valid Base64 and decodes to a self-contained PowerShell script (~3,000 chars). ^[decoded_final.txt:1]
Stage 3 — PowerShell Gate + Downloader
Decoded PS script performs three gates before proceeding:
- Internet-connectivity gate:
Test-Connection 'www.google.com' -ErrorAction SilentlyContinue. If$null(no connectivity), callsirRkHwhich runsRestart-Computer -Force. ^[decoded_final.txt:4-12] - Debugger/sandbox process gate:
Get-Processenumerateshandle,autorunsc,Dbgview,tcpvcon,any.run,sandbox,tcpview,OLLYDBG,ImmunityDebugger,Wireshark,apateDNS,analyze. If any found, also triggersRestart-Computer -Force. ^[decoded_final.txt:16-22]
If gates pass, it forces TLS 1.2, constructs a C2 URL via Base64 decoding:
- Primary C2 (stage-2 payload text file):
https://andrefelipedonascime1775471117328.2082219.meusitehostgator.com.br/FVTwhWzaQj_06_04_Meus_ArquivosDeTexto/03.txt^[decoded_final.txt] - Secondary C2 (.NET assembly DLL or PE):
https://catalogo.castrou2la.com/a9f88b/pr.txt^[decoded_final.txt]
It downloads 03.txt, strips a %x% prefix, saves the cleaned content to C:\Users\Public\pfvzx.txt, splits the file on commas into a [byte[]] array, reflectively loads it via System.Reflection.Assembly::Load($cplhq), invokes type ClassLibrary3.Class1 with method prFVI, passing a 5-argument object array containing the secondary C2 URL, %vVlGz% (script path), msbuild path, $true, and the assembly byte array itself. ^[decoded_final.txt]
Stage 4 — Second-Stage Drop
The same PowerShell script writes a second PS file (sqzch_01.ps1) to C:\Users\Public\ and immediately re-launches PowerShell with -ExecutionPolicy Bypass -File pointing to it. ^[decoded_final.txt]
Build / RE
- Toolchain: Hand-written JScript — no compiler, no packer, no framework.
- Obfuscation: Manual — dead functions, repeated no-op variable assignments, Unicode garbage, semicolon spam. No string-array obfuscation (unlike spamita). No control-flow flattening. ^[sample_utf8.js:1-470]
- Anti-analysis: Process-name debugger/sandbox enumeration (PowerShell
get-process), connectivity check towww.google.com, conditional computer restart on detection. No anti-VM (CPUID, WMI), no timing delays. ^[decoded_final.txt] - Code quality: Low — verbose, repetitive, easily cleaned with simple string concatenation and regex. The author appears to have copy-pasted the same junk-function block dozens of times. Comments in Portuguese (
Linha 5: "..." para ZaYEL). ^[sample_utf8.js:181;^sample_utf8.js:293]
Deploy / ATT&CK
| Tactic | Technique | Implementation |
|---|---|---|
| Execution | T1059.005 — Visual Basic / JScript | WScript hosts .js file; native Windows feature. ^[sample_utf8.js:1] |
| Execution | T1059.001 — PowerShell | PowerShell invoked with -ExecutionPolicy Bypass -File via ShellExecute. ^[decoded_final.txt] |
| Defense Evasion | T1497 — Virtualization/Sandbox Evasion | Process-name check for debuggers / sandboxes; restart-on-detection. ^[decoded_final.txt:16] |
| Defense Evasion | T1218 — System Binary Proxy Execution | wscript.exe used to proxy execution of JScript payload. ^[sample_utf8.js:56] |
| Persistence | T1547.001 — Registry Run Keys | Suspected (not observed in this sample but common in Troldesh cluster); the nswls.js copy path is Public, a known Troldesh persistence directory. ^[sample_utf8.js:52-53] |
| Discovery | T1012 — Query Registry / T1082 — System Information | WScript.ScriptFullName path introspection to detect Temp/Downloads origin. ^[sample_utf8.js:41] |
| Command & Control | T1071.001 — Web Protocols | HTTP(S) to HostGator domain for second-stage payload; secondary C2 on catalogo.castrou2la.com. ^[decoded_final.txt] |
| Exfil | T1041 — Exfiltration Over C2 Channel | Inferred from Troldesh pattern; not observed in static. |
C2 Infrastructure
| Indicator | Type | Note |
|---|---|---|
andrefelipedonascime1775471117328.2082219.meusitehostgator.com.br |
Domain | Brazilian HostGator subdomain; serves stage-2 text payload (03.txt). Pattern: *.meusitehostgator.com.br is a known cheap reseller host abused by Brazilian malware. ^[decoded_final.txt] |
catalogo.castrou2la.com |
Domain | Secondary C2; catalogo path suggests masquerade as an e-commerce store. ^[decoded_final.txt] |
https://catalogo.castrou2la.com/a9f88b/pr.txt |
URL | Likely reflectively-loaded .NET assembly or packed PE delivered as comma-separated decimal bytes. ^[decoded_final.txt] |
C:\Users\Public\nswls.js |
File path | Relocated copy of the JScript payload. ^[sample_utf8.js:50] |
C:\Users\Public\ntkzl.ps1 |
File path | First-stage PowerShell script generated by JS. ^[decoded_final.txt] |
C:\Users\Public\hhsqh.txt |
File path | C2 URL holder file created by the PS payload. ^[decoded_final.txt] |
C:\Users\Public\pfvzx.txt |
File path | Second-stage payload text file (cleaned). ^[decoded_final.txt] |
C:\Users\Public\sqzch_01.ps1 |
File path | Second-stage PowerShell script generated at runtime. ^[decoded_final.txt] |
Interesting Tidbits
- Portuguese fingerprints: Comments read
para RGrIv doisandpara verificar se um, and the HostGator domain is a Brazilian reseller (meusitehostgator.com.br). This aligns with Brazilian crimeware clusters such as Troldesh/Xorist and generic stealers/droppers. No Portuguese-language ransom notes observed (static only). ^[sample_utf8.js:293;^sample_utf8.js:342] - Reused C2 infrastructure: The numeric subdomain
1775471117328.2082219.meusitehostgator.com.brfollows a pattern of numeric tokens, possibly derived from victim ID or campaign metadata. - No YARA hits: Triaged with zero YARA matches, confirming the sample has no known family label in our current rule sets. ^[yara.txt]
- CAPE skipped: Not a supported binary class for detonation. All behavioral claims are static inferences. ^[dynamic-analysis.md]
- Attribution confidence: medium. Pattern (WScript→PS→.NET reflector, Brazilian HostGator,
C:\Users\Publicstaging, process-name sandbox gate) is strongly consistent with Troldesh / Xorist / generic Brazilian stealer chains. However, without the second-stage payload or a ransom note, no definitive family label is assigned.
Detection Signatures
IOC List
| IOC | Type |
|---|---|
0e4141aac553fa9b2e3a224ad54ce65ba61ddbf9c1e856d363b59cad111ef0d4 |
SHA-256 (this sample) |
ykqtogmy.js |
Filename (observed) |
C:\Users\Public\nswls.js |
File path (persistence/copy) |
C:\Users\Public\ntkzl.ps1 |
File path (generated PS) |
C:\Users\Public\sqzch_01.ps1 |
File path (second-stage PS) |
C:\Users\Public\hhsqh.txt |
File path (C2 URL holder) |
C:\Users\Public\pfvzx.txt |
File path (second-stage payload) |
andrefelipedonascime1775471117328.2082219.meusitehostgator.com.br |
Domain |
catalogo.castrou2la.com |
Domain |
Sigma Rule — WScript PowerShell Chain with Public Path
title: WScript-to-PowerShell Chain with Public Directory Staging
id: c7a3f2e1-8b44-4c90-a3d2-0e4141aa-
status: experimental
description: Detects WScript spawning PowerShell with ExecutionPolicy Bypass targeting files in C:\Users\Public\, consistent with JS dropper staging.
logsource:
category: process_creation
product: windows
detection:
selection_main:
ParentImage|endswith: '\wscript.exe'
CommandLine|contains:
- 'ExecutionPolicy Bypass'
- 'C:\\Users\\Public\\'
selection_child:
Image|endswith: '\powershell.exe'
condition: selection_main and selection_child
falsepositives:
- Legitimate administrative scripts
level: high
YARA Rule — Troldesh-Style JS Dropper Signature
rule troldesh_js_dropper_heuristic
{
meta:
description = "Heuristic for Troldesh-style WScript→PowerShell dropper JS"
author = "pp-hermes"
date = "2026-06-02"
sha256 = "0e4141aac553fa9b2e3a224ad54ce65ba61ddbf9c1e856d363b59cad111ef0d4"
strings:
$wscript_fullname = "WScript.ScriptFullName" ascii wide
$temp_check = "Temp" ascii wide
$downloads_check = "Downloads" ascii wide
$shell_app = "Shell.Application" ascii wide
$shell_exec = "ShellExecute" ascii wide
$fso = "Scripting.FileSystemObject" ascii wide
$powershell_chain = "power" + "rsh" + "ell" ascii wide
$base64_decode = "FromBase64String" ascii wide
$reflection_load = "System.Reflection.Assembly" ascii wide
condition:
filesize < 100KB and
all of ($wscript_fullname, $fso, $shell_app) and
any of ($temp_check, $downloads_check) and
any of ($powershell_chain, $base64_decode, $reflection_load)
}
How To Mess With It (Homelab Replication)
- Write a minimal JScript that checks
WScript.ScriptFullName.indexOf("Temp"), copies toC:\Users\Public\, and launches itself. - Build the PowerShell downloader inside a Base64-encoded string; concatenate with
+ 'A' +noise. - Add a sandbox gate (
get-process handle, wireshark, any.run -SilentlyContinue). - Reflectively load a small .NET assembly from a comma-delimited text file via
System.Reflection.Assembly::Load([byte[]]). - Compare
capaoutput — N/A for script; instead verify with manual string extraction and YARA rule above.
This is an exercise in persistence staging and PowerShell obfuscation, not in PE reverse engineering.
References
- Sample:
0e4141aac553fa9b2e3a224ad54ce65ba61ddbf9c1e856d363b59cad111ef0d4 - Artifact ID:
cb212459-9a29-4924-8903-9301e0f27779 - Source: OpenCTI / MalwareBazaar
- Related wiki page: spamita — another JScript family with comparable three-stage obfuscation, though this sample uses manual dead-code injection rather than RC4 encryption.
Provenance
Analysis derived from UTF-16LE JScript source (sample_utf8.js, lines 1–470) decoded via iconv -f UTF-16LE -t UTF-8; Base64 payload reconstructed with string concatenation stripping noise characters (', + , spaces) matching the PowerShell replace operations defined at lines 426–443 of the JS source. Decoded PowerShell saved to /tmp/decoded_final.txt. Dynamic analysis absent (CAPE skipped — unsupported file type). File-type: Unicode text UTF-16LE ^[file.txt]. No PE sections; not a binary.