연습으로, 당신의 임무는 스크립트가 포함된 입력을 찾아내는 것 입니다. 당신은 이 페이지가 입력을 당신의 브라우저로 되돌려주도록 시도해야 하며, 이는 스크립트를 실행할 것 입니다. 이 Lesson을 통과하기 위해, 당신은 반드시 alert()와 document.cookie 를 사용해야 합니다.
풀이 환경
대상 : WebGoat 7
브라우저: Chrome
분석
사용자의 입력을 그대로 반영하는 부분을 찾아 스크립트를 실행하는
Reflected XSS 공격 입니다.
따라서, 사용자의 입력이 그대로 표시되는 부분을 찾습니다.
Enter your credit card number 또는 Enter your three digit access code
여기에 임의의 값을 입력한 뒤
Update Cart 또는 Purchase를 클릭하면, 입력한 값이 그대로 반영이 되는 것을 확인할 수 있습니다.
이제 저곳에서 alert(document.cookie); 가 실행이 되도록 해야 합니다.
우선, 동작을 시작하는 Purchase 나 Update Cart를 확인해 보겠습니다.
Purchase 또는 Update Cart 버튼 우 클릭 -> 검사
버튼을 클릭하면 purchase 함수를 호출 합니다.
그리고 이 함수는 현재 form에 있는 eval.js에서 확인할 수 있습니다.
eval.js는 페이지 로드 시
매번 새로 다운받기 때문에 Network 탭에서 확인해야 합니다.
개발자 도구 -> Network
아래는 eval.js 파일의 전체 내용입니다.
var http_request = false; function makeXHR(method, url, parameters) { //alert('url: ' + url + ' parameters: ' + parameters); http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType('text/html'); } } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!http_request) { alert('Cannot create XMLHTTP instance'); return false; } // http_request.onreadystatechange = alertContents; http_request.open(method, url, true); http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http_request.setRequestHeader("Content-length", parameters.length); http_request.setRequestHeader("Connection", "close"); http_request.onreadystatechange = function() { if(http_request.readyState == 4) { var status = http_request.status; var responseText = http_request.responseText; //alert('status: ' + status); //alert('responseText: ' + responseText); eval(http_request.responseText); if(responseText.indexOf("');") != -1 && responseText.indexOf("alert") != -1 && responseText.indexOf("document.cookie") != -1){ document.form.submit(); } } }; http_request.send(parameters); } function purchase(url) { var field1 = document.form.field1.value; var field2 = document.form.field2.value; //alert('field1: ' + field1 + ' field2: ' + field2); var parameters = 'field1=' + field1 + '&field2=' + field2; makeXHR('POST', url, parameters); }
값을 입력한 후 버튼을 클릭하면 onclick 이벤트에 따라 purchase 함수를 호출하게 됩니다.
이 때, purchase 함수의 파라미터로 request url을 보냅니다.
purchase 함수는 앞서 입력한 값을 읽어와 Request Parameter의 형태로 변환한 후
'POST', url, Request Parameter 를 makeXHR의 파라미터로 하여
makeXHR 함수를 호출합니다.
makeXHR 함수는 넘어온 파라미터를 가지고 POST Request를 생성하여
서버로 전송을 합니다.
Request에 대한 Response를 받아 그 값을
eval 함수를 통해 실행합니다.
그 후 Response의 값에 '); , alert , document.cookie 이 3가지가 있으면
양식을 제출하며 문제는 풀리게 됩니다.
여기서 헷갈릴 수 있는 것이
onreadystatechange 함수인데요.
이 함수는 서버로 보낸 요청(request)에 대한 응답을 받았을 때 어떤 동작을 할 것인지에 대한 사항을 정의하게 됩니다. 즉, 해당 함수를 수행하는 것이 아니라 단순하게 어떤 함수가 불릴 것 인지만 정하지, 실행하지는 않습니다.
풀이
분석이 끝났으므로, 문제를 풉니다.
eval 함수는 파라미터로 받은 javascript 구문을 그대로 실행하는 함수이므로,
makeXHR 함수에서 보내는 Request에 대한 Response에 실행시킬
javascript 구문이 포함됩니다.
정상 요청을 보낸 후 Response를 확인하면 alert 함수가 포함된 것을 볼 수 있습니다.
Enter your credit card number 혹은 Enter your three digit access code
둘 중 한 곳에 실행시킬 구문을 적어 그에 대한 Response를 확인해 봅니다.
alert(document.cookie); 를 입력하면 form이 제출이 되어 새로운 페이지를 요청하기 때문에, 다른 구문으로 시도합니다.
alert("chmodi");
alert 함수가 실행이 된 모습입니다. 내용이 바뀌었습니다.
해당 Response 입니다. 입력한 값이 문자열로 처리되어 있습니다.
입력한 값이 그대로 문자열로 들어가 브라우저에서 실행되기 때문에,
Javascript 구문만 맞다면 우리가 원하는 함수를 실행할 수 있습니다.
다음과 같이 입력해봅니다.
( Enter your three digit access code에 입력해야만 정답으로 인정이 되네요;;;)
123'); alert(document.cookie); ('
3 번의 alert 창을 넘기면 문제가 풀립니다.
그리고 이때의 Response는 다음과 같습니다.