Preface
Intigriti host capture the flag(CTF) event’s through out the year, each month they host a new CTF and you have 7 days to complete it. https://challenge-0622.intigriti.io/
Initial identification of attack vectors
The functionality on the site wasn’t vast and it was limited to three functions:
- Milk
- Cookie
- Alert
Alert
Its function is used to create alert boxes.
This one is what peaked my interest at first, as the objective is to alert(document.domain) and this is already doing half the job for us.
Yet, input what is JavaScript or HTML is either capitalised or encoded, and in my mind it wasn’t a viable attack vector what I would want to dig further into.
Milk
Its function was to calculate the amount of cups and buckets of milk.
This one had me invested for a little while, different input locations had different encoding. In cups, it would handle a hash(#) by URL encoding it. This differs to how it was handled in buckets as it wasn’t encoded at all, I was trying to find other quirks, but it was hopeless. It was also not possible due to the inputs being evaluated and it can only take an integer.
<script>var total = eval(0.000000+0.000000*4); document.getElementById("total").value=total;</script>
Cookie
Its function was to set a cookie with other information.
Cookie was quite interesting, there wasn’t any user-controlled input at first what was quite disheartening but looking into it further allowed for the initial break through.
When pressing submit in the URL you get parameters what you can control, looking in the source code show’s how it’s being used.
function cookie_spawn(eggs,chocolate,vendor,location,price){
const cookie_value= 'eggs:' + eggs.toString() +',
chocolate:'+ chocolate.toString() +',
price:10, vendor:'+ vendor.toString() +'; '
;document.cookie='cookieshop= '+cookie_value};
I originally thought there was nothing in this as it looks like it’s all hard-coded but there is one what hasn’t been given any name or a value, location. This is seemed out of the ordinary and was either a red-heiring or a loose thread I needed to pull. I pulled it and found some unusual reactions.
There is another JavaScript function called create and it has cookie_spawn inside of it and you can supply input for it. This was the first break through what had me set on using cookie as the attack vector.
function create() { cookie_spawn('eggs','chocolate','https://challenge-0622.intigriti.io/challenge/index.php?choice=cookie26eggs=eggs26chocolate=chocolate','/challenge/index.php?choice=cookieeggs=eggschocolate=chocolate',);
Exploitation
This initially looked very difficult to exploit due to the weird quirks of the input. I would often get the error: challenge not defined, I was running into this often and it was a hard barrier to pass, but the idea of it not being defined rung alarm bells in my head.
I had realised that it was trying to evaluate the path in the location parameter! It was trying to divide challenge / index.php
yet, challenge is undefined and that is the same case with index.
First, I needed to close the list opened by cookie_spawn and break out of the create function, this was needed so I could add the payload and not be trapped in a function where things were being stripped. This is possible by adding a closed bracket, curly brace and a semi-colon. https://challenge-0622.intigriti.io/challenge/index.php?1)};a={//&choice=cookie&nl=\
This is still quite far from working due to an error: missing : in conditional expression. This could be pointing towards a ternary operator what is still a definite way to cause JavaScript to execute, but it isn’t the route I ended up going down.
This made me think about types of JavaScript operators. I would need an operator what would take precedence over the first operation of challenge / index.php.
I spent time researching operators what could be suitable, it needs to include a question mark(?) as that is needed for the query. The question mark is used in:
- ternary operator — This operator is frequently used as an alternative to an
if...else
statement - nullish assignment — Only if the value of x is nullish then the value of y will be assigned to x that means if the value of x is null or undefined then the value of y will be assigned to x.
- nullish coalescing operator — returns its right-hand side operand when its left-hand side operand is
null
so this was my list of possible operators, ternary operator could work, nullish assignment couldn’t work but the nullish coalescing operator look’s more likely to work.
What does the nullish coalescing operator do?
The nullish coalescing operator (??
) is a logical operator that returns its right-hand side operand when its left-hand side operand is null
or undefined
, and otherwise returns its left-hand side operand.
How can this be used?
Both challenge
and index
are undefined what would make this operator perfect for this, and this can be integrated to our payload https://challenge-0622.intigriti.io/challenge/index.php??1)};a={//&choice=cookie&nl=\
we still get challenge not defined.
Finishing
All that is left to do is add the alert(document.domain). https://challenge-0622.intigriti.io/challenge/index.php??1)};alert(document.domain);a={//&choice=cookie&nl=\
function create() { cookie_spawn('eggs','chocolate','https://challenge-0622.intigriti.io/challenge/index.php?1)};a={//26choice=cookie26test=\','/challenge/index.php?1)};a={//choice=cookietest=\',);