a27bda8928aaf0601341d9121c429a501a74260dd37c89754c2bb4288fda572aletsdiskusscom: a27bda89 — Update_14.js, seventeenth confirmed sibling
Executive Summary
Seventeenth confirmed sibling in the letsdiskusscom Node.js poem-word-list dropper cluster. The carrier script Update_14.js (10.1 MB) uses numbered-suffix poem steganography to decode five embedded payloads — a signed Revo EXE, three Microsoft VC++ runtime DLLs, and a BAT persistence launcher — to a fake Microsoft Edge Updates Helper directory under %ProgramData%. Same EXE, vcruntime140.dll, vcruntime140_1.dll, and BAT hash as all 16 prior poem-stego siblings. The msvcp140.dll is a new morph (SHA-256 012212f9..., 1,248,256 bytes, MSVC 14.27.29016.0), bringing the cluster's distinct msvcp140 morph count to seventeen. Static-only analysis; CAPE skipped because the sample is plain JavaScript source.
What It Is
- Filename:
Update_14.js^[metadata.json] - File type: JavaScript source, ASCII text, very long lines (63,365 chars), CRLF terminators ^[file.txt]
- Size: 10,142,852 bytes (10.1 MB) ^[exiftool.json]
- SHA-256:
a27bda8928aaf0601341d9121c429a501a74260dd37c89754c2bb4288fda572a - Family:
letsdiskusscom(high confidence, cluster sibling #17) - OpenCTI labels:
js,malware-bazaar^[metadata.json]
How It Works
The script is a self-contained Node.js installer with no external network dependencies. It uses the same 256-word English poem lookup-table steganography observed across all poem-stego siblings, with numbered suffixes on repeated vocabulary words (gentle1, hush2, wraps3, etc.) to defeat simple word-frequency deduplication. ^[strings.txt:6]
Execution flow:
- Decode payloads via
writePositionsToFile(wlist, <payload>, outPath)— each payload string is a sequence of poem words; the decoder maps each word to its zero-based index inwlist, producing a byte array. ^[strings.txt:18-25] - Stage to disk at
%ProgramData%\Microsoft Edge Updates Helper 9yyM0KCwtOI5\:Microsoft Edge Updates Helper.exe— signed Revo EXE (52,400 bytes)msvcp140.dll— MSVC 14.27.29016.0 (1,248,256 bytes)vcruntime140.dll— MSVC runtime (101,672 bytes)vcruntime140_1.dll— MSVC runtime (44,328 bytes)9yyM0KCwtOI5.bat— registry persistence launcher (440 bytes)
- Launch the BAT with the EXE path as argument, then launch the EXE directly. ^[strings.txt:39-41]
A minor builder artifact is present: dll4Path is assigned to the same BAT path as autorunPath, suggesting copy-paste drift in the builder template. ^[strings.txt:17]
Decompiled Behavior
Not applicable — this is plain JavaScript source, not a compiled PE. No Ghidra or radare2 analysis required. The entire logic is readable from strings.txt (which is the source file itself, as file confirms it is ASCII text with no binary overlay). ^[file.txt]
C2 Infrastructure
None. The carrier is entirely self-contained. No network URLs, no download cradles, no hardcoded IPs or domains. The malicious act is the silent staging and execution of a signed third-party binary under a deceptive directory name. Any actual C2 would live inside the dropped EXE, which has not been independently detonated or reverse-engineered in this corpus.
Interesting Tidbits
- Build counter continues: filename
Update_14.jsresumes theUpdate_N.jspattern after the plainUpdate.jswave (siblingc485dd9c). The builder appears to maintain an internal counter. ^[metadata.json] - Seventeenth msvcp140 morph: prior siblings cycled through sixteen distinct
msvcp140.dllbuilds. This sample adds a seventeenth (SHA-256012212f9..., 1,248,256 bytes, compiled 2020-06-16). All are legitimate Microsoft VC++ runtime DLLs; the morph rotation likely serves as a trivial sandbox/AV evasion tactic (rotate file hashes to avoid hash-based detection on the DLL). ^[strings.txt:14] - Payload hash stability: EXE, DLL2, DLL3, and BAT hashes match all 16 prior poem-stego siblings exactly. The builder reuses the signed Revo EXE and two vcruntime DLLs across every build, only swapping
msvcp140.dll. ^[strings.txt:12-17] - Staging suffix entropy:
9yyM0KCwtOI5— 12-character alphanumeric random suffix, consistent with the cluster's per-build unique directory naming. ^[strings.txt:5] - BAT content unchanged: identical HKCU Run registry persistence script as all prior siblings. ^[strings.txt:11]
How To Mess With It (Homelab Replication)
- Encode any binary as a poem-word sequence:
- Build a 256-word vocabulary list (English poem prose works well).
- For each byte
bof your payload, emitvocab[b]. - Number repeated words (
word1,word2) to bloat file size and evade frequency analysis.
- Wrap in Node.js using the
writePositionsToFilepattern from this sample. - Stage and execute via
fs.writeFileSync+child_process.spawnwithshell: true. - Verification: your output JS should be ~10 MB for ~50 KB of embedded PE payload (200× bloat factor due to word encoding). Run
node yourfile.json a Windows VM with Node.js installed.
Deployable Signatures
YARA rule — letsdiskusscom poem-stego dropper
rule letsdiskusscom_poem_stego_dropper {
meta:
description = "Node.js poem-word-list steganography dropper (letsdiskusscom cluster)"
author = "PacketPursuit"
date = "2026-08-23"
reference = "/intel/analyses/a27bda8928aaf0601341d9121c429a501a74260dd37c89754c2bb4288fda572a.html"
strings:
$wlist = "const wlist = \"gentle" ascii wide
$app_name = "Microsoft Edge Updates Helper" ascii wide
$func1 = "writePositionsToFile" ascii wide
$func2 = "safeMakeDir" ascii wide
$func3 = "launchExecutable" ascii wide
$spawn = "require('child_process')" ascii wide
$programdata = "process.env.PROGRAMDATA" ascii wide
condition:
filesize > 1MB and
$wlist and $app_name and $func1 and $func2 and $func3 and $spawn and $programdata
}
Sigma rule — Node.js poem dropper execution
title: Node.js Poem-Stego Dropper Execution
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains:
- 'Update_'
- '.js'
ParentImage|endswith:
- '\node.exe'
CommandLine|contains:
- 'Microsoft Edge Updates Helper'
condition: selection
falsepositives:
- Unlikely; the directory name and filename pattern are attacker-controlled.
level: high
IOC list
| Artifact | Value | Notes |
|---|---|---|
| JS filename pattern | Update_*.js or Update.js |
Build counter or plain wave |
| Staging directory | %ProgramData%\Microsoft Edge Updates Helper <12-char suffix>\ |
Random alphanumeric suffix |
| Dropped EXE | Microsoft Edge Updates Helper.exe |
Signed Revo component (SHA-256 8b94af60...) |
| Dropped DLL1 | msvcp140.dll |
Rotates per build (17 distinct morphs observed) |
| Dropped DLL2 | vcruntime140.dll |
Stable across cluster (SHA-256 ff43e813...) |
| Dropped DLL3 | vcruntime140_1.dll |
Stable across cluster (SHA-256 7b8f70dd...) |
| Dropped BAT | *.bat |
HKCU Run persistence (SHA-256 dff20059...) |
| Registry key | HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
Value name Microsoft Edge Updates Helper |
Behavioral fingerprint
This sample is a Node.js script that, when executed via node.exe, creates a subdirectory under %ProgramData% named Microsoft Edge Updates Helper <random12>, writes five files to it (EXE + three DLLs + BAT), then spawns the BAT file and the EXE via child_process.spawn with shell: true. No network activity from the carrier. The BAT sets an HKCU Run key pointing to the EXE. All payloads are decoded at runtime from a 256-word English poem lookup-table with numbered suffix obfuscation.
Detection Signatures
| Capability | ATT&CK Technique | Evidence |
|---|---|---|
| JavaScript execution | T1059.007 | require('child_process'), spawn(..., {shell: true}) ^[strings.txt:3,30] |
| Obfuscated payload encoding | T1027.002 | 256-word poem lookup-table with numbered suffixes ^[strings.txt:6] |
| Masquerading | T1036.005 | Microsoft Edge Updates Helper directory and filename ^[strings.txt:4,12] |
| Registry Run persistence | T1547.001 | BAT writes HKCU\...\Run with reg add ^[strings.txt:11] |
| Create system process | T1543.003 | child_process.spawn with shell: true ^[strings.txt:30] |
References
letsdiskusscomentity page:entities/letsdiskusscom.mdpoem-word-list-steganographytechnique page:techniques/poem-word-list-steganography.mdregistry-run-persistenceprocedure page:procedures/registry-run-persistence.md- Sibling
b23bb560(16th sibling,Update_19.js):/intel/analyses/b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024.html
Provenance
Analysis derived from strings.txt (the JS source itself, as file.txt confirms plain ASCII text), metadata.json, exiftool.json, file.txt, and manual decoding of the poem-word payloads. No dynamic execution performed; CAPE skipped because the sample is JavaScript source, not a supported binary class. Tool versions: file 5.44, exiftool 12.76.