최근에 Facebook 내 Stored XSS 취약점 관련 버그바운티 리포트가 올라왔습니다.
https://opnsec.com/2018/03/stored-xss-on-facebook/

og를 이용해서 xss까지 진행된 케이스인데, 생각보다 조금 의외의 내용이라 글로 공유합니다.

우선 og는 Open Graph로 웹의 품질 개선을 위해서 많이들 사용하는 부분입니다. meta 태그로 페이지에 대한 정보를 제공해주고, 이를 다른 어플리케이션이 활용할 수 있도록 도와주지요. 대표적으론 메신저나 SNS에서 링크를 공유할 때 사이트의 주요 이미지, 타이틀 정보 등이 요약되어 작성하는데 사용됩니다.

사실 og 자체에 대한 문제는 아닙니다. 웹 브라우저에서 #에 대해 처리하는 방식에서 발생한 문제이지요.

XSS in MediaElements.js(facebook video swf)

우선 해당 리포트에서 문제점인 라이브러리는 페북에서 사용되고 있던 "MediaElements.js" 입니다.
이 친구는 ogVideoType이 video/flv인 경우 FlashMediaElement.swf를 로드하고 ogVideoUrl을 FlashME.swf로 전달해서 영상을 재생합니다.

FlashME로 ogVideoUrl을 전달하는 과정의 코드를 보면 이런 형태입니다.

function absolutizeUrl(ogVideoUrl) {
var tempDiv = document.createElement('div');
tempDiv.innerHTML = '<a href="' + ogVideoUrl.toString().split('"').join('&quot;') + '">x</a>';
return tempDiv.firstChild.href;
}
flashDiv.innerHTML ='<embed src="FlashME.swf?videoFile=' + encodeURI(absolutizeUrl(ogVideoUrl )) +'" type="application/x-shockwave-flash">';

absolutizeUrl() 함수를 통해서 url 데이터를 가공한 후 플래시 파일의 인자값으로 데이터를 전달해주는데, 크롬에선 #과 "(quot)가 순차로 들어간 경우엔 필터링되지 않고 구문 밖으로 나가게 됩니다.


이걸 이용해서 XSS를 하였고 리포트 이후 이제 세상에 드러나게 되었습니다.

Why vulnerable? Bypass double quot(") Filter!

우선 #과 해시태그에 대한 관계를 알아야합니다.
사실 SNS 하면 아주 익숙하죠.. 작성한 글에 속성이나 관련된 것들을 표기해주는 양식(?)이고 많은 사람들이 SNS를 하면서 사용합니다. 또 다른 의미로는 샵을 통해 웹 페이지 내 특정 섹션에 바로 접근할 수 있도록 도와줍니다.

제 생각엔 전자로 인해서 웹 브라우저가 DOM 영역에 데이터 사용 시 url에 있는 #을 인코딩 시키지 않고 직접 사용하는 것으로 보입니다.
(어찌됬던 인코딩 안됩니다. 설마 후자인가...)

크롬(64버전 이하, 하필 딱 제가 테스트한 크롬 버전이 64네요)에서 #(해시태그)를 만났을 때 발생하고 Firefox 이외에는 모두 인코딩 시켜주지 않으니 Firefox을 제외한 나머지 버전에선 영향력이 있는 공격코드가 되겠네요.

간단하게 실험해보면..  아래 두 코드와 결과를 봅시다. 단순하게 DOM Write 하는 코드이고, 하나는 해시태그 뒤에 "(quot)를 넣어줬고, 하나는 그냥 "(quot) 만 넣어줬습니다.

document.write("<img/src="+absolutizeUrl('http://www.hahwul.com#" onerror=alert(45)')+">");

# 이 있는 경우 hash tag로 인지해 인코딩되지 않아 구문 탈출 가능함

document.write("<img/src="+absolutizeUrl('http://www.hahwul.com" onerror=alert(45)')+">");

#이 없으니 encoding되어 그대로 삽입됨. 덕분에 주소를 찾을 수 없어 에러 발생


원래 코드대로라면 싱글쿼터(') 안에 있기 때문에 모두 URL 인코딩을 거쳐 문자열로 처리되어야 하지만 위의 코드가 해시 태그로 인해 특수문자가 그대로 들어가게 됩니다.
그래서 구문 밖으로 탈출 할 수 있고 XSS가 가능해지죠.


XSS Vector and Conclusion

내용을 보다보니 혼자 내린 결론은.. 단순히 Facebook에서 쓰고있던 FlashMediaElement.swf의 문제가 아니란 겁니다.

결국은 해시태그를 포함한 URL 형태의 문자는 Firefox과 Chrome 65 버전 이상을 제외하곤 모두 Encoding 되지 않아 구문을 탈출 할 수 있게 됩니다.

URL을 처리하는 기능이나 페이지에선 당연히 영향력이 있는 부분이겠고 일반적인 XSS 우회 기법으로도 충분히 사용할 수 있다고 생각되네요.

http://www.hahwul.com#" [xss code]

Reflected나 일부 Stored XSS 는 Frount-End단에서 직접 필터링 하는 경우도 있습니다. 대체로 출력 과정에서 막는 부분이고, 잘 찾다보면 은근히 보이는 타입입니다.
이런 경우에 사용할 수 있는 좋은 방법으로 보입니다.

댓글 2개: