2274d74fcc2ad81b9c41c4ca578be6f252a34aaa858020bdaa07eb34e2cd196bletsdiskusscom: 2274d74f — Ninth confirmed sibling, ninth distinct msvcp140.dll morph (MSVC 14.27, Jun 2020), plain 256-word poem steganography
Executive Summary
A 9.3 MB Node.js dropper (Update_11.js) that belongs to the letsdiskusscom cluster. It uses the same 256-word English poem lookup-table steganography seen in siblings d0ca14b3 through ddcb25ee to encode five payloads (one signed Revo EXE, three VC++ runtime DLLs, and one BAT persistence script) by word-to-byte index mapping. This sample carries a ninth distinct msvcp140.dll variant (MSVC 14.27.29016.0, compiled 2020-06-16), confirming the builder operator re-bundles a fresh VC++ runtime with every build rather than reusing a fixed set. The BAT file adds HKCU\Software\Microsoft\Windows\CurrentVersion\Run persistence before launching the staged EXE. No C2; fully self-contained. ^[file.txt] ^[strings.txt:1-45]
What It Is
| Field | Value |
|---|---|
| SHA-256 | 2274d74fcc2ad81b9c41c4ca578be6f252a34aaa858020bdaa07eb34e2cd196b |
| Filename (ingestion) | Update_11.js |
| File type | JavaScript source, ASCII text, 60 lines, 63,365-char lines, CRLF ^[file.txt] |
| Size | 9,283,780 bytes (9.3 MB) ^[exiftool.json] |
| Family | letsdiskusscom (high confidence, ninth confirmed sibling) |
| Build | Node.js JavaScript, raw .js delivery |
| Obfuscation | None at JS level; payload concealment via 256-word English poem lookup-table steganography |
| CAPE status | skipped — JavaScript source is not a supported binary class ^[dynamic-analysis.md] |
How It Works
-
Poem-word-list steganography. A 256-word English poem is defined as
wlist. Five payload strings (exe,dll1,dll2,dll3,bat) are each encoded as sequences of poem words. At runtime,writePositionsToFile()maps each word back to its index inwlist, masks to& 0xFF, and writes the resulting byte stream to disk. ^[strings.txt:6-45] -
Staging directory.
folder = path.join(process.env.PROGRAMDATA, "Microsoft Edge Updates Helper GQYJq5Av3lIJ"). The random suffixGQYJq5Av3lIJvaries per sample (e.g.,hvdyNBO34tkN,xp7v5lqfYx3tin prior siblings). ^[strings.txt:5] -
Payloads dropped. Five files written:
Microsoft Edge Updates Helper.exe— signed RevoSrp.exe (DigiCert, VS REVO GROUP OOD)msvcp140.dll— MSVC 14.27.29016.0, 2020-06-16 timestamp (ninth distinct morph)vcruntime140.dll— identical to all prior siblingsvcruntime140_1.dll— identical to all prior siblingsGQYJq5Av3lIJ.bat— registry persistence + launcher ^[strings.txt:12-17]
-
Persistence. The BAT script calls
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "Microsoft Edge Updates Helper" /t REG_SZ /d "\"%~1\"" /fbefore launching the EXE. ^[strings.txt:40-45] -
Execution. The Node.js script spawns the BAT via
child_process.spawn(..., { shell: true, stdio: 'inherit' }), which in turn launches the EXE. ^[strings.txt:29-41]
Decompiled Behavior
Not applicable — source is plaintext JavaScript, not a compiled PE. The full logic is visible in strings.txt. No javascript-obfuscator IIFE or control-flow flattening is present; the obfuscation layer is entirely the poem-word-list payload encoding.
C2 Infrastructure
None. The sample is fully self-contained with no network IAT, no hardcoded URLs, and no callback. The malicious act is silent local payload staging + execution + registry persistence.
Interesting Tidbits
- Ninth distinct
msvcp140.dllmorph: SHA-2565bce8c8b7a80030599367853da4c82f85dd59f11634ea249e467d033638609d0, compiled 2020-06-16, MSVC 14.27.29016.0. Prior siblings carried eight other distinct hashes. This confirms the builder re-packages a new VC++ runtime with every build rather than reusing a cached set. - Plain poem, no numbered suffixes: Unlike sibling
3465e6eewhich introducedgentle1,hush2, etc., this sample reverts to the plain 256-word vocabulary. The builder oscillates between plain and numbered-suffix templates. - RevoSrp.exe payload: The staged EXE is a signed Revo Registry Cleaner component (
RevoSrp.exe, VS REVO GROUP OOD, DigiCert). Its presence is not inherently malicious — the threat is the deceptive delivery mechanism. - DLL name masquerade: The three dropped DLLs are legitimate Microsoft VC++ runtime DLLs, lending credibility to the staging directory.
- No
detached: true: Thespawncall usesshell: true, stdio: 'inherit'but notdetached, meaning the Node.js parent will block until the child exits (or at least inherit stdio).
How To Mess With It (Homelab Replication)
Goal: Reproduce the poem-word-list steganography dropper in Node.js.
Toolchain: Node.js 18+ (LTS), any text editor.
Steps:
- Choose a 256-word English vocabulary (a poem, prose passage, or random word list). Map each word to index
0..255. - Encode a binary payload by replacing every byte with its corresponding word. For byte
0x00, use word at index 0; for0xFF, use word at index 255. - In Node.js, read the word list and payload word string. Split both on spaces. For each payload word, find its index in the vocabulary list, mask to
& 0xFF, and write to aBuffer. - Write the buffer to
%ProgramData%\Microsoft Edge Updates Helper <random_suffix>\<filename>. - Optionally wrap in a BAT file that adds a
HKCU\Runregistry entry before executing the payload.
Verification: Compare your output byte stream to the original payload via sha256sum. The decoded bytes should match bit-for-bit.
What you'll learn: How natural-language steganography defeats naive string-extraction tools (the payload is invisible to strings until decoded) and why YARA rules targeting the poem vocabulary are effective detection.
Deployable Signatures
YARA Rule
rule letsdiskusscom_poem_stego_dropper
{
meta:
description = "Node.js dropper using 256-word English poem lookup-table steganography"
author = "PacketPursuit"
family = "letsdiskusscom"
reference = "/intel/analyses/2274d74fcc2ad81b9c41c4ca578be6f252a34aaa858020bdaa07eb34e2cd196b.html"
strings:
$wlist_start = "const wlist = \"gentle hush that wraps the midnight air"
$wlist_end = "unwearied humble code"
$func_write = "function writePositionsToFile(listA, listB, outPath)"
$spawn_shell = "spawn(execPath, args, { shell: true"
$progdata = "Microsoft Edge Updates Helper"
$reg_add = "reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\""
condition:
filesize > 5MB and
$wlist_start and
$wlist_end and
$func_write and
$progdata and
any of ($spawn_shell, $reg_add)
}
Sigma Rule
title: Letsdiskusscom Node.js Dropper Execution
status: experimental
description: Detects Node.js spawning a batch file from a Microsoft Edge Updates Helper directory under ProgramData, indicative of letsdiskusscom poem-stego dropper execution.
logsource:
category: process_creation
product: windows
detection:
selection:
ParentImage|endswith: '\node.exe'
CommandLine|contains:
- 'Microsoft Edge Updates Helper'
- 'ProgramData'
- '.bat'
condition: selection
falsepositives:
- Unlikely — the directory name is attacker-controlled and non-standard.
level: high
tags:
- attack.execution
- attack.t1059.007
- attack.persistence
- attack.t1547.001
IOC List
| Indicator | Type | Value |
|---|---|---|
| Carrier SHA-256 | hash | 2274d74fcc2ad81b9c41c4ca578be6f252a34aaa858020bdaa07eb34e2cd196b |
| Staged EXE SHA-256 | hash | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f (RevoSrp.exe) |
| Staged DLL1 SHA-256 | hash | 5bce8c8b7a80030599367853da4c82f85dd59f11634ea249e467d033638609d0 (msvcp140.dll, MSVC 14.27) |
| Staged DLL2 SHA-256 | hash | ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 (vcruntime140.dll) |
| Staged DLL3 SHA-256 | hash | 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 (vcruntime140_1.dll) |
| Staging directory | path | %ProgramData%\Microsoft Edge Updates Helper* |
| Registry persistence | registry | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper |
| Process tree | behavior | node.exe → cmd.exe /c *.bat → RevoSrp.exe |
| Poem vocabulary | string | 256-word English poem beginning with gentle hush that wraps the midnight air... |
Behavioral Fingerprint Statement
This JavaScript dropper writes five files to a %ProgramData% subdirectory named Microsoft Edge Updates Helper <random_suffix>: a signed Revo EXE, three VC++ runtime DLLs (msvcp140.dll, vcruntime140.dll, vcruntime140_1.dll), and a BAT file that adds an HKCU\Run registry entry before executing the EXE. The payload bytes are encoded inside the JS source as sequences of words from a 256-word English poem, decoded at runtime by word-to-index mapping. The Node.js parent spawns the BAT via child_process.spawn with shell: true. No network C2 is present. Detection should focus on the anomalous node.exe → .bat → .exe chain under %ProgramData% and the distinctive poem vocabulary strings in the JS source.
Detection Signatures
| ATT&CK | Technique | Evidence |
|---|---|---|
| T1059.007 | JavaScript | Node.js require('fs'), require('child_process') ^[strings.txt:1-3] |
| T1027.002 | Obfuscated Files or Info | 256-word poem lookup-table steganography hides PE payloads as natural-language word sequences ^[strings.txt:6-11] |
| T1036.005 | Masquerading | Microsoft Edge Updates Helper directory name and signed Revo EXE masquerade ^[strings.txt:4-5] |
| T1547.001 | Registry Run Keys | BAT calls reg add HKCU\...\Run with value Microsoft Edge Updates Helper ^[strings.txt:40-45] |
| T1543.003 | Create/modify system process | child_process.spawn(..., { shell: true, stdio: 'inherit' }) ^[strings.txt:29-41] |
References
- letsdiskusscom — Cluster entity page (eight prior siblings documented) ^[entities/letsdiskusscom.md]
- poem-word-list-steganography — Technique page for the 256-word poem encoding ^[techniques/poem-word-list-steganography.md]
- natural-language-payload-encoding — Concept page for prose-based payload hiding ^[concepts/natural-language-payload-encoding.md]
- registry-run-persistence — Procedure page for BAT-based Run key technique ^[procedures/registry-run-persistence.md]
- Sibling
d0ca14b3— First poem-stego variant with BAT persistence - Sibling
ddcb25ee— Eighth sibling, plain poem, MSVC 14.40 msvcp140.dll
Provenance
file.txt— file(1) output,filev5.45exiftool.json— ExifTool 12.76 metadatastrings.txt— strings(1) output, GNU strings 2.42dynamic-analysis.md— CAPE sandbox status (skipped)ssdeep.txt— ssdeep 2.14.1tlsh.txt— TLSH 4.12.0- Payload SHA-256s computed via Python 3.11 hashlib after custom poem-word-list decoder reimplementation