"alert\x281\x29"instanceof{[Symbol.hasInstance]:eval};
Array.prototype[Symbol.hasInstance]=eval;"alert\x281\x29"instanceof[];
지금 올려주신 xss페이로드 두 개는 아래와 같이 나눌 수 있습니다.
"alert\x281\x29" instanceof {[Symbol.hasInstance]:eval};
Array.prototype[Symbol.hasInstance]=eval; "alert\x281\x29" instanceof [];
위의 페이로드를 이해하기 위해선 우선 Symbol이 무엇인지 알아야합니다.
Symbol은 ecmascript 6에 도입된 자바스크립트의 새로운 원시타입으로 고유한 값을 가지며 객체의 속성의 식별자로 이용됩니다.
이 Symbol에는 다양한 속성이 존재하는데 그중 하나가 Symbol.hasInstance
로 주어진 객체의 생성자가 함수의 인스턴스인지 확인하는데 사용하는 메소드입니다.
이 메소드는 instanceof와 함께 사용할 수 있는데
instanceof는 우측에 오는 값이 객체인지 확인하고 Symbol.hasInstance가 설정되있다면 해당 객체를 메소드로 호출하여 연산의 결과로 이용합니다.
그럼 만약 Array의 Symbol.hasInstance가 설정되있다면 위의 코드는 아래와 같이 나타낼 수 있습니다.
Array[Symbol.hasInstance](obj);
위의 두 페이로드는 이 원리를 이용한 페이로드입니다.
그럼 이제 페이로드를 하나씩 분석해보겠습니다.
우선적으로 분석해볼 페이로드는 "alert\x281\x29" instanceof {[Symbol.hasInstance]:eval};
입니다.
"alert\x281\x29"
는 Ecma Script에서 Hex Ascii String과 Unicode String, Octal String에 대하여 Auto Typecasting을 지원하기 때문에 "alert(1)"
로 자동으로 변환되게 됩니다.
이제 중요한 부분은 {[Symbol.hasInstance]:eval}
입니다. 간단하게 설명하자면 {}
빈 객체의 Symbol.hasInstance
속성의 값을 eval로 설정한 것인데
여기서 사용된 것은 Computed Property Name으로 객체의 key값을 표현식을 이용하여 나타내는 것 입니다.
위와 같이 객체의 Symbol.hasInstance
가 설정되었으므로 instanceof는 아래와 같이 함수를 호출하게 되고
obj = {[Symbol.hasInstance]:eval}
obj[Symbol.hasInstance](alert(1))
obj[Symbol.hasInstance]
는 eval함수이기때문에 최종적으론 alert함수가 실행됩니다.
다음 페이로드는 Array.prototype[Symbol.hasInstance]=eval; "alert\x281\x29" instanceof [];
입니다.
여기서 사용된 원리는 기본적으로 위의 페이로드와 같습니다. 다른 점이 있다면 이 페이로드는 javascript의 특징 중 하나인 prototype을 이용했다는 것입니다.
javascript는 prototype기반 언어로 모든 객체들은 속성과 메소드를 상속받기 위해 prototype 객체를 가지게 됩니다. 따라서 Array함수의 Prototype에 Symbol.hasInstance
를 key로 값을 설정하면 모든 배열은 해당 속성을 상속받게 됩니다.
따라서 Array.prototype[Symbol.hasInstance]
를 eval함수로 설정했으므로 []
는 eval함수를 값으로 하는 Symbol.hasInstance
라는 속성을 상속받게되고 "alert\x281\x29" instanceof [];
는 최종적으로 eval('alert(1)')
을 한 것과 같은 효과를 가지게 되어 alert가 실행되게됩니다.