You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a frame with src ./captcha.php and that's all, so we need to look into this php file:
<body><formid="captcha"><divid="input-fields"><spanid="a"></span><spanid="b">+</span><inputid="c"type="text"size="4"value=""required/>
=
<spanid="d"></span><progressid="e"value="0"max="100"style="display:none"></progress></div><inputtype="submit"id="f"/><inputtype="button"onclick="setNewNumber()"value="Retry"id="g"/></form></body><script>consta=document.querySelector("#a");constc=document.querySelector("#c");constb=document.querySelector("#b");constd=document.querySelector("#d");window.onload=function(){setNewNumber();document.getElementById("captcha").onsubmit=function(e){e.preventDefault();loadCalc(0);};}functionloadCalc(pVal){document.getElementsByTagName("progress")[0].style.display="block";document.getElementsByTagName("progress")[0].value=pVal;if(pVal==100){calc();}else{window.setTimeout(function(){loadCalc(pVal+1)},10);}}functionsetNewNumber(){document.getElementsByTagName("progress")[0].style.display="none";vardValue=Math.round(Math.random()*1000);d.innerText=dValue;a.innerText=Math.round(Math.random()*dValue);}functioncalc(){constoperation=a.innerText+b.innerText+c.value;if(!operation.match(/[a-df-z<>()!\\='"]/gi)){// Allow letter 'e' because: https://en.wikipedia.org/wiki/E_(mathematical_constant)if(d.innerText==eval(operation)){alert("🚫🤖 Congratulations, you're not a robot!");}else{alert("🤖 Sorry to break the news to you, but you are a robot!");}setNewNumber();}c.value="";}</script>
When the user clicks the submit button, the input value will be sent to eval function if there is no forbidden characters in the input value.
So we need to write a JavaScript program without a-df-z<>()!\='".
If you heard about JSFuck, yes, we can solve in a similar way.
Because we can't use alphabet directly, so we need to find a way to run the JavaScript dynamically, like eval, Function, setTimeout and setInterval.
Once we can use one of the above function, we can create our own function with whatever function body we want. Because function body is just a string, we can use their alternatives and put it together.
Like, `${0/0}`[1] as an alternative to a. This works because 0/0 produces NaN and backtick cast it to a string.
Let's find out which function we should use.
There is no way to access eval, setTimeout and setInterval if we can't access window. But Function is much easier to access because there are many ways to achieve it.
For example, []['constructor']['constructor']. Once we have function constructor, we can create our own function and execute it, like below:
You can run this on your console and see the alert. We use backtick for function call, two times. The first time is to create a function while the second is to execute it.
Someone might notice that there is a _ before ${alert(1)}, it's because of how tagged templates works.
If we do []['constructor']['constructor']`${'alert(1)'}`, the console will give us an error: Uncaught SyntaxError: Unexpected token ','.
It's easier to see what's going on under the hood by creating a dummy function:
Copy and paste this paragraph and click submit, boom! XSS triggered!
After the success I submitted my answer and got a reply said it's self-XSS(yes it is, but I didn't notice that 😂 ), it also said that I can experiment more with php.
It's not hard to find that query string c will be reflected on the page, so just add ?c= and paste the payload(remember to url encode) to change it from self-XSS to one-click XSS and solve the challenge.
The winner is some, so we will use it to replace []['constructor'].
Also, we should use alert(document.domain) as our payload instead of eval(location.hash.slice(1)), save a lot of characters. Even eval(name) is longer than alert() because the cost to get v is too high.
challenge link: https://challenge-0521.intigriti.io/
There is a frame with src
./captcha.php
and that's all, so we need to look into this php file:When the user clicks the submit button, the input value will be sent to
eval
function if there is no forbidden characters in the input value.So we need to write a JavaScript program without
a-df-z<>()!\='"
.If you heard about JSFuck, yes, we can solve in a similar way.
Because we can't use alphabet directly, so we need to find a way to run the JavaScript dynamically, like
eval
,Function
,setTimeout
andsetInterval
.Once we can use one of the above function, we can create our own function with whatever function body we want. Because function body is just a string, we can use their alternatives and put it together.
Like,
`${0/0}`[1]
as an alternative toa
. This works because0/0
producesNaN
and backtick cast it to a string.Let's find out which function we should use.
There is no way to access
eval
,setTimeout
andsetInterval
if we can't accesswindow
. ButFunction
is much easier to access because there are many ways to achieve it.For example,
[]['constructor']['constructor']
. Once we have function constructor, we can create our own function and execute it, like below:You can run this on your console and see the alert. We use backtick for function call, two times. The first time is to create a function while the second is to execute it.
Someone might notice that there is a
_
before${alert(1)}
, it's because of how tagged templates works.If we do
[]['constructor']['constructor']`${'alert(1)'}`
, the console will give us an error:Uncaught SyntaxError: Unexpected token ','
.It's easier to see what's going on under the hood by creating a dummy function:
Without prefix
_
, it's like calling function constructor with first parameter,
, which is not a valid argument name.But if we add
_
(or any valid name for parameter),_,
is a valid syntax for argument because,
is just a trailing comma.After find out the goal:
The last thing we need to do is to find a way to generate those characters.
jsfuck is a good resource if you don't know where to start.
Here is the string I used:
We can find all the replacement for our payload from the string above except
(
and)
.Where can we find these two characters? By casting a function to a string!
By piece all the alternatives we found together plus a little bit of programming, we can generate the valid payload:
output(length 851):
Copy and paste this paragraph and click submit, boom! XSS triggered!
After the success I submitted my answer and got a reply said it's self-XSS(yes it is, but I didn't notice that 😂 ), it also said that I can experiment more with php.
It's not hard to find that query string
c
will be reflected on the page, so just add?c=
and paste the payload(remember to url encode) to change it from self-XSS to one-click XSS and solve the challenge.url:
The story ends? No.
Go further
Pop an alert is not enough, I want to run any JavaScript on the page!
I just changed the payload to this:
So we can run any JS code after hash tag on the URL.
In order to do this, we need to find the replacement for
v
andh
.It's a little bit difficult because we can't find it in the common string we used:
undefined
,NaN
and[Object object]
.For
v
we can get it from any native function, like above,nati"v"e code
. But later I found that Firefox and Chrome output differently.Chrome outputs:
function RegExp() { [native code] }
and Firefox outputsfunction RegExp() {\n [native code]\n}
. Let's ignore it for now.How about
h
? We can get it by usingtoString
with radix 36:17['toString']`36`
, and getS
from string constructor.You may notice that at this point, we can actually generate any alphabet with
num['toString']`36`
. Forv
we can also use this.So the final payload will be(length 1925):
and the url is:
It works perfectly on both Firefox and Chrome!
Reduce the payload size
The last thing I want to do is to reduce the payload size. So I made following changes:
undefined
bye[0]
instead of ``[0], save 1 character.[object Object]
, ``+{} is redundant, use{}
only also works. Save 3 characters.e
as much as possible because it's shorter.We can also find the array method with the shortest length:
The winner is
some
, so we will use it to replace[]['constructor']
.Also, we should use
alert(document.domain)
as our payload instead ofeval(location.hash.slice(1))
, save a lot of characters. Eveneval(name)
is longer thanalert()
because the cost to getv
is too high.Below is the shortest payload I find, length 466:
The code I used to generate the payload:
Reduce the size, again
Remember the "v" issue? The cost is too high to get v to construct the payload
eval(name)
.It's because Firefox and Chrome produce different result:
We can ignore this issue for now and target Chrome only, the result is:
It's 376, reduce about 100 characters compare to the previous result 466.
The code I used to generate:
The text was updated successfully, but these errors were encountered: