Intended
Looking at the code, we'll see that it takes in two GET parameters number
and
name
. number
can only be one character and name
can be an
arbitrary value, but it's sanitized using DOMPurify. The website also uses Bootstrap. The goal is to make our input land
inside the eval
.
eval($('number#number').html())
We do control
$('number#number')
, but the issue is that it can only be one
character long. Now the question can we append some data to this tag before it lands into
eval
?
Yes, we can.
Fortunately, we have
Bootstrap Popovers,
which is just an HTML popover, but the nice thing about this is that we can tell where this
popover should go using
data-container
. If we set the
data-container=number
, this will insert the popover inside
number
element, which is exactly what we need.
Consider the following.
number=7
name=<button data-toggle=popover data-container=number data-content="blah blah">
The resulting
number.innerHTML
will be the following.
7<some-popover-template-html-code>blah blah<some-popover-template-html-code>
Now we can control the value that lands inside
eval
, but it's not valid Javascript.
To make this a valid Javascript code, we need to get rid of the popover HTML template. We
usually think about comments to get rid of some code, but here, the value of
number
can only be a character long, so we instead use strings.
Consider the following.
number='
name=<button data-toggle=popover data-container=number data-content="'-alert(1337)//">
The resulting
number.innerHTML
will be the following.
'<some-popover-template-html-code>'-alert(1337)//<some-popover-template-html-code>
If we try this, the XSS wouldn't work, because
popover('show')
has to be called on
our popover element, so that Bootstrap would inject our code to the
number
tag. But
there's
already
popover('show')
called on
#keanu
. We can set the
id to
keanu
so that Bootstrap would use our button instead of the already exisiting one.
Final Solution
number='
name=<button data-toggle=popover data-container=number id=keanu data-content="'-alert(1337)//">
name=<img x="/><img src=x onerror=alert(1337)>" y="<x">
This was possible because of a recent
DOMPurify bypass for Jquery found by
Masato Kinugawa.