4c57911f992d2760d089820ec5a73be433aa4f91a656f241b7fc980c98b0ba8eletsdiskusscom: 4c57911f992d — Update_15.js, twentieth confirmed sibling
Executive Summary
Twentieth confirmed sibling of the letsdiskusscom Node.js poem-steganography dropper cluster. Filename Update_15.js continues the active build-counter pattern. Numbered-suffix poem vocabulary (gentle1, hush2, etc.) persists. Same signed Revo EXE and two vcruntime DLLs as all nineteen prior siblings; introduces a twentieth distinct msvcp140.dll morph (907,776 bytes). Static-only (CAPE skipped — JS source not a supported binary class).
What It Is
- Filename:
Update_15.js^[metadata.json] - Size: 7,699,519 bytes (7.7 MB) ^[file.txt]
- Format: JavaScript source, ASCII text, CRLF line terminators, 60 lines with extremely long lines (up to ~63,365 chars) ^[file.txt] ^[exiftool.json]
- Family:
letsdiskusscom— high-confidence cluster sibling ^[entities/letsdiskusscom.md] - Staging directory:
%ProgramData%\Microsoft Edge Updates Helper tge9KnkgpkOY^[decoded from JS source]
How It Works
The carrier is a Node.js script that decodes five embedded payloads from a 256-word English poem lookup-table using numbered-suffix vocabulary obfuscation. See poem-word-list-steganography for the full technique breakdown.
Decoding function (lines 23-33):
function writePositionsToFile(listA, listB, outPath) {
const a = listA.split(' ');
const b = listB.split(' ');
const positions = b.map(word => {
const idx = a.indexOf(word);
return idx >= 0 ? idx : 0;
});
const buffer = Buffer.from(positions.map(p => p & 0xFF));
fs.writeFileSync(outPath, buffer);
}
Word list: 256 words, 256 unique. Numbered suffixes (gentle1 through fail164) appended after the first complete poem cycle to defeat naive deduplication. ^[decoded from JS source]
Decoded payloads
| File | Size | SHA-256 | Notes |
|---|---|---|---|
Microsoft Edge Updates Helper.exe |
52,400 B | 8b94af60... |
Same signed Revo EXE as all 19 prior siblings |
msvcp140.dll |
907,776 B | c8f39899... |
Twentieth distinct morph — new to cluster |
vcruntime140.dll |
101,672 B | ff43e813... |
Same as all prior siblings |
vcruntime140_1.dll |
44,328 B | 7b8f70dd... |
Same as all prior siblings |
tge9KnkgpkOY.bat |
440 B | dff20059... |
Same BAT as all prior siblings |
The BAT writes HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper pointing to the staged EXE, then launches it. ^[decoded BAT payload]
C2 Infrastructure
None observed. Self-contained local installer. No network IOCs in carrier script or decoded payloads. The malicious act is deceptive delivery + silent execution + registry persistence.
Interesting Tidbits
- Build-counter continuity:
Update_15.jssits betweenUpdate_14.js(a27bda89) andUpdate_16.js(26155786) in the filename sequence, confirming an active build counter rather than random naming. ^[entities/letsdiskusscom.md] - msvcp140.dll morph #20: 907,776 bytes, SHA-256
c8f39899.... Not observed in any prior sibling. The builder actively rotates this DLL while keeping the core Revo EXE and vcruntime pair constant — likely to evade hash-based detection on the runtime dependency rather than the payload. ^[decoded payload hashes] - Identical BAT hash:
dff20059...— same 440-byte batch script across all twenty siblings, confirming a single BAT template shared by the builder. ^[decoded payload hashes] - No
javascript-obfuscator: This sibling uses the custom poem-stego encoding, not the commercial JS obfuscator seen in the first sibling (9dc2cded). The poem template has completely replaced the obfuscator template in recent builds. ^[entities/letsdiskusscom.md]
How To Mess With It (Homelab Replication)
- Encode a payload with poem steganography:
with open('words.txt') as f: words = f.read().split() assert len(words) == 256 with open('payload.exe', 'rb') as f: data = f.read() encoded = ' '.join(words[b] for b in data) - Add numbered suffixes (optional): After the first 256-word cycle, append
1,2, etc. to repeated words. - Wrap in Node.js carrier: Use the
writePositionsToFilepattern from this sample, stage to%ProgramData%, spawn viachild_process.spawn. - Verify: Decode your own carrier back to the original payload; compare SHA-256.
Deployable Signatures
YARA rule
rule letsdiskusscom_poem_stego_dropper {
meta:
description = "Node.js poem-word-list steganography dropper (letsdiskusscom cluster)"
author = "PacketPursuit"
date = "2026-08-23"
hash = "4c57911f992d2760d089820ec5a73be433aa4f91a656f241b7fc980c98b0ba8e"
strings:
$node_fs = "const fs = require('fs');"
$node_path = "const path = require('path');"
$node_spawn = "const { spawn } = require('child_process');"
$app_name = "Microsoft Edge Updates Helper"
$wlist = "const wlist ="
$func = "function writePositionsToFile(listA, listB, outPath)"
$poem_start = "gentle hush that wraps the midnight air"
$bat_ext = ".bat"
$dll1 = "msvcp140.dll"
$dll2 = "vcruntime140.dll"
condition:
filesize > 1MB and
all of ($node_*) and
$app_name and
$wlist and
$func and
$poem_start and
$bat_ext and
$dll1 and
$dll2
}
Behavioral hunt query (Sigma-like)
title: letsdiskusscom Node.js dropper execution
detection:
selection:
- Image|endswith: 'node.exe'
- CommandLine|contains:
- 'Microsoft Edge Updates Helper'
- 'Update_'
- '.js'
selection_file_write:
- TargetFilename|contains: 'Microsoft Edge Updates Helper'
- TargetFilename|endswith: '.exe'
selection_spawn:
- ParentImage|endswith: 'node.exe'
- Image|endswith:
- 'cmd.exe'
- 'conhost.exe'
condition: selection and selection_file_write and selection_spawn
IOC list
| Type | Value | Context |
|---|---|---|
| Filename | Update_15.js |
Carrier script |
| Staging dir | %ProgramData%\Microsoft Edge Updates Helper tge9KnkgpkOY |
Payload drop location |
| Registry key | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper |
Persistence |
| EXE SHA-256 | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
Signed Revo payload |
| DLL SHA-256 | c8f3989934455b62a700cdb450b24b476305c3e747282ac905c1e9c49ecd7678 |
msvcp140.dll morph #20 |
| DLL SHA-256 | ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 |
vcruntime140.dll |
| DLL SHA-256 | 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 |
vcruntime140_1.dll |
| BAT SHA-256 | dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
Registry persistence script |
Behavioral fingerprint
This Node.js script requires fs, path, and child_process, defines a 256-word English poem vocabulary with optional numbered suffixes, and uses writePositionsToFile to decode four PE files and one BAT script by word-index lookup. It stages payloads to a %ProgramData% subdirectory named Microsoft Edge Updates Helper <random_suffix>, writes an HKCU Run registry entry via the BAT, and silently executes the dropped EXE. No C2 traffic is generated by the carrier.
Detection Signatures
| Capability | ATT&CK |
|---|---|
| JavaScript execution | T1059.007 |
| Obfuscated Files or Info (poem steganography) | T1027.002 |
| Masquerading (browser update helper) | T1036.005 |
| Registry Run Keys | T1547.001 |
| Create/modify system process | T1543.003 |
References
- letsdiskusscom — Cluster entity page
- poem-word-list-steganography — Technique deep-dive
- registry-run-persistence — Procedure page for BAT-based Run key
- natural-language-payload-encoding — Broader concept
Provenance
file.txt—fileutility (file type: JavaScript source, ASCII text)exiftool.json— ExifTool 12.76 (7.7 MB, 60 lines, 1,107,076 words)triage.json— triage-fast pipeline (tier: deep, no family attribution)dynamic-analysis.md— CAPE skipped (JS source not supported)capa.txt— capa errored (unsupported file format)floss.txt— floss errored (invalid CLI args)binwalk.txt— binwalk (no embedded artifacts detected)rabin2-info.txt— radare2 (not a PE, 7.7 MB plain text)- Decoded payloads verified via Python3 script (SHA-256 computed with hashlib)
- Source JS decoded manually by extracting
constdeclarations and running the embeddedwritePositionsToFilelogic