0de6482c69377a127b91aa9c28d24981b656be44a9181a83c5b014a933987216Report: RFQ rfq_pdf.js — CJK-Steganography JScript Dropper
Build / RE
Outer Stage — JScript Polyglot (UTF-16 LE)
The carrier file is a 1,027,966-byte JScript source saved as UTF-16 LE with CRLF line terminators ^[file.txt], making it appear as Unicode text to casual inspection and causing CAPE to skip detonation (not a supported binary class). The social-engineering lure is a request-for-quotation PDF masquerade (RFQ rfq_pdf.js) — a double-extension attack exploiting Windows "Hide extensions for known file types." ^[metadata.json]
The script is not obfuscated with javascript-obfuscator or any commercial tool. Instead, the author has hand-rolled a CJK Unified Ideographs steganography engine that encodes a raw PE payload inside Unicode character literals assigned to nested JavaScript object properties.
Key structural observations from the decoded script ^[strings.txt]:
- A global object
KazakhstanFinallyUnfinishedStoppedacts as a lookup table with 74 top-level semantic English keys (e.g.,RitchieDetectingNutrientSuffers,FarmingAppellantLawyersHoffmanSpanish). - Each top-level key contains between 4 and 8 nested sub-keys, also random semantic English phrases (e.g.,
FamiliarityDistributionBatteriesHomepageInteraction,BrendanSpeciallyCruises). - The leaf value of every nested property is a long CJK character string (e.g.,
"㑍㑚㒐㐀㐃㐀㐀㐀㐄..."). Each CJK character encodes one payload byte viabyte = charcode - 0x3400. - An array
PostponedChargedOperationalRestrictionsMichaelsholds 384 environment-variable names. - A second array
VerticallyStayingSamuraiRealismholds 384[top_key, sub_key]pairs. - A
forloop walks both arrays in lockstep, assigns each decoded CJK block to an environment variable viaWScript.Shell.Environment("Process").Item(...), then spawns a PowerShell stage that reads those variables back and reconstructs the inner payload in-memory.
The technique is a custom byte-in-Unicode steganography with semantic English variable/key names used purely as obfuscation — the phrases have no actual meaning in the malware logic.
Inner Stage — .NET Framework 4.8 PE32+ Assembly
Reconstruction of the 384 CJK blocks yields a 385,024-byte PE32+ executable (GUI) x86-64 Mono/.NET assembly ^[reconstructed.bin].
| Property | Value |
|---|---|
| TimeDateStamp | 0x4ea90170 (2011-10-28 06:10:56 UTC) — likely forged or statically linked library timestamp |
| Linker | 11.27 (Visual Studio 2012 / .NET 4.8 toolchain) |
| Magic | 0x20b (PE32+) |
| Subsystem | 2 (GUI) |
| Sections | .text (382,464 bytes, entropy 2.60), .rsrc (2,048 bytes, entropy 4.11) |
| EntryPoint | 0x0 (typical for .NET assemblies; CLR handles entry) |
All observable type and method names are obfuscated with random semantic English phrases (e.g., AspirationsVegetablesUnregisteredDesignatedPartnerships, AuthorizesMercedesPracticed, GrindingNonethelessSubsystemAdherenceAndover) — the same naming convention used in the outer JScript keys. No meaningful namespace, class, or method names survive.
Import surface:
URLDownloadToFileWfromurlmon.dll^[strings.txt] — the primary C2 download primitive.OleGetClipboard/OleFlushClipboard— clipboard manipulation.AccessibleObjectFromWindow— potential accessibility/UI automation abuse.AllocHGlobal,Marshal— unmanaged memory allocation.GetCurrentProcess— self-reference.SHA256,ComputeHash,System.Security.Cryptography— hashing/cryptographic operations.- Standard .NET Framework 4.8 references:
System.Runtime.InteropServices,System.Runtime.CompilerServices,DllImportAttribute,AsyncCallback,BeginInvoke.
No hardcoded URLs, IPs, or domains were recovered from the reconstructed binary via static string extraction. The C2 endpoint is likely delivered at runtime or embedded in a secondary resource/config block that is itself encrypted.
The .NET assembly does not appear to be packed with ConfuserEx, SmartAssembly, or similar commercial protectors; the obfuscation is limited to name mangling and the outer CJK steganography wrapper. Entropy on .text (2.60) is consistent with unobfuscated IL, not a packed or encrypted payload.
Anti-Analysis
- UTF-16 LE encoding with very long lines (5,559-character lines) frustrates line-based grep and diff tools. ^[file.txt]
- CJK steganography hides the PE payload inside Unicode character literals that look like padding or noise to Western-language analysts.
- Semantic English obfuscation (random dictionary words for all variables, keys, and .NET type names) defeats string-based IOC extraction and symbol-based detection.
- Environment-variable staging breaks the payload across 384 process-scoped variables, making memory-dump analysis harder.
- No CAPE detonation because the outer file is typed as JavaScript text, not a PE — the sandbox skipped execution entirely. ^[dynamic-analysis.md]
Deploy / ATT&CK
| Technique | ID | Evidence |
|---|---|---|
| User Execution | T1204.001 | Double-extension JScript lure (RFQ rfq_pdf.js) masquerading as a PDF. |
| Obfuscated Files or Information | T1027.002 | Custom CJK Unicode steganography encoding a PE payload inside JavaScript object literals. |
| Inter-Process Communication via Environment Variables | T1134 (analogous) | Payload reconstructed from 384 WScript.Shell.Environment("Process") variables. |
| Ingress Tool Transfer | T1105 | URLDownloadToFileW import in inner .NET assembly; downloader behavior inferred. |
| Clipboard Modification | T1115 | OleGetClipboard / OleFlushClipboard present in .NET assembly. |
| Cryptographic Hashing | T1560.001 | SHA256.ComputeHash present; likely used for integrity checking or data transformation. |
C2 protocol: Static-only analysis. No network IOCs recovered. The inner .NET assembly imports URLDownloadToFileW from urlmon.dll, indicating an HTTP/HTTPS download stage, but the target URL is not embedded in the binary strings. It may be:
- Passed as an argument from the JScript stage (not recovered in this analysis), or
- Embedded in an encrypted resource or config block decoded at runtime.
Persistence: None observed statically. The JScript does not write to %APPDATA%\Startup, registry Run keys, or scheduled tasks. The .NET assembly may establish persistence after fetching its final payload, but that behavior requires dynamic execution.
Attribution: No linguistic, cultural, or infrastructure indicators. The semantic English obfuscation is generic (random dictionary words). No reused code signatures, PDB paths, or compiler artifacts link this to a known family. This is a singleton pending cluster confirmation.
Siblings
None confirmed. This is the first observed sample of this technique in the corpus.
IOCs
- SHA-256 (outer):
0de6482c69377a127b91aa9c28d24981b656be44a9181a83c5b014a933987216 - SHA-256 (inner .NET):
a0ddf0c9be23a7df15c29baa73d957d73f3dacadbc541673b89e9c61024ceb3c - MD5 (inner .NET):
99ace247a5da67754991079ce63efa85 - Filename lure:
RFQ rfq_pdf.js - Steganography decode key:
byte = charcode - 0x3400 - Environment variable count: 384
- CJK block count: 384
Recommendations
- Sigma / YARA: Hunt for UTF-16 LE JScript files containing large blocks of CJK Unified Ideographs (U+3400–U+4DBF) interleaved with semantic English variable assignments. A regex like
KazakhstanFinallyUnfinishedStopped\["[A-Z][a-z]+"\]is family-specific but may be brittle if the author rotates keys. - Memory forensics: Scan process environment blocks for unusually high counts of
WScript.Shell-created variables containing Base64 or binary data. - Dynamic: Execute the sample in a JavaScript-capable sandbox (not CAPE) to capture the PowerShell spawn and network traffic from the inner .NET downloader.