typeanalysisfamilyletsdiskusscomconfidencehighmalware-familyloaderscriptnodejsobfuscationevasionpersistencemitre-attck
SHA-256: c485dd9c6d810f36618315d661ecb801f4ef8d44ef9946876a4649ed8c23c15e

letsdiskusscom: c485dd9c — fifteenth confirmed poem-stego sibling, Update.js

Executive Summary

Update.js is the fifteenth confirmed sibling in the letsdiskusscom Node.js dropper cluster. It encodes four PE payloads and a persistence BAT inside a 256-word English poem via numbered-suffix steganography, stages them to %ProgramData%\Microsoft Edge Updates Helper WG4n5KCoqYf0, and silently executes a signed Revo Uninstaller component. No C2 — self-contained local payload delivery with registry Run persistence. ^[strings.txt:1]

What It Is

Field Value
SHA-256 c485dd9c6d810f36618315d661ecb801f4ef8d44ef9946876a4649ed8c23c15e
Filename Update.js
Size 8,150,621 bytes (7.8 MB)
File type JavaScript source, ASCII text, very long lines (63,365), CRLF terminators ^[file.txt:1]
Family letsdiskusscom (high-confidence cluster sibling)
Source OpenCTI / MalwareBazaar (js label)

The sample is a Node.js script using fs, path, and child_process modules to drop and execute embedded Windows PE payloads. All payloads are encoded inside the script via custom poem-word-list steganography. ^[strings.txt:1]

How It Works

1. Poem-word-list steganography

The script defines a 256-word lookup table (wlist) — the same English poem fragment observed in siblings 3465e6ee through 26155786 — and five payload strings (exe, dll1, dll2, dll3, bat). Each payload word is looked up in wlist by index; the index value (masked to 0xFF) is written to disk as a byte. ^[strings.txt:6]

Builder variant: numbered suffixes on repeated vocabulary (gentle1, hush2, that3 ... fail164). This poisons frequency analysis without changing lookup semantics. Same template as siblings 3465e6ee, ae2e9acd, 70862e4d, ff3ae2e7, 1fbaf8ab, and 26155786. ^[strings.txt:6] ^[techniques/poem-word-list-steganography.md]

2. Payload decode and staging

const folder = path.join(process.env.PROGRAMDATA, `Microsoft Edge Updates Helper WG4n5KCoqYf0`);
const exePath = path.join(folder, "Microsoft Edge Updates Helper.exe");
const autorunPath = path.join(folder, "WG4n5KCoqYf0.bat");
// ... plus three VC++ runtime DLLs

The script creates the staging directory recursively with mode 0o755, decodes all five payloads via writePositionsToFile, then spawns the BAT (adds registry persistence) followed by the EXE. ^[strings.txt:12]

3. Registry Run persistence via BAT

The decoded BAT adds an HKCU\Software\Microsoft\Windows\CurrentVersion\Run entry named "Microsoft Edge Updates Helper" pointing to the staged EXE. ^[manual decode of bat.bin]

4. Payloads decoded

Payload SHA-256 Size Description
EXE 8b94af60...7fc55f 52,400 B RevoSrp.exe — VS Revo Group, MSVC 14.44, Authenticode signed (DigiCert). Same hash as all 14 prior siblings. ^[exiftool.json: exe]
DLL1 832c1425...0d8ca 969,728 B msvcp140.dll, Microsoft, MSVC 14.27.29016.0. Fifteenth distinct msvcp140 morph in cluster. Unsigned. ^[exiftool.json: dll1]
DLL2 ff43e813...4c833 101,672 B vcruntime140.dll, Microsoft, MSVC 14.27. Signed. Same hash as all 14 prior siblings. ^[exiftool.json: dll2]
DLL3 7b8f70dd...6dfc7 44,328 B vcruntime140_1.dll, Microsoft, MSVC 14.27. Signed. Same hash as all 14 prior siblings. ^[exiftool.json: dll3]
BAT dff20059...06919 440 B Registry Run persistence script. Same hash as all 14 prior siblings. ^[manual decode]

Decoded Script Behavior

Entry point is the top-level block at the bottom of the script:

  1. Directory creation — safeMakeDir(folder) with recursive: true and mode 0o755. ^[strings.txt:27]
  2. Payload reconstruction — Five calls to writePositionsToFile(wlist, payload, destPath) decode the poem strings back to raw PE/BAT bytes. ^[strings.txt:18]
  3. Execution — launchExecutable spawns "autorunPath" with shell: true and passes exePath as an argument, then spawns exePath directly. The BAT adds the registry key and exits; the EXE runs regardless. ^[strings.txt:29]
  4. Error handling — Wrapped in a bare try/catch that logs "Installation failed" to stderr and exits with code 1. ^[strings.txt:42]

C2 Infrastructure

None. Self-contained local installer. No network requests, no hardcoded URLs, no DNS, no C2 callbacks. The malicious act is silent staging and execution of a masqueraded signed binary with persistence.

Interesting Tidbits

  • Fifteenth distinct msvcp140.dll: The cluster now shows 15 unique msvcp140 morphs. The builder rotates VC++ runtime redistributables between builds while keeping the Revo EXE and vcruntime DLLs constant, likely to evade hash-based detection on the DLL alone. ^[exiftool.json: dll1]
  • Filename lacks build counter: Unlike prior siblings (Update_3.js, Update_13.js, Update_16.js, Update_22.js, Update_25.js), this sample is simply Update.js. This may represent a fresh campaign wave, a different distribution channel, or a builder configuration toggle. ^[metadata.json:5]
  • MSVC 14.27 timestamp on DLL1: 2020-06-16 03:11:14 — same vintage runtime as siblings 5126076d, 2274d74f, ae2e9acd, 70862e4d, ff3ae2e7, 1fbaf8ab, and 26155786. The builder draws from a pool of older redistributables. ^[exiftool.json: dll1]
  • RevoSrp.exe PDB path: D:\\Work_REVO\\VSRevo\\Windows\\Projects\\Registry Cleaner\\revo-registry-cleaner\\Revo Registry Cleaner\\x64\\Release\\RevoSrp.pdb — same as sibling 26155786, confirming a Registry Cleaner product-line origin rather than Uninstaller Pro. ^[strings.txt: exe_strings.txt]
  • BAT argument passing: The BAT accepts "%~1" (the EXE path) as an argument, but the registry key hardcodes the EXE path inside the BAT's own string — the argument is redundant and likely builder template residue. ^[manual decode of bat.bin]
  • No javascript-obfuscator: The obfuscation is purely the poem steganography. No self-defend IIFE, no string-array rotator, no dead-code injection. ^[strings.txt:1]

How To Mess With It (Homelab Replication)

See poem-word-list-steganography for the full replication recipe. The numbered-suffix variant used here is identical to sibling 26155786; add suffixes only on repeated words to poison frequency analysis without changing decode semantics.

Deployable Signatures

YARA rule — letsdiskusscom poem-stego Node.js dropper

rule letsdiskusscom_poem_stego_js
{
    meta:
        description = "Node.js dropper using 256-word poem steganography to encode PE payloads"
        author = "PacketPursuit"
        reference = "/intel/analyses/c485dd9c6d810f36618315d661ecb801f4ef8d44ef9946876a4649ed8c23c15e.html"
        date = "2026-08-22"
    strings:
        $require_fs = "const fs = require('fs');"
        $require_path = "const path = require('path');"
        $require_spawn = "const { spawn } = require('child_process');"
        $wlist = "const wlist = \"gentle hush"
        $exe = "const exe = \"unwearied"
        $dll1 = "const dll1 = \"unwearied"
        $func = "function writePositionsToFile(listA, listB, outPath)"
        $progdata = "Microsoft Edge Updates Helper"
    condition:
        filesize > 1MB and filesize < 15MB
        and all of ($require_*)
        and $func
        and $progdata
        and any of ($wlist, $exe, $dll1)
}

Sigma rule — Node.js spawning signed EXE from fake Edge Updates Helper directory

title: Node.js spawning signed EXE from fake Edge Updates Helper directory
logsource:
    product: windows
    category: process_creation
detection:
    selection_parent:
        ParentImage|endswith: '\\node.exe'
    selection_child:
        CommandLine|contains:
            - 'Microsoft Edge Updates Helper'
            - 'WG4n5KCoqYf0'
    selection_registry:
        CommandLine|contains:
            - 'reg add'
            - 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
    condition: selection_parent and (selection_child or selection_registry)
falsepositives:
    - Unknown
level: high

IOC list

Indicator Value Type
SHA-256 (carrier) c485dd9c6d810f36618315d661ecb801f4ef8d44ef9946876a4649ed8c23c15e Hash
SHA-256 (embedded EXE) 8b94af60bb58bc1629edb3b4f6a86ccff5769bb9b96d8826f06686af2d7fc55f Hash
SHA-256 (embedded DLL1) 832c14257068501f4edbdd18e0ab7eac5b615dbd2e63da20a47ec7475f00d8ca Hash
SHA-256 (embedded DLL2) ff43e813785ee948a937b642b03050bb4b1c6a5e23049646b891a66f65d4c833 Hash
SHA-256 (embedded DLL3) 7b8f70dd3bdae110e61823d1ca6fd8955a5617119f5405cdd6b14cad3656dfc7 Hash
SHA-256 (embedded BAT) dff20059f161090c76f9f45ac2269f2965bdc96023c78c1072f8d1aa66b06919 Hash
Staging directory %ProgramData%\Microsoft Edge Updates Helper WG4n5KCoqYf0 Path
Registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Microsoft Edge Updates Helper Registry
Process tree node.exe → cmd.exe /c "WG4n5KCoqYf0.bat" → Microsoft Edge Updates Helper.exe Behavior

Behavioral fingerprint

This Node.js script drops five files to a fake %ProgramData%\Microsoft Edge Updates Helper <random_suffix> directory: one 52 KB signed x64 EXE (RevoSrp.exe), three Microsoft VC++ runtime DLLs (msvcp140.dll, vcruntime140.dll, vcruntime140_1.dll), and one 440-byte BAT script. The BAT adds an HKCU\Run persistence entry, then the EXE is launched via child_process.spawn with shell: true. No network activity. The script body contains extremely long lines (tens of thousands of characters) composed of English poem words with optional numeric suffixes.

Detection Signatures

  • capa: N/A — JavaScript source file, not a supported binary class. ^[capa.txt:1]
  • MITRE ATT&CK:
    • T1059.007 (Command and Scripting Interpreter: JavaScript)
    • T1027.002 (Obfuscated Files or Information: Software Packing) — poem-word-list encoding
    • T1036.005 (Masquerading: Match Legitimate Name or Location)
    • T1547.001 (Boot or Logon Autostart Execution: Registry Run Keys)
    • T1543.003 (Create or Modify System Process: Windows Service) — via child_process.spawn

References

Provenance

  • Source file: wiki/wiki/raw/analyses/c485dd9c6d810f36618315d661ecb801f4ef8d44ef9946876a4649ed8c23c15e/
  • Decoded payloads written to /tmp/c485_decode/ via manual Python script
  • File type: file 5.44
  • Metadata: exiftool 12.76
  • capa: skipped (JavaScript source, unsupported file class) ^[capa.txt:1]
  • CAPE: skipped (JavaScript source, no Windows guest) ^[dynamic-analysis.md:1]
  • No radare2 or Ghidra analysis required — behavior is fully recoverable from plaintext JavaScript decode.