adc5a0b48efb808930acadd51091509e481512446aac030a367d4577be861eb2letsdiskusscom: adc5a0b48efb — Update_23.js, 25th confirmed sibling, 25th distinct msvcp140.dll morph
Executive Summary
Twenty-fifth confirmed sibling in the letsdiskusscom Node.js poem-word-list dropper cluster (Update_23.js, 7.8 MB). Uses the active numbered-suffix steganography template (gentle1, hush2, etc.) to encode four PE files and one BAT script inside a 256-word English poem. Embeds the same signed Revo EXE and both vcruntime DLLs as all twenty-four prior siblings, confirming payload reuse, but swaps msvcp140.dll for a twenty-fifth distinct morph (915,968 bytes, MSVC 14.27.29016.0). Staging directory suffix is P0fUY3DjdXfI. No C2, no network — self-contained local installer with BAT-based HKCU Run persistence. Static-only (CAPE skipped — JS source unsupported).
What It Is
| Field | Value |
|---|---|
| SHA-256 | adc5a0b48efb808930acadd51091509e481512446aac030a367d4577be861eb2 |
| Filename | Update_23.js |
| Size | 7,761,938 bytes (7.8 MB) |
| Type | JavaScript source, ASCII, CRLF line terminators, 60 lines, very long lines (63,365 chars) ^[file.txt] |
| OpenCTI labels | js, malware-bazaar ^[triage.json] |
| Family | letsdiskusscom (high-confidence cluster sibling) |
| Tier | deep |
How It Works
The carrier is a Node.js script that relies on the victim having node.exe available (or being bundled with a portable runtime). It defines five payload strings encoded via a 256-word English poem lookup table with numbered suffixes on repeated vocabulary words (e.g. gentle1, hush2). At runtime, the writePositionsToFile function splits the poem into an array, looks up each payload word to recover its byte index, and writes the resulting bytes to disk. ^[strings.txt:0-59]
Decoded payloads (all five written to %ProgramData%\Microsoft Edge Updates Helper P0fUY3DjdXfI\):
| File | SHA-256 | Size | Notes |
|---|---|---|---|
Microsoft Edge Updates Helper.exe |
8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
52,400 | Same as all 24 prior siblings. Signed RevoSrp.exe (VS Revo Group, DigiCert), MSVC 14.44, compiled 2025-06-02. ^[exiftool.json] |
msvcp140.dll |
fa77a57e508320f005266cd8d28efb61dd36de3a019e8fcf940045c322a13c1a |
915,968 | 25th distinct morph in cluster. MSVC 14.27.29016.0, compiled 2020-06-16. Microsoft-signed (certificate parse warning in rabin2). ^[exiftool.json] |
vcruntime140.dll |
ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 |
101,672 | Same as all prior siblings. Microsoft-signed. ^[exiftool.json] |
vcruntime140_1.dll |
7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 |
44,328 | Same as all prior siblings. Microsoft-signed. ^[exiftool.json] |
P0fUY3DjdXfI.bat |
dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
440 | Same as all prior siblings. Writes HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper. ^[strings.txt] |
After dropping the files, the script spawns the BAT with the EXE path as an argument, then spawns the EXE directly via child_process.spawn(..., { shell: true }). ^[strings.txt:54-55]
Template artifact preserved: const dll4Path = path.join(folder, "P0fUY3DjdXfI.bat") is declared on line 21 but never used — the BAT is written via writePositionsToFile(wlist, bat, autorunPath) instead. This dead-variable artifact has been present in every numbered-suffix sibling since the template was introduced. ^[strings.txt:21]
Decompiled Behavior
Not applicable — the sample is a JavaScript source file, not a compiled PE. No Ghidra or radare2 decompilation possible. The entire logic is plaintext Node.js. ^[file.txt]
C2 Infrastructure
None. The dropper is entirely self-contained; no network calls, no download URLs, no callback domains. The malicious act is the deceptive delivery and silent execution of the signed Revo EXE inside a masquerade directory. ^[strings.txt]
Interesting Tidbits
- Build-counter continuity:
Update_23.jsfills the gap betweenUpdate_22.js(siblingff3ae2e72f50) andUpdate_25.js(sibling1fbaf8ab9f90), confirming the internal build numbering is sequential and this template is actively maintained. ^[strings.txt:4] - No payload evolution: Twenty-five builds, zero change to the embedded EXE, DLL2, DLL3, or BAT hashes. The only rotated component is
msvcp140.dll. This suggests the builder is a kit where the operator swaps in a fresh VC++ runtime DLL per build while the core payload (RevoSrp.exe) remains static. ^[exiftool.json] - Certificate on EXE: DigiCert-signed, valid at time of compilation (Jun 2025). The signature is legitimate — the threat is not the EXE itself but the deceptive delivery mechanism and the registry persistence it installs. ^[exiftool.json]
- DLL1 certificate parsing issue:
rabin2 -Ireportssigned: falsewith a warning "Invalid certificate entry" for the msvcp140.dll, yet pefile confirms a non-zero cert directory size. This is likely a rabin2 parsing quirk on Microsoft Authenticode with nested SPC certificates; the DLL is genuine Microsoft VC++ runtime 14.27. ^[exiftool.json]
How To Mess With It (Homelab Replication)
- Reproduce the encoder:
with open('words.txt') as f: words = f.read().split() # 256 words with open('payload.exe', 'rb') as f: data = f.read() encoded = ' '.join(words[b] for b in data) - Wrap in Node.js carrier using the
writePositionsToFilepattern from anyletsdiskusscomsibling. - Verify: Decode the JS back to the original PE and compare SHA-256.
- Observe: The resulting
.jswill be ~15× the size of the payload (poem words are longer than raw bytes) and will have very low Shannon entropy despite large file size — a strong anti-static signal that is ironically easy to detect.
Deployable Signatures
YARA — JS poem-stego dropper (numbered-suffix variant)
rule letsdiskusscom_js_poem_stego_numbered_suffix : script dropper {
meta:
description = "Node.js poem-word-list steganography dropper with numbered suffixes (letsdiskusscom cluster)"
author = "PacketPursuit"
date = "2026-08-24"
sha256 = "adc5a0b48efb808930acadd51091509e481512446aac030a367d4577be861eb2"
family = "letsdiskusscom"
strings:
$node1 = "const fs = require('fs');"
$node2 = "const path = require('path');"
$node3 = "const { spawn } = require('child_process');"
$func = /function writePositionsToFile\(listA, listB, outPath\)/
$wlist = "const wlist ="
$exe = "const exe ="
$bat = "const bat ="
$app_name = "Microsoft Edge Updates Helper"
$numbered = /gentle\d+ hush\d+/ // numbered-suffix template fingerprint
condition:
filesize > 1MB and filesize < 15MB
and all of ($node*)
and $func
and $wlist
and $exe
and $bat
and $app_name
and $numbered
}
Sigma — BAT-based HKCU Run persistence
title: letsdiskusscom BAT Registry Run Persistence
logsource:
category: process_creation
product: windows
detection:
selection:
CommandLine|contains|all:
- 'reg add'
- 'HKCU\Software\Microsoft\Windows\CurrentVersion\Run'
- 'Microsoft Edge Updates Helper'
condition: selection
falsepositives:
- Unknown
level: high
tags:
- attack.persistence
- attack.t1547.001
IOC list
| Indicator | Type | Value | Note |
|---|---|---|---|
| Carrier SHA-256 | hash | adc5a0b48efb808930acadd51091509e481512446aac030a367d4577be861eb2 |
Update_23.js |
| Embedded EXE SHA-256 | hash | 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f |
RevoSrp.exe (same across all siblings) |
| Embedded BAT SHA-256 | hash | dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 |
Same across all siblings |
| Staging directory | path | %ProgramData%\Microsoft Edge Updates Helper P0fUY3DjdXfI\ |
This sample's suffix |
| Registry value | reg | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper |
BAT persistence |
| Embedded DLL2 SHA-256 | hash | ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 |
vcruntime140.dll |
| Embedded DLL3 SHA-256 | hash | 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 |
vcruntime140_1.dll |
Behavioral fingerprint
This Node.js script writes four PE files and one BAT file to a %ProgramData% subdirectory named Microsoft Edge Updates Helper <random_suffix>\, then immediately spawns the BAT (passing the EXE path as an argument) followed by spawning the EXE directly via child_process.spawn with shell: true. The BAT adds an HKCU Run key pointing to the EXE. No network traffic is generated by the carrier. The script is 7–11 MB, contains 60 lines with lines exceeding 60,000 characters, and encodes payloads as space-separated English poem words with numbered suffixes.
Detection Signatures
| ATT&CK | Technique | Evidence |
|---|---|---|
| T1059.007 | Command and Scripting Interpreter: JavaScript | Node.js require('fs'), require('child_process') ^[strings.txt] |
| T1027.002 | Obfuscated Files or Information | 256-word poem lookup-table with numbered-suffix encoding ^[strings.txt] |
| T1036.005 | Masquerading | Microsoft Edge Updates Helper directory name ^[strings.txt] |
| T1547.001 | Boot or Logon Autostart Execution: Registry Run Keys | BAT calls reg add HKCU\...\Run with value Microsoft Edge Updates Helper ^[strings.txt] |
| T1543.003 | Create or Modify System Process | spawn(..., { shell: true }) executes staged EXE ^[strings.txt] |
References
- letsdiskusscom — Entity page for the cluster (24 prior confirmed siblings)
- poem-word-list-steganography — Technique page for the 256-word poem encoding
- registry-run-persistence — Procedure page for the BAT-based Run key
- natural-language-payload-encoding — Concept page for prose-based payload hiding
- MalwareBazaar artifact:
adc5a0b48efb808930acadd51091509e481512446aac030a367d4577be861eb2
Provenance
file.txt—fileutility output (file type identification)exiftool.json— ExifTool metadata extraction (file size, line counts, MIME type)strings.txt— Full ASCII string extraction (JavaScript source lines, poem vocabulary, function definitions, file paths)triage.json— Triage pipeline metadata (artifact ID, labels, tier assignment)- Decoded payloads verified by re-running the
writePositionsToFiledecoding logic in Python and confirming SHA-256 hashes match the original cluster payloads for EXE, DLL2, DLL3, and BAT. - DLL1 (
msvcp140.dll) hashfa77a57e...is novel to this sample and does not appear in any of the 24 prior sibling reports.