typeanalysisfamilyletsdiskusscomconfidencehighcreated2026-08-23updated2026-08-23malware-familyloaderscriptnodejsobfuscationevasionpersistence
SHA-256: 4c57911f992d2760d089820ec5a73be433aa4f91a656f241b7fc980c98b0ba8e

letsdiskusscom: 4c57911f992d — Update_15.js, twentieth confirmed sibling

Executive Summary

Twentieth confirmed sibling of the letsdiskusscom Node.js poem-steganography dropper cluster. Filename Update_15.js continues the active build-counter pattern. Numbered-suffix poem vocabulary (gentle1, hush2, etc.) persists. Same signed Revo EXE and two vcruntime DLLs as all nineteen prior siblings; introduces a twentieth distinct msvcp140.dll morph (907,776 bytes). Static-only (CAPE skipped — JS source not a supported binary class).

What It Is

  • Filename: Update_15.js ^[metadata.json]
  • Size: 7,699,519 bytes (7.7 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 tge9KnkgpkOY ^[decoded from JS source]

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 23-33):

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. ^[decoded from JS source]

Decoded payloads

File Size SHA-256 Notes
Microsoft Edge Updates Helper.exe 52,400 B 8b94af60... Same signed Revo EXE as all 19 prior siblings
msvcp140.dll 907,776 B c8f39899... Twentieth distinct morph — new to cluster
vcruntime140.dll 101,672 B ff43e813... Same as all prior siblings
vcruntime140_1.dll 44,328 B 7b8f70dd... Same as all prior siblings
tge9KnkgpkOY.bat 440 B dff20059... Same BAT as all prior siblings

The BAT writes HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper pointing to the staged EXE, then launches it. ^[decoded BAT payload]

C2 Infrastructure

None observed. Self-contained local installer. No network IOCs in carrier script or decoded payloads. The malicious act is deceptive delivery + silent execution + registry persistence.

Interesting Tidbits

  • Build-counter continuity: Update_15.js sits between Update_14.js (a27bda89) and Update_16.js (26155786) in the filename sequence, confirming an active build counter rather than random naming. ^[entities/letsdiskusscom.md]
  • msvcp140.dll morph #20: 907,776 bytes, SHA-256 c8f39899.... Not observed in any prior sibling. The builder actively rotates this DLL while keeping the core Revo EXE and vcruntime pair constant — likely to evade hash-based detection on the runtime dependency rather than the payload. ^[decoded payload hashes]
  • Identical BAT hash: dff20059... — same 440-byte batch script across all twenty siblings, confirming a single BAT template shared by the builder. ^[decoded payload hashes]
  • No javascript-obfuscator: This sibling uses the custom poem-stego encoding, not the commercial JS obfuscator seen in the first sibling (9dc2cded). The poem template has completely replaced the obfuscator template in recent builds. ^[entities/letsdiskusscom.md]

How To Mess With It (Homelab Replication)

  1. Encode a payload with poem steganography:
    with open('words.txt') as f: words = f.read().split()
    assert len(words) == 256
    with open('payload.exe', 'rb') as f: data = f.read()
    encoded = ' '.join(words[b] for b in data)
    
  2. Add numbered suffixes (optional): After the first 256-word cycle, append 1, 2, etc. to repeated words.
  3. Wrap in Node.js carrier: Use the writePositionsToFile pattern from this sample, stage to %ProgramData%, spawn via child_process.spawn.
  4. Verify: Decode your own carrier back to the original payload; compare SHA-256.

Deployable Signatures

YARA rule

rule letsdiskusscom_poem_stego_dropper {
    meta:
        description = "Node.js poem-word-list steganography dropper (letsdiskusscom cluster)"
        author = "PacketPursuit"
        date = "2026-08-23"
        hash = "4c57911f992d2760d089820ec5a73be433aa4f91a656f241b7fc980c98b0ba8e"
    strings:
        $node_fs = "const fs = require('fs');"
        $node_path = "const path = require('path');"
        $node_spawn = "const { spawn } = require('child_process');"
        $app_name = "Microsoft Edge Updates Helper"
        $wlist = "const wlist ="
        $func = "function writePositionsToFile(listA, listB, outPath)"
        $poem_start = "gentle hush that wraps the midnight air"
        $bat_ext = ".bat"
        $dll1 = "msvcp140.dll"
        $dll2 = "vcruntime140.dll"
    condition:
        filesize > 1MB and
        all of ($node_*) and
        $app_name and
        $wlist and
        $func and
        $poem_start and
        $bat_ext and
        $dll1 and
        $dll2
}

Behavioral hunt query (Sigma-like)

title: letsdiskusscom Node.js dropper execution
detection:
  selection:
    - Image|endswith: 'node.exe'
    - CommandLine|contains:
      - 'Microsoft Edge Updates Helper'
      - 'Update_'
      - '.js'
  selection_file_write:
    - TargetFilename|contains: 'Microsoft Edge Updates Helper'
    - TargetFilename|endswith: '.exe'
  selection_spawn:
    - ParentImage|endswith: 'node.exe'
    - Image|endswith:
      - 'cmd.exe'
      - 'conhost.exe'
  condition: selection and selection_file_write and selection_spawn

IOC list

Type Value Context
Filename Update_15.js Carrier script
Staging dir %ProgramData%\Microsoft Edge Updates Helper tge9KnkgpkOY Payload drop location
Registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper Persistence
EXE SHA-256 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f Signed Revo payload
DLL SHA-256 c8f3989934455b62a700cdb450b24b476305c3e747282ac905c1e9c49ecd7678 msvcp140.dll morph #20
DLL SHA-256 ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 vcruntime140.dll
DLL SHA-256 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 vcruntime140_1.dll
BAT SHA-256 dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 Registry persistence script

Behavioral fingerprint

This Node.js script requires fs, path, and child_process, defines a 256-word English poem vocabulary with optional numbered suffixes, and uses writePositionsToFile to decode four PE files and one BAT script by word-index lookup. It stages payloads to a %ProgramData% subdirectory named Microsoft Edge Updates Helper <random_suffix>, writes an HKCU Run registry entry via the BAT, and silently executes the dropped EXE. No C2 traffic is generated by the carrier.

Detection Signatures

Capability ATT&CK
JavaScript execution T1059.007
Obfuscated Files or Info (poem steganography) T1027.002
Masquerading (browser update helper) T1036.005
Registry Run Keys T1547.001
Create/modify system process T1543.003

References

Provenance

  • file.txt — file utility (file type: JavaScript source, ASCII text)
  • exiftool.json — ExifTool 12.76 (7.7 MB, 60 lines, 1,107,076 words)
  • triage.json — triage-fast pipeline (tier: deep, no family attribution)
  • dynamic-analysis.md — CAPE skipped (JS source not supported)
  • capa.txt — capa errored (unsupported file format)
  • floss.txt — floss errored (invalid CLI args)
  • binwalk.txt — binwalk (no embedded artifacts detected)
  • rabin2-info.txt — radare2 (not a PE, 7.7 MB plain text)
  • Decoded payloads verified via Python3 script (SHA-256 computed with hashlib)
  • Source JS decoded manually by extracting const declarations and running the embedded writePositionsToFile logic