familyletsdiskusscomconfidencehighcreated2026-08-22updated2026-08-22malware-familyloaderscriptnodejsobfuscationevasionpersistencemitre-attck
SHA-256: ddcb25ee4715a186558c8bf9540929049d9d69e0fe23d15ef885e71327d217a1

letsdiskusscom: ddcb25ee — Eighth confirmed sibling, eighth distinct msvcp140.dll morph

Eighth confirmed sibling of the letsdiskusscom Node.js dropper cluster. Identical 256-word English poem lookup-table steganography, identical signed RevoSrp.exe payload (SHA-256 8b94af60...), identical BAT-based HKCU\Run persistence script, and identical vcruntime DLLs — but an eighth distinct msvcp140.dll morph (SHA-256 696b6350..., 889,344 bytes, MSVC 14.40.33807.0). Builds on the existing seven-sibling cluster described in letsdiskusscom. ^[strings.txt:1]

What It Is

  • File: Update_7.js, 7,563,833 bytes, JavaScript source, ASCII, CRLF line terminators. ^[file.txt]
  • SHA-256: ddcb25ee4715a186558c8bf9540929049d9d69e0fe23d15ef885e71327d217a1
  • Family: letsdiskusscom (eighth confirmed sibling; high confidence)
  • Build stack: Plain Node.js (no javascript-obfuscator); require('fs'), require('path'), require('child_process').
  • Payload encoding: 256-word English poem lookup-table steganography (the same poem used across all poem-stego siblings, with numbered-suffix variant in 3465e6ee). Each payload byte is encoded as the index of a poem word; decoded by mapping word back to index and masking to & 0xFF. ^[strings.txt:3]

How It Works

Poem-Lookup Steganography

The script declares wlist — a 256-word English poem in sequence. Five payload strings (exe, bat, dll1, dll2, dll3) are expressed as space-delimited word sequences drawn from this list. At runtime, writePositionsToFile() maps each payload word back to its index in wlist, masks to 0xFF, writes to a Buffer, and persists to disk. ^[strings.txt:3]

This is the same technique documented in poem-word-list-steganography and observed across siblings d0ca14b3, 247b54b5, af4313e4, c075aeba, 3465e6ee, and 5126076d. This sample reverts to the plain 256-word list (no numbered suffixes), matching siblings d0ca14b3 through c075aeba and 5126076d, and diverging from 3465e6ee which introduced gentle1, hush2, etc.

Staging Directory

%ProgramData%\Microsoft Edge Updates Helper XQ49JB98nU3B\

Same directory name suffix (XQ49JB98nU3B) across all eight siblings. ^[strings.txt:4]

Dropped Files (decoded)

File Size SHA-256 Notes
Microsoft Edge Updates Helper.exe 52,400 8b94af60... RevoSrp.exe (VS Revo Group, signed, MSVC 14.44, PE32+ x64). Same hash across all eight siblings. ^[strings.txt:5]
msvcp140.dll 889,344 696b6350... Eighth distinct morph. MSVC 14.40.33807.0. Timestamp 0x683d5af8 (2025-06-02). ^[strings.txt:6]
vcruntime140.dll 101,672 ff43e813... Same hash across all eight siblings. ^[strings.txt:7]
vcruntime140_1.dll 44,328 7b8f70dd... Same hash across all eight siblings. ^[strings.txt:8]
XQ49JB98nU3B.bat 440 dff20059... Same BAT hash across all eight siblings. Adds HKCU\Software\Microsoft\Windows\CurrentVersion\Run persistence. ^[strings.txt:9]

Execution Flow

  1. Create %ProgramData%\Microsoft Edge Updates Helper XQ49JB98nU3B.
  2. Decode and write five files via writePositionsToFile().
  3. Launch the BAT with the EXE path as argument (launchExecutable(autorunPath, [exePath])).
  4. The BAT adds the EXE to HKCU\...\Run via reg add, then exits.
  5. The JS then launches the EXE directly (launchExecutable(exePath)).

Steps 3 and 4 both call spawn(..., { shell: true }). ^[strings.txt:10]

Decompiled Behavior

Not applicable — this is a plaintext JavaScript source file, not a compiled PE. The entire logic is visible in strings.txt. No Ghidra or radare2 analysis required.

C2 Infrastructure

None observed. This is a self-contained local installer — no network calls, no download URLs, no C2 beaconing in the carrier script. The RevoSrp.exe inner payload may contain its own C2 surface (not analyzed statically in this session). ^[strings.txt:11]

Interesting Tidbits

  • Eight msvcp140.dll morphs, one cluster: The builder appears to randomize or select from a pool of VC++ runtime redistributables while keeping the core payload (RevoSrp.exe) identical. This suggests an automated build pipeline that swaps dependency DLLs but pins the malicious EXE. ^[entities/letsdiskusscom.md]
  • No obfuscation on the JS: Unlike sibling 9dc2cded which used javascript-obfuscator, this sample is plain Node.js. The only anti-static measure is the sheer size (7.5 MB) and the poem encoding.
  • Version-info masquerade: The inner RevoSrp.exe carries CompanyName: VS Revo Group and ProductName: RevoSrp, masquerading as a legitimate uninstaller component. ^[exiftool.json]
  • dll4 = dll1? The script declares const dll4Path = path.join(folder, "XQ49JB98nU3B.bat") but dll4 is never defined in the payloads — likely a copy-paste artefact from the builder template. ^[strings.txt:12]
  • CAPE skipped: File type is JavaScript source, not a supported binary class for detonation. ^[dynamic-analysis.md]

How To Mess With It (Homelab Replication)

Build a proof-of-concept poem encoder in Python:

import struct

wlist = "gentle hush that wraps ...".split()  # 256 words
assert len(wlist) == 256

def encode_file(path):
    with open(path, 'rb') as f:
        data = f.read()
    words = [wlist[b] for b in data]
    return ' '.join(words)

exe_words = encode_file('/path/to/payload.exe')
# Write exe_words into a JS template matching the original

Verification: The decoded EXE should be a 52 KB PE32+ x64 with VS Revo Group version info and a valid Authenticode signature.

Deployable Signatures

YARA rule

rule letsdiskusscom_poem_stego_js
{
    meta:
        description = "Letsdiskusscom Node.js dropper with 256-word poem lookup-table steganography"
        author = "PacketPursuit"
        date = "2026-08-22"
        hash = "ddcb25ee4715a186558c8bf9540929049d9d69e0fe23d15ef885e71327d217a1"
        family = "letsdiskusscom"
    strings:
        $a = "Microsoft Edge Updates Helper XQ49JB98nU3B"
        $b = "const fs = require('fs');"
        $c = "const { spawn } = require('child_process');"
        $d = "writePositionsToFile"
        $e = "wlist = \"gentle hush that wraps the midnight air"
        $f = "XQ49JB98nU3B.bat"
        $g = "Microsoft Edge Updates Helper.exe"
    condition:
        filesize > 7MB and
        4 of ($a,$b,$c,$d,$e,$f,$g)
}

Behavioral hunt query (Sigma)

title: Letsdiskusscom Node.js Dropper Execution
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    CommandLine|contains:
      - 'Microsoft Edge Updates Helper XQ49JB98nU3B'
      - 'XQ49JB98nU3B.bat'
  condition: selection
falsepositives:
  - None expected — the directory name and batch filename are unique to this cluster.
level: critical

IOC list

Indicator Value Type
Carrier SHA-256 ddcb25ee4715a186558c8bf9540929049d9d69e0fe23d15ef885e71327d217a1 Hash
Inner EXE SHA-256 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f Hash
msvcp140.dll SHA-256 696b635099d5f7e60d432475674cb7fc0d7286ea5bd5472ade1bacfc07e6f355 Hash
BAT SHA-256 dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 Hash
Staging dir %ProgramData%\Microsoft Edge Updates Helper XQ49JB98nU3B\ Path
Registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper Registry
App name Microsoft Edge Updates Helper String

Behavioral fingerprint

This JavaScript carrier is a self-contained Node.js installer that decodes five embedded payloads from a 256-word English poem lookup table, stages them to a fake Microsoft Edge Updates Helper directory under %ProgramData%, adds the dropped EXE to the current-user Run key via a BAT script, and launches it with { shell: true }. No network calls in the carrier. The inner EXE is always a signed 52 KB RevoSrp.exe (VS Revo Group, MSVC 14.44) with varying msvcp140.dll redistributable morphs.

Detection Signatures

ATT&CK ID Technique Evidence
T1059.007 JavaScript execution Node.js require('fs'), require('child_process') ^[strings.txt:1]
T1027.002 Obfuscated Files or Info 256-word poem lookup-table steganography ^[strings.txt:3]
T1036.005 Masquerading Microsoft Edge Updates Helper directory and registry value ^[strings.txt:4]
T1547.001 Registry Run Keys BAT writes HKCU\...\Run for persistence ^[strings.txt:9]
T1543.003 Create/modify system process child_process.spawn(..., { shell: true }) ^[strings.txt:10]

References

Provenance

  • file.txt — file(1) output (file v5.44)
  • strings.txt — strings -n 4 output (GNU binutils strings 2.42)
  • exiftool.json — ExifTool 12.76 JSON export
  • dynamic-analysis.md — CAPE skipped (file type not supported)
  • Decoded payloads verified via custom Python decoder against the 256-word wlist and compared to known sibling hashes.