February Xss Challenge Intigriti Writeup
Introduction
The challenge site offers a nice interface which allows you to enter a username and answer to the following question: Have you ever played this game?
. On submitting the same page is requested again with two parameters in the request: q
and first
. The first one contains the username and the second contains the string yes
or no
depending on our selection. The details of how this is handled is containined in one single script and can be found by simply inspecting the page source:
The Challenge
When the page is requested with the q
and first
parameters, the showModal
function is executed and a popup is shown.There is some insecure innerHTML
assignment in that function! We have a limit of 24 characters on the username (the q
parameter), but let’s try to inject some html code. For instance I tried <img src=x/>
:
That looks good! The image tag is injected and no sanitization is going on. Despite of this, injecting a script tag would not work because of the length constraints.
A short payload
A collection of very short xss payloads is avaiable at @terjanq’s github repo. At first I ended up trying <svg/onload=alert(name)>
. This should be automatically parsed by the browser and adjusted to a valid svg
tag. For instance <svg onload="alert(name)"></svg>
.
It worked! But was it really so easy?
The name variable is usually a propriety of window that can be overwritten by setting up an
iframe
… but not in this case! Looking back to the source code, we can see that thename
variable is hardcoded at the first line. Nothing to do here!
What’s next?
We have an alert but no arbitrary javascript execution is possible. By injecting <svg/onload=eval(name)>
, the content of name
is evaluated and executed. This seems a good way to go but we don’t really can control the name
variable. At this point, I looked for other variables that we can control. To do so, I placed a breakpoint on contentDOM.innerHTML = content
and inspected the Scope
tab in the inspector to see all variables We have access in this context. My research revealed only three valid (short enough) strings that we can use: name
,qs
and uri
. Look at that, we can control the uri!
I spent some time trying to get something out of this. At some point I tried the following in the js console:
> https://example
2
< 2
In other words, https://example
and 1
on the next line is valid javscript! To double check:
> eval("https://challenge\n1")
< 1
https:1
is treated as a key:value
pair, and the fact that they are separated by a comment (starting with //
) and a newline (\n
) is not a problem!
The exploit
With this knowledge we can solve the challenge! We control the url and in particular we can set the first
parameter to anything we want. Because before beeing assigned to uri
, the url is urlDecoded with decodeURIComponent()
we can also inject newlines using %0a
. To make the uri valid we need a newline, a number, a semi-colon and then arbitrary javascript! We can do so by setting the first
variable to %0a1;alert(document.domain)
. Our username instead will be set to <style/onload=eval(uri)>
, to evaluate the uri!
Final payload will be:
https://challenge-0222.intigriti.io/challenge/xss.html?q=%3Cstyle%2Fonload%3Deval(uri)%3E&first=%0A1;alert(document.domain);
To visit the link you can click here.
Alert! Very nice challenge and don’t forget to follow intigriti on twitter to stay updated for the ones that are coming!
Note: I used a
style
tag instead of ansvg
tag because the original payload wasn’t firing on firefox. I investigated and it seems like firefox executes theonload
event onsvg
andimg
tags only when they are loaded from external resources (e.g. they use thesrc
attribute).