b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024letsdiskusscom: b23bb560 — sixteenth confirmed poem-stego sibling, Update_19.js
Executive Summary
Update_19.js is the sixteenth confirmed sibling in the letsdiskusscom Node.js dropper cluster. It encodes four PE payloads and a persistence BAT inside a 256-word English poem via numbered-suffix steganography, stages them to %ProgramData%\Microsoft Edge Updates Helper z624TzPkJS1N, and silently executes a signed Revo Uninstaller component. No C2 — self-contained local payload delivery with registry Run persistence. ^[strings.txt:1]
What It Is
| Field | Value |
|---|---|
| SHA-256 | b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024 |
| Filename | Update_19.js |
| Size | 8,416,260 bytes (8.4 MB) |
| File type | JavaScript source, ASCII text, very long lines (63,365), CRLF terminators ^[file.txt:1] |
| Family | letsdiskusscom (high-confidence cluster sibling) |
| Source | OpenCTI / MalwareBazaar (js label) |
The sample is a Node.js script using fs, path, and child_process modules to drop and execute embedded Windows PE payloads. All payloads are encoded inside the script via custom poem-word-list steganography. ^[strings.txt:1]
How It Works
1. Poem-word-list steganography
The script defines a 256-word lookup table (wlist) — the same English poem fragment observed in all fifteen prior siblings — and five payload strings (exe, dll1, dll2, dll3, bat). Each payload word is looked up in wlist by index; the index value (masked to 0xFF) is written to disk as a byte. ^[strings.txt:6]
Builder variant: numbered suffixes on repeated vocabulary (gentle1, hush2, that3 ... fail164). This poisons frequency analysis without changing lookup semantics. Same template as siblings 3465e6ee, ae2e9acd, 70862e4d, ff3ae2e7, 1fbaf8ab, 26155786, and c485dd9c. ^[strings.txt:6] ^[techniques/poem-word-list-steganography.md]
2. Payload decode and staging
const folder = path.join(process.env.PROGRAMDATA, `Microsoft Edge Updates Helper z624TzPkJS1N`);
const exePath = path.join(folder, "Microsoft Edge Updates Helper.exe");
const autorunPath = path.join(folder, "z624TzPkJS1N.bat");
// ... plus three VC++ runtime DLLs
The script creates the staging directory recursively with mode 0o755, decodes all five payloads via writePositionsToFile, then spawns the BAT (adds registry persistence) followed by the EXE. ^[strings.txt:12]
3. Registry Run persistence via BAT
The decoded BAT adds an HKCU\Software\Microsoft\Windows\CurrentVersion\Run entry named "Microsoft Edge Updates Helper" pointing to the staged EXE. ^[manual decode of bat.bin]
4. Payloads decoded
| Payload | SHA-256 | Size | Description |
|---|---|---|---|
| EXE | 8b94af60...7fc55f |
52,400 B | RevoSrp.exe — VS Revo Group, MSVC 14.44, Authenticode signed (DigiCert). Same hash as all 15 prior siblings. ^[exiftool.json: exe] |
| DLL1 | f5324faf...cb83a2 |
1,006,592 B | msvcp140.dll, Microsoft, MSVC 14.27.29016.0. Sixteenth distinct msvcp140 morph in cluster. Unsigned. ^[rabin2-info: dll1] |
| DLL2 | ff43e813...4c833 |
101,672 B | vcruntime140.dll, Microsoft, MSVC 14.27. Signed. Same hash as all 15 prior siblings. ^[exiftool.json: dll2] |
| DLL3 | 7b8f70dd...6dfc7 |
44,328 B | vcruntime140_1.dll, Microsoft, MSVC 14.27. Signed. Same hash as all 15 prior siblings. ^[exiftool.json: dll3] |
| BAT | dff20059...06919 |
440 B | Registry Run persistence script. Same hash as all 15 prior siblings. ^[manual decode] |
Decoded Script Behavior
Entry point is the top-level block at the bottom of the script:
- Directory creation —
safeMakeDir(folder)withrecursive: trueand mode0o755. ^[strings.txt:27] - Payload reconstruction — Five calls to
writePositionsToFile(wlist, payload, destPath)decode the poem strings back to raw PE/BAT bytes. ^[strings.txt:18] - Execution —
launchExecutablespawns"autorunPath"withshell: trueand passesexePathas an argument, then spawnsexePathdirectly. The BAT adds the registry key and exits; the EXE runs regardless. ^[strings.txt:29] - Error handling — Wrapped in a bare
try/catchthat logs"Installation failed"to stderr and exits with code 1. ^[strings.txt:42]
C2 Infrastructure
None. Self-contained local installer. No network requests, no hardcoded URLs, no DNS, no C2 callbacks. The malicious act is silent staging and execution of a masqueraded signed binary with persistence.
Interesting Tidbits
- Sixteenth distinct msvcp140.dll: The cluster now shows 16 unique msvcp140 morphs. The builder rotates VC++ runtime redistributables between builds while keeping the Revo EXE and vcruntime DLLs constant, likely to evade hash-based detection on the DLL alone. ^[rabin2-info: dll1]
- Filename continues build-counter pattern:
Update_19.jsfalls between siblings26155786(Update_16.js) andff3ae2e7(Update_22.js), suggesting the build counter is active and sequential within campaign waves. ^[metadata.json:5] - MSVC 14.27 timestamp on DLL1:
2020-06-16 03:11:14— same vintage runtime as siblings5126076d,2274d74f,ae2e9acd,70862e4d,ff3ae2e7,1fbaf8ab,26155786, andc485dd9c. The builder draws from a consistent pool of older redistributables. ^[rabin2-info: dll1] - RevoSrp.exe PDB path:
D:\\Work_REVO\\VSRevo\\Windows\\Projects\\Registry Cleaner\\revo-registry-cleaner\\Revo Registry Cleaner\\x64\\Release\\RevoSrp.pdb— same as sibling26155786andc485dd9c, confirming a Registry Cleaner product-line origin rather than Uninstaller Pro. ^[strings.txt: exe_strings.txt] - BAT argument passing: The BAT accepts
"%~1"(the EXE path) as an argument, but the registry key hardcodes the EXE path inside the BAT's own string — the argument is redundant and likely builder template residue. ^[manual decode of bat.bin] - No
javascript-obfuscator: The obfuscation is purely the poem steganography. No self-defend IIFE, no string-array rotator, no dead-code injection. ^[strings.txt:1] - Staging directory suffix entropy:
z624TzPkJS1Nis 12 characters of mixed alphanumeric entropy, consistent with the random-suffix pattern in all siblings (e.g.WG4n5KCoqYf0,iRRSX1DkpmRS). This suggests a runtime or builder-side random generation, not hardcoded per campaign.
How To Mess With It (Homelab Replication)
See poem-word-list-steganography for the full replication recipe. The numbered-suffix variant used here is identical to sibling c485dd9c; add suffixes only on repeated words to poison frequency analysis without changing decode semantics.
Deployable Signatures
YARA rule — letsdiskusscom poem-stego Node.js dropper
rule letsdiskusscom_poem_stego_js
{
meta:
description = "Node.js dropper using 256-word poem steganography to encode PE payloads"
author = "PacketPursuit"
reference = "/intel/analyses/b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024.html"
date = "2026-08-22"
strings:
$require_fs = "const fs = require('fs');"
$require_path = "const path = require('path');"
$require_spawn = "const { spawn } = require('child_process');"
$wlist = "const wlist = \"gentle hush"
$exe = "const exe = \"unwearied"
$dll1 = "const dll1 = \"unwearied"
$func = "function writePositionsToFile(listA, listB, outPath)"
$progdata = "Microsoft Edge Updates Helper"
condition:
filesize > 1MB and filesize < 15MB
and all of ($require_*)
and $func
and $progdata
and any of ($wlist, $exe, $dll1)
}
Sigma rule — Node.js spawning signed EXE from fake Edge Updates Helper directory
title: Node.js spawning signed EXE from fake Edge Updates Helper directory
logsource:
product: windows
category: process_creation
detection:
selection_parent:
ParentImage|endswith: '\\node.exe'
selection_child:
CommandLine|contains:
- 'Microsoft Edge Updates Helper'
- 'z624TzPkJS1N'
selection_registry:
CommandLine|contains:
- 'reg add'
- 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
condition: selection_parent and (selection_child or selection_registry)
falsepositives:
- Unknown
level: high
IOC list
| Indicator | Value | Type |
|---|---|---|
| SHA-256 (carrier) | b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024 |
Hash |
| SHA-256 (embedded EXE) | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
Hash |
| SHA-256 (embedded DLL1) | f5324faf0e84dd1cc97817753d9a27c482a91c53c0740386b42913c89bcb83a2 |
Hash |
| SHA-256 (embedded DLL2) | ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 |
Hash |
| SHA-256 (embedded DLL3) | 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 |
Hash |
| SHA-256 (embedded BAT) | dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
Hash |
| Staging directory | %ProgramData%\Microsoft Edge Updates Helper z624TzPkJS1N |
Path |
| Registry key | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper |
Registry |
| Process tree | node.exe → cmd.exe /c "z624TzPkJS1N.bat" → Microsoft Edge Updates Helper.exe |
Behavior |
Behavioral fingerprint
This Node.js script drops five files to a fake %ProgramData%\Microsoft Edge Updates Helper <random_suffix> directory: one 52 KB signed x64 EXE (RevoSrp.exe), three Microsoft VC++ runtime DLLs (msvcp140.dll, vcruntime140.dll, vcruntime140_1.dll), and one 440-byte BAT script. The BAT adds an HKCU\Run persistence entry, then the EXE is launched via child_process.spawn with shell: true. No network activity. The script body contains extremely long lines (tens of thousands of characters) composed of English poem words with optional numeric suffixes.
Detection Signatures
- capa: N/A — JavaScript source file, not a supported binary class. ^[capa.txt:1]
- MITRE ATT&CK:
- T1059.007 (Command and Scripting Interpreter: JavaScript)
- T1027.002 (Obfuscated Files or Information: Software Packing) — poem-word-list encoding
- T1036.005 (Masquerading: Match Legitimate Name or Location)
- T1547.001 (Boot or Logon Autostart Execution: Registry Run Keys)
- T1543.003 (Create or Modify System Process: Windows Service) — via
child_process.spawn
References
- letsdiskusscom — cluster entity page
- poem-word-list-steganography — technique page
- natural-language-payload-encoding — concept page
- registry-run-persistence — procedure page
- OpenCTI label:
letsdiskuss-com - MalwareBazaar:
b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024
Provenance
- Source file:
wiki/wiki/raw/analyses/b23bb560a20c587c6888813fc06a53d4eac46af78a3813fdeefa6b6667176024/ - Decoded payloads via manual Python script (
/tmp/decode_b23bb560.py) - File type:
file 5.44 - Metadata:
exiftool 12.76 - capa: skipped (JavaScript source, unsupported file class) ^[capa.txt:1]
- CAPE: skipped (JavaScript source, no Windows guest) ^[dynamic-analysis.md:1]
- No radare2 or Ghidra analysis required — behavior is fully recoverable from plaintext JavaScript decode.