Executive Summary
Fortra Intelligence and Research Experts (FIRE) has identified an active phishing campaign delivering fileless malware that uses five distinct layers of obfuscation. The high level of obfuscation serves to improve the compromise success rate and buy extra time to achieve credential theft and/or data exfiltration objectives. The layered obfuscation is intended to:
Increase initial delivery success rates by bypassing prevention controls at the email and endpoint level
Decrease the likelihood of post-delivery detection to increase dwell time to achieve attacker objectives (such as credential theft, data exfiltration or further payload delivery)
Complicate forensic investigations and delay remediation
The file-less malware is a multi-stage JScript and PowerShell loader to deploy an in-memory .NET assembly. The sample chains five distinct obfuscation layers before reflectively loading the final stage, without writing the executable payload to disk.
FIRE first observed the fileless campaign targeting a North America-based multinational software and SaaS provider (large enterprise) and the sophistication identified in the analysis suggests the campaign targets similarly sized enterprises as high value targets.
At this stage, there is not enough evidence to determine whether this level of sophistication reflects the work of a single advanced persistent threat group or if we will see multiple groups use the loader as part of a crypter-as-a-service model.
The loader demonstrates how attackers are investing more heavily in evasion techniques. The layered obfuscation is designed to defeat static signatures, AMSI and string scanning, and disk-based detection by hiding code across multiple execution layers and reconstructing it only at runtime. As a result, defenders may have fewer traditional opportunities to detect malicious activity before execution.
A successful infection can lead to credential theft, data exfiltration, and follow-on payload delivery with minimal executable artifacts on disk. The fileless malware can be used to further compromise and achieve ransomware or data theft objectives that can lead to operational downtime, compliance fines and loss of consumer trust.
Top actions:
Hunt for wscript.exe launching conhost.exe --headless powershell.exe with EncodedCommand.
Alert on PowerShell that executes [scriptblock]::Create from process environment variables.
Hunt for random-named environment variables followed by Reflection.Assembly::Load.
Pivot on the stage-1 SHA256 and loader environment-variable names (see Appendices).
Introduction
This write-up follows static de-obfuscation of a Windows Script Host JScript sample delivered in a TAR (Tape Archive file) lure that masqueraded as a purchase order. It focuses on the loader and its obfuscation chain rather than the phishing narrative or the separate network-focused companion report. The final-stage payload (associated with Agent Tesla) is out of scope here and is pending direct .NET assembly recovery.
Threat Landscape
Fileless malware minimizes disk artifacts and forces defenders onto process, memory, script, and telemetry-based detection. This sample fits that trend but adds a distinctive staging method: the payload is spread across hundreds of process environment variables rather than stored in a conventional file or single command-line blob, then reconstructed and reflectively loaded in memory. The loader engineering is the notable finding, because it can plausibly be reused with other payloads.
Hypothesis — obfuscation tooling is maturing, and may now be customized (moderate confidence, not confirmed): The discipline in this sample suggests obfuscation is advancing beyond single-packer commodity crypters toward multi-stage, multi-layer chains, and that the obfuscation may be generated in a tailored rather than off-the-shelf manner. Supporting observations: five independently keyed/encoded layers instead of one packer; nonstandard CJK/Hanzi byte encoding chosen specifically to dodge Base64/hex heuristics; large-scale (364-way) environment-variable fragmentation; and method-name string splitting for AMSI evasion. Taken together these point to deliberate engineering rather than a generic builder run with defaults.
"Customized" can mean two different things, and they carry different defensive implications:
Builder / crypter-as-a-service that auto-generates unique obfuscation per sample — would imply the technique is becoming commoditized and will spread across unrelated actors.
Hand-tailored per campaign or target — would imply a higher-resource actor and more deliberate targeting.
The two can be distinguished by evidence, not assumed. Reuse of the same encoding scheme across unrelated actors points to a shared builder; per-target variation in keys, variable names, and lures tied to one actor points to bespoke work. At this stage we do not have sufficient evidence for how the sample is being used across multiple campaigns and by which threat actors. Until that is established, the customization claim should remain a hypothesis (see Closing Notes for what would confirm or refute it).
Threat Specifics
Origin and intent: Stage and run an in-memory .NET payload while avoiding static signatures and disk-based detection.
Delivery mechanism: First-stage WSH JScript inside a TAR archive, named to resemble a purchase order; decoy code, randomized variable names, and reconstructed strings obscure the real path.
Execution flow: The JScript obtains WScript.Shell.Environment("Process"), populates hundreds of env variables with encoded fragments, decrypts a PowerShell loader into z6ti4ttoCGD1, stores the script path in kYcT4A1u9jXwA, and launches hidden PowerShell via conhost.exe --headless.
Obfuscation Chain At-A-Glance
| Layer | Stage/Location | Technique | Output Handed to Next Layer |
|---|---|---|---|
| 1 | JScript on disk (WSH) | Char-by-char string rebuild, decoy module, random variable names | WScript.Shell.Environment("Process") handle |
| 2 | JScript array v385 | Constant offset (−65) + reversal | Hidden PowerShell launch command |
| 3 | JScript array v382 | 16-byte cyclic key: (byte − key[i mod 16]) & 255 | Base64 PowerShell loader |
| 4 | PowerShell | 364-way env-variable fragmentation + method-name splitting | Reassembled CJK-encoded blob |
| 5 | PowerShell | CJK encoding: byte = codepoint − 0x4E00 | In-memory .NET assembly → EntryPoint.Invoke |
Layer-by-Layer Breakdown
Layer 1 — JScript on disk
Mechanism: real strings rebuilt character-by-character at runtime; decoy event-emitter module and random variable names pad the file.
Purpose: defeat static string scanning and slow manual review.
De-obfuscation: evaluate the rebuild arithmetic to recover strings; treat the decoy module as noise. The real goal is obtaining the process-environment handle.
Detection signal: wscript.exe running a script from an archive, then spawning conhost.exe / powershell.exe.
Layer 2 — Array v385 (launch-command cipher)
Mechanism: reversed offset cipher — constant −65 per byte plus order reversal.
Purpose: hide the actual powershell.exe … -EncodedCommand invocation.
De-obfuscation: reverse the byte order, then add 65 back per byte.
Detection signal: wscript.exe → conhost.exe --headless powershell.exe with w h -NOp -nOnI -EncodedCommand.
Layer 3 — Array v382 (PowerShell-loader cipher)
Mechanism: 16-byte cyclic key applied as (byte − key[i mod 16]) & 255.
Purpose: keep the PowerShell loader out of clear text in the script.
De-obfuscation: add the matching key byte back, modulo 256, per position; result decodes to the Base64 loader staged into an env variable.
Detection signal: loader text stored in env variable z6ti4ttoCGD1; script path in kYcT4A1u9jXwA.
Layer 4 — PowerShell env-variable fragmentation
Mechanism: payload fragmented across 364 env variables and reassembled at runtime; method names split (e.g., ('Lo'+'ad')).
Purpose: AMSI / string-scanning evasion; avoid one large scannable blob.
De-obfuscation: concatenate the 364 fragments in order; rejoin split method names to reveal the real API calls.
Detection signal: a process creating many random-named env variables, then [scriptblock]::Create($env:<name>).
Layer 5 — PowerShell CJK byte encoding
Mechanism: bytes encoded as CJK/Hanzi characters; recovered as byte = codepoint − 0x4E00 (decimal 19968).
Purpose: avoid Base64 and hex heuristics.
De-obfuscation: per character, ([uint16][char]X) − 19968 yields the byte; the byte array is loaded reflectively and its entry point invoked.
Detection signal: decode loop [byte](([uint16][char]X) - 19968); Reflection.Assembly::Load + EntryPoint.Invoke.
Observed TTPs (MITRE ATT&CK): T1027 — Obfuscated/Compressed Files; T1027.013 — Encrypted/Encoded File; T1140 — Deobfuscate/Decode; T1562.001 — AMSI evasion via string splitting; T1620 — Reflective Code Loading; T1059.005 — JScript; T1059.001 — PowerShell.
Impact Assessment
Template guide: operational impact, detection difficulty, and exposure — framed around the obfuscation.
Operational impact: Successful execution runs the .NET assembly without dropping its executable to disk, reducing the value of dropped-file hunting and increasing dependence on script-block, process-chain, environment, and memory telemetry.
Detection difficulty: Hard to catch with static signatures alone — strings are reconstructed at runtime, the loader lives in an env variable, and the payload is distributed across hundreds of CJK-encoded fragments that do not resemble conventional Base64 or hex.
Mitigation Guidance
Template guide: prioritized detection/hunting actions (Immediate / Short term / Ongoing).
Immediate (within 24 hours):
Hunt for wscript.exe launching conhost.exe --headless powershell.exe with w h, NOp, nOnI, EncodedCommand.
Search for PowerShell that calls [scriptblock]::Create($env:<name>) or Reflection.Assembly::Load on byte arrays reconstructed from strings.
Add high-priority detections for env-variable names z6ti4ttoCGD1 and kYcT4A1u9jXwA.
Short term (within one week):
4. Deploy detections for high-volume, random-named process environment variables followed by reflective loading.
5. Search sandbox / telemetry for the CJK decode loop [byte](([uint16][char]X) - 19968) and 364-way env-variable concatenation.
6. Pivot across telemetry for the stage-1 SHA256 (see Appendices).
Ongoing:
7. Monitor variants that reuse the env-variable staging pattern but change keys, variable names, or final payload.
8. Preserve command-line, script-block, AMSI, and PowerShell transcription telemetry — disk artifacts may be absent.
Closing Notes
The core risk in this sample is the loader architecture: a disciplined attempt to hide the executable body across volatile process state, reconstruct it only at runtime, and execute it reflectively in memory. The most impactful actions target loader behavior rather than a single payload hash — process-chain hunting for WSH-to-hidden-PowerShell, alerting on execution from environment variables, and pivoting on the CJK decode loop and env-variable names.
Assessment — advancing and possibly customized obfuscation: The maturation hypothesis (see Threat Landscape) is supported by this sample but not proven. Confirming or refuting it requires: recovering the second-stage .NET assembly and comparing it against known crypter/packer families; searching malware corpora for the distinctive markers (the CJK decode loop, the env-variable naming and 364-way fragmentation pattern); and checking whether the same encoding scheme recurs across unrelated actors (shared builder) or varies per target within one actor (bespoke work). Detections built on the loader behavior hold regardless of which way that resolves which is why we are disclosing this intelligence while FIRE continues to investigate the intentions behind the sophisticated obfuscation.
Immediate next steps and owners:
Endpoint/EDR team: hunt for WSH-to-PowerShell chains and reflective Assembly.Load behavior.
Threat Intel team: pivot on hashes, variable names, CJK decode loop, and delivery URL pattern.
Malware Analysis team: recover and statically analyze the second-stage .NET assembly.
Appendices
Appendix A — Indicators (loader / obfuscation)
Stage-1 JScript SHA256: 3E08E1F04DB3AFBE10BDA13BDE59845A515044FE38AE75DCA164FB54DD440C2A
PowerShell loader env variable: z6ti4ttoCGD1
Script path / argv[0] env variable: kYcT4A1u9jXwA
CJK decode marker: [byte](([uint16][char]X) - 19968)
Execution-from-env-var pattern: [scriptblock]::Create($env:<random>)
Appendix B — De-obfuscation workflow
Recover the first-stage JScript; strip the decoy module / rebuild static strings (Layer 1).
Reverse + offset-shift array v385 to recover the launch command (Layer 2).
Apply the 16-byte cyclic key in reverse to array v382 to recover the Base64 loader (Layer 3).
Concatenate the 364 env-variable fragments and rejoin split method names (Layer 4).
Apply the CJK decode (codepoint − 0x4E00) to obtain the .NET assembly bytes (Layer 5).
Appendix C — Static analysis notes & scope
The decoded PowerShell loader was recovered as temp_ps1.txt during static analysis. Layers 1–3 and the loader behavior in Layers 4–5 are confirmed. A prior speculative WebClient / XOR-URL / Start-Process / self-deletion description was omitted because it is not present in the actual loader; if such behavior exists, it belongs to the loaded .NET assembly and requires direct second-stage analysis. Treat this as a current snapshot pending recovery of that assembly.