# AI, Scripts, Operator: Inside the ConnectWise Attack

Stolen ConnectWise Cloud Backup app credential was replayed across ~1,000 M365 tenants, letting the actor add secrets/certs and self-grant Global Admin within hours.

- Payout: Real-world hack
- Severity: critical
- Program: ConnectWise
- Analysis by: Huntress
- Disclosed: 2026-10-26
- Write-up quality: 8/10
- Original: https://www.huntress.com/blog/connectwise-attack-ai
- Library page: https://bugbountylibrary.com/r/blog%3Ahuntress-com-blog-connectwise-attack-ai
- Tags: area:cloud domain:cloud impact:internal-access impact:mass-exploit impact:privesc kind:incident platform:threat-intel sev:critical tech:azure tech:oauth technique:default-creds technique:recon vuln:auth-bypass vuln:privilege-escalation

**Target:** Microsoft 365 tenants via ConnectWise Cloud Backup multi-tenant application credential (Entra app-only auth, Graph API)
**Root cause:** A single multi-tenant ConnectWise Cloud Backup application credential was compromised and could authenticate to downstream Microsoft 365 tenants; tenants trusted the vendor app, so app-only tokens granted directory write access (credential addition, role assignment) without further consent.
**Steps:**
1. Obtain ConnectWise Cloud Backup application credential (acquisition method unknown; preceded by password spray from 144.172.64[.]99, Oct 10-14).
2. From 144.172.64[.]128, request one token per tenant iterating a sorted list of ~1,000 tenant IDs, 1-6 min apart, UA `Python-urllib/3.12` (06:13-08:46 UTC Oct 15).
3. Earlier at 06:04 UTC, ~100 parallel token requests in 10s against first 100 tenants via thread pool, all failing identically.
4. In target tenant: add application secret, remove it, add again; upload certificate (fails on thumbprint mismatch); retry loop added 55s later succeeds.
5. Grant Global Administrator to the app/service principal, remove it, re-grant; on refusal grant a different role to a sibling principal, then delete original service principal.
6. Repeat sequence in second tenant 47s later with both keys in one run.
7. Use Graph token requests for targeted sweeps: 17 hand-picked tenants over 3h, then fixed 6-resource probe per tenant in sorted order at 4s/tenant.
**How found:** Huntress analyzed Entra sign-in and directory audit logs plus fleet-wide sweeps: spotted ascending tenant-ID ordering with fixed cadence and identical UA (script loop), a 100-request/10s burst with identical failures (thread pool), tooling mutating within 55s of a failure to add exponential-backoff retry (operator/agent adaptation), pilot-then-batch targeting, and hand-edited UA strings (python-requests/2.31 vs 2.31.0, browser UA missing KHTML segment).
**Exploitation:** Attacker replayed the stolen vendor app credential tenant-by-tenant to obtain app-only Graph tokens, then used directory write access to plant persistent credentials (secrets, certificates) and escalate the Teams application identity to Global Administrator, plus grant roles to sibling service principals for redundancy — establishing persistent admin access across many downstream M365 tenants at machine speed.
**Escalation:** Credential planting chained to self-assignment of Global Administrator / Privileged Role Administrator, then sibling-principal role grants for redundant access; scaled horizontally across ~1,000-2,250 tenants.
**Insight:** Vendor multi-tenant app credentials are a cross-tenant skeleton key: baseline each vendor app's UA (e.g. kiota-dotnet), source range and cadence, and alert on a vendor principal granting itself Global Admin or a role to a sibling principal — plus enable Graph activity logs, since Graph reads never appear in Entra audit logs.

