※ 영문영상에서 정보를 따와서 오역이 있을 수도 있습니다. 지적 시 성실히 수정하도록 하겠습니다.
※ alert(document.domain) alert(window.origin) 순으로 script가 출력되게끔 설정해놨습니다.
▶When reporting XSS, don't use alert(1)
XSS취약점을 발견하면, 통상적으로 alert(1)을 쓴다. 해당 영상에서는 왜 alert(1) 대신에 alert(document.domain), alert(window.origin), console.log를 써야하는지 설명하고 있다. XSS 취약점을 bug hunt 할 때에, 특히나 현재의 web app에서, 중요하게 이해해야하는 정보들을 설명한다. 이는 실제로 얼마만큼의 파급력을 XSS가 가졌는지 알게 해준다. 실제로 치명적인 XSS 취약점을 찾았는가는 중요하다. 발견한 문제가 그렇지 않은 XSS 취약점이라면 별로 유효하지 않은 문제이기 때문이다.
▶Why do we use alert(1) to XSS?
두가지 큰 이점이 있기 때문에 alert(1)을 쓴다.
첫째로, 한눈에 볼 수 있기 때문이다. 만약, 무작위적으로 XSS payload를 다양한 입력 필드에 넣고 웹 브라우저로 돌아오면, alert 팝업을 볼 수 있다. 다시말해, 각 입력값을 주의깊게 살펴보지 않아도 된다는 뜻이다. (적어도) 기본적인 XSS 사례에서 왜 XSS가 쉽게 bug hunt되는지에 대한 이유이다. 해당 취약점은 입력을 뿌리고 경고팝업이 뜨도록 기도하는 것처럼 간단하다.
하지만, alert는 또 다른 이점을 가지고 있기도 하다. 가끔 제한된 형태의 자바스크립트를 허용하는 템플릿 기능을 가지는 일부 client-side 자바스크립트 프레임워크가 있다. 몇몇 일부 제한된 버전의 자바스크립트를 가지고 있는 입력란을 상상해보자. 예를 들면, 몇몇 변수영역을 출력하거나 기본적인 산수를 하는 경우가 있다. 이런 것들(변수영역, 산수영역)을 주입하는 것은 보안에 문제가 되지 않는다. 그러나, alert의 경우에는 window객체의 일부 함수이다. 그리고 윈도우 객체에는 공격자가 흥미를 가지는 가장 중요한 데이터들이 담겨져 있다. 예를 들면, session token을 가지고 있을 수 있는 localStorage가 있다. 또, 유명한 window.document.cookies도 있다. 이는, alert()를 실행하는 것이 발견한 XSS가 심각성을 가지는지에 대한 지표가 될 수 있음을 뜻한다. 참고사항으로 최근에는 제한된 자바스크립트 템플릿을 대부분 포기했는데, fix와 bypass의 쫓고 쫓기는 싸움이 되고, 항상 막는 것은 어려움을 배웠기 때문이다. 흥미가 있다면, angularJS의 sandboxing 시도의 역사를 찾아보는 것이 도움이 될 것이다(https://www.youtube.com/watch?v=67Yc8_Bszlk&list=PLhixgUqwRTjwJTIkNopKuGLk3Pm9Ri1sF : 해당 영상의 저자가 설명해놓은 영상이 있다.).
어쨋든 alert(1)이 XSS Injection이 치명적으로 이용될 수 있는지, 좋은 지표로 보임에도 불구하고, 실제로는 더 이상 좋은 지표가 아니다. alert() 팝업이 뜨더라도 이는 치명적인 보안적 문제가 될 수도 없다는 얘기다. 과연 왜 그럴까? 이는 alert(document.domain)이나 alert(window.origin)으로 설명할 수 있다. 해당 지표들을 사용하면, XSS취약점을 찾는 당사자에게도 찾는 것을 명확하게 해주면서 bug bounty report를 사용할 때에도, report를 받는 사람이(해당 영상에서는 google) XSS취약점 발견한 것을 리뷰하기 더 수월하게 만들어 줄 수 있다.
구글의 Blogger service를 예시로 들 수 있다(영상 시점이 좀 지난 영상이므로 좀 다를 수도 있다.). Blogger의 기능을 찾아보다보면, 임의의 HTML을 블로그에 삽입하는 기능을 찾아볼 수 있다. 다시말해, alert(1)은 Inject할 수 있음을 뜻한다. 실제로 써보면 '1'로 오류창이 뜨는 것을 확인할 수 있다. 도메인은 "blogger.com"이고 해당 사이트가 XSS의 범위 내라고 생각하고 Bug Bounty의 대상이라고 생각할 수도 있다. 하지만 틀렸다. 이유를 설명하자면, alert(1)을 alert(document.domain)으로 변경해주고 시도하면 알 수 있다. 새로운 payload를 저장하고 블로그 포스팅을 preview하게 되면, XSS는 발생하지만, 도메인이 "유저의 서브 도메인.blogspot.com"과 같이 뜨는 것을 발견할 수 있다.
그럼 왜 XSS가 왜 blogger.com 이 아니라 blogspot.com에서 발생할까? 크롬 개발자도구를 보자. 해당 웹사이트(blogger.com)는 실제로 src를 "유저의 서브 도메인.blogspot.com"으로 가지는 iframe을 가지고 있다. 그리고 XSS는 해당 도메인에 위치한다. 따라서, 우리는 실제 XSS 취약점을 "blogger.com"에서 찾은 것이 아니게 된다.
이제 또 다른 의문이 생긴다. 왜 구글은 두개의 다른 도메인을 blogger서비스를 운영하면서 쓸까? XSS가 그 이유다. 구글은 다양한 샌드박스 도메인을 사용해서 사용자생성 콘텐츠를 안전하게 호스팅한다. 많은 sandbox들이 사용자가 업로드한 HTML과 JavaScript를 분리하기 위해서 사용한다. 그렇게 어떠한 유저 정보에 접근하지 못하도록 확실히 한다. XSS 공격이 접근하지 말아야 할 정보에 접근하는 공격인 것을 명심하자. 쿠키를 예로 들 때, 쿠키는 "blogger.com" 도메인에 속해있다. 따라서, "유저의 서브 도메인.blogspot.com"에서 XSS공격을 시행해봤자, 해당 쿠키들은 탈취할 수 없다. SOP(Same-Origin Policy) 때문에 그렇다. 다시말해, 둘은 서로 다른 웹사이트로 취급되기 때문이다. 이것이 왜 XSS 가 시행되는 도메인이 어딘지 명확하게 알려주는 alert(document.domain)혹은 alert(window.origin)을 사용하라고 말하는 이유이다. 해당 지표는 어떠한 데이터에 XSS가 접근할 수 있는지 알려준다. 위 예시로 본다면 "유저의 서브 도메인.blogspot.com"에 해당하는 정보만 접근할 수 있음을 뜻한다.
구글은 블로그를 운영하는데 자의적으로 html과 javascript를 사용해서 스스로 블로그를 꾸밀 수 있게 만드는 것을 추구한다. 또한, 해당 기능이 XSS를 통해 다른 블로그 유저들을 공격하는 것을 원치 않기도 한다. 따라서 그들은 user data를 다른 domain에 넣고 iframe을 통해서 글을 넣는다. 따라서, alert 팝업을 본다면 document.domain 혹은 window.origin을 활용해서 XSS 발생이 치명적인 domain에서 발생하는지, 중요하지 않은 sandbox에서 발생하는지 확인할 수 있다. 다시말해, 이는 심각한 문제인지 아닌지를 판별할 수 있는 기준이 된다.
실제 다른 domain(또는 출처)을 통한 sandbox 외에도 sandbox iframe 개념도 존재한다. 해당 영상 주인이 전에 소개한 적이 있으니 참고하면 되겠다(https://www.youtube.com/watch?v=aCexqB9qi70). 구글이 json-p sandbox를 실행한다. 사용자가 제어하는 XSS payload와 함께 기본적으로 iframe을 삽입하지만, sandbox속성도 설정해서 iframe과 함께 넣어준다. 계산을 eval로 구현하고 출력하는 자바스크립트가 있다고 가정해보자. 그리고 해당 스크립트는 iframe안에서 실행되고 출력되는 상황을 가정해보자. 해당 iframe은 "allow-scripts allow-modals" 속성이 sandbox에 설정되어 있다. 만약, alert(1)을 쳤을 때, 경고창이 뜬다고 위험한 취약점일까? 전혀 아니다. document.session에 값을 설정하고 확인해보면 알 수 있다. alert(document.session)을 친다면, "undefined"를 alert창으로 띄운다. 이는 alert(document.domain)이나 alert(window.origin)으로 그 이유를 알 수 있다. 둘을 입력하면 빈값을 출력할 뿐이다. 해당 사례는 위의 blogger 사례와는 약간 다르다. 그러나 iframe이 다른 origin을 가지는 것은 이 경우에서도 쉽게 발견할 수 있다(비록 이상한 origin이 뜨지만). iframe은 삽입된 웹사이트에서도 격리되어 있다는 얘기다. 이러한 이유로 document.session을 탈취할 수 없다. 그래서 Blogger사례와 같이 고립된 iframe을 구현할 수 있는 것이다. 이러한 alert는 위와같이 유효한 보안문제가 될 수 없다.
XSS찾는 또 다른 팁을 주자면, 우선 sandbox처리가 된 iframe의 injection을 발견한다면, allow-modals 옵션이 허용된 경우는 찾기가 흔치않다. 예시로 구글 사이트(sites.google.com)에서 XSS payload를 입력하면 alert창이 뜨지 않는다. 이후 개발자도구 콘솔창을 본다면, sandbox 로 XSS가 막혔음을 확인해 볼 수 있다. 이러한 경우, console.log를 사용하는 것이 어디서 XSS payload를 실행하는지 혹은 XSS payload를 실행하는지 안하는지 확인하는데에 더욱 낫다. 그러나 이는 개발자도구에서 console의 출력에 아주 면밀히 주의를 기울여야함을 의미한다. 이 때 빠르고 쉽게 찾기 위해서 filter을 사용하는 것이 도움이 된다. XSS 찾는 것이 이렇게 생각보다 까다롭다. 어쨋든, console.log를 통해서 javascript를 실행하고 확인할 수 있다.
그래서 실제로 XSS가 sites.google.com에 발생했고, bug bounty에 성공한 것일까? 다시 말하지만, document.domain 출력으로 실제로 실행되는 실제 실행문 결과를 봐야한다. console.log("XSSTEST:"+window.origin) 과 같이 payload를 입력하면, console로 해당 payload를 출력하는 것을 확인해볼 수 있는데, 또 다른 sandbox domain을 가지고 있는 것을 확인해볼 수 있다(https://@@@@@@.googleusercontent.com). 따라서, bug bounty에 성공했다고 말할 수 없다. 즉, 보이는 XSS가 실제로 취약점이 아니라는 소리다. 위와 같이 또 다른 도메인을 넣어서 무해하게 만들도록 계획했다는 것이다.
이제는 생각이 들 것이다. "왜 bounty대상이 아닌, sandbox iframe 또는 sandbox domain의 XSS를 조사하는데 관심을 가져야하는가?". 만약 당신이 JSONP sandboxed iframe에 injection을 시행할 경우, iframe의 실제 사이트는 보통 iframe과 post메시지를 통해 통신한다. 그래서 기본적으로 Sandbox escape를 이용해서 메시지를 통해 실제 사이트에 XSS를 시행할 기회가 생길 수 있다. 이러한 경우에는 취약점은 첫번째 XSS에 있는 것이 아닌, sandbox escape에 있는 것이다. 따라서, sandbox된 XSS 그자체로는 Bounty의 가치가 없다는 소리다. 정리하자면, 어떻게든 다른 bug를 연결하고 escalate하고, 범위 내 domain에서 javascript를 실행할 수 있다면, bounty할 수 있는 유효한 보안문제가 된다.
전체적으로 요약하면 다음과 같다. 가장 중요하게 명심해야 할 점은 구글은 의도적으로 sandboxed subdomain 혹은 sandboxed iframe으로 XSS를 허용하고 있다. 간단한 alert()는 실제 심각한 XSS 문제를 내포하고 있음을 증명하기에 충분치 않다. 그러므로 항상 XSS가 실행되는 실제 domain을 봐야하고, 이는 alert(document.domain), alert(window.origin)으로 확인할 수 있다. 발견한 취약점이 sandbox domain으로 밝혀질 경우, 기분이 안좋을 순 있지만, 그러한 효과없는 XSS를 발견해도 일단은 좋아해도 좋다. 다른 취약점과 연결할 때 유용할 수 있으므로, 일단은 해당 취약점이 어디에서 발견됐는지 기억해두자.
▶구글이 bug로 제출하지 않는 subdomain 목록
|
※ 단, 삽입된 코드가 중요한 사용자 데이터에 대한 액세스 권한을 얻는 공격 시나리오가 있는 경우는 예외
▶세줄 요약
1. alert(1) 자체로는 실제 domain을 확인할 수가 없고 유효한 XSS인지 확인할 길이 없다. 따라서, alert(document.domain)혹은 alert(window.origin)을 사용하자.
2. alert() 창이 iframe의 sandbox기능 때문에 뜨지 않을 수 있다. 이러한 경우 console.log를 활용해서 XSS payload를 실행할 수 있다.
3. XSS payload가 sandbox domain일 경우, 그 자체로는 Invalid XSS임을 명심하자.
'정보보안(웹해킹) > XSS(Cross-Site Scripting)' 카테고리의 다른 글
Self-XSS (Self Cross-Site Scripting) (0) | 2023.01.03 |
---|---|
JSFuck and XSS Payload (부제 : !,[,],(,),+ 만으로 XSS하기) (0) | 2022.12.11 |
XSS 블랙리스트 필터링 우회 (0) | 2022.11.22 |
XSS응답 확인 : Request bin 사이트 및 사용법 (0) | 2022.11.22 |
XSS(Cross-Site Scripting) 응용 (0) | 2022.11.22 |
댓글