diff --git a/src/pentesting-web/oauth-to-account-takeover.md b/src/pentesting-web/oauth-to-account-takeover.md index f8b019d0c4b..59445bc3f2c 100644 --- a/src/pentesting-web/oauth-to-account-takeover.md +++ b/src/pentesting-web/oauth-to-account-takeover.md @@ -325,8 +325,40 @@ In mobile OAuth implementations, apps use **custom URI schemes** to receive redi +### Meta Accounts Center FXAuth chain (prefix bypass + postMessage leak + login CSRF) + +Meta’s Accounts Center linking flow between Facebook and Instagram exposed an ATO chain combining redirect validation flaws, token replay and cross-window leakage: + +- **Prefix escape on `native_sso` redirects**: For Instagram’s `app_id=1217981644879628`, `https://www.facebook.com/login/native_sso/` only checked that `extra_data` started with `/accounts_center/`. A double URL-encoded payload plus mixed `/` and `\` bypassed the prefix and landed on arbitrary `www.instagram.com` endpoints, e.g.: + + ```text + https://www.facebook.com/login/native_sso/?flow=fbcal&app_id=1217981644879628&token=FXAUTH_TOKEN&custom_content_config=accounts_center&extra_data=/accounts_center/%252%0DE%252%0DE\%252%0DE%252%0DE\/%252%0DE%252%0DE\%252%0DE%252%0DE\billing_interfaces\external_result?nonce=ATTACKER_NONCE + ``` + +- **Valid nonce generation (attacker IG account)**: The Instagram billing flow required a per-user nonce. After logging into `https://www.instagram.com/ad_tools/`, capture a billing access token (e.g., to `facebook.com/auth/token`) and call the GraphQL mutation `doc_id=8354858754606667` with the attacker `payment_account_id` to receive a `nonce` value. + +- **Login CSRF to force attacker IG session**: Instagram’s one-click email login endpoint (`/_n/web_emaillogin?uid=ENC_UID&token=LOGIN_NONCE&auto_send=0`) sets session cookies via GET with no interaction. Loading it in the victim browser authenticates the attacker’s Instagram account, so subsequent SSO/billing requests run under the attacker IG context. + +- **`postMessage('*')` URL leak**: Redirecting the SSO flow to `https://www.instagram.com/billing_interfaces/external_result/?blob=...&token=...&nonce=ATTACKER_NONCE` caused that page to `postMessage` the **full URL** to `opener`/`parent` with `targetOrigin='*'` whenever the nonce was valid. An attacker opener can harvest the blob/token: + + ```html + + ``` + +- **Replay to finalize linking**: Browsing to `https://accountscenter.instagram.com/add/?background_page=%2Fprofiles%2F&blob=&token=&auth_flow=linking` using the stolen blob/token binds the victim’s Facebook account to the attacker’s Instagram profile, persisting access without victim credentials or 2FA. + +**Key takeaways:** + +- Prefix-only redirect validation can be defeated with double-encoding and separator confusion, turning “restricted” SSO redirects into arbitrary same-host redirects. +- Any result page that posts sensitive query params with `targetOrigin='*'` lets an attacker-controlled opener exfiltrate tokens; conditioning the leak on a nonce doesn’t help if the attacker can legitimately mint one and force victim navigation under their session. +- GET-based one-click login endpoints act as **login CSRF/forced-login** primitives that let attackers swap the victim browser into their account to drive subsequent flows. +- Linking artifacts (FXAuth token + blob/token) must be single-use and bound to the original session/app; otherwise they can be replayed across apps to achieve persistent account takeover. + ## References +- [Steal FXAuth leads Instagram ATO](https://ysamm.com/uncategorized/2026/01/15/steal-fxauth-leads-instagram-ato.html) - [**https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1**](https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1) - [**https://portswigger.net/research/hidden-oauth-attack-vectors**](https://portswigger.net/research/hidden-oauth-attack-vectors) - [**https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html**](https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html)