tl;dr
- Intended: Append
; secure; samesite=none
to cookie. Now,<script src="https://jason.2021.chall.actf.co/flags?callback=load"></script>
would retrieve the flag. - Unintended: Append .actf.co as domain to cookie using CSRF -> Setup a xss payload in reaction.py challenge -> Log in to this using CSRF -> Payload in Reaction.py exfiltrates document.cookie
Number of Solves: 41
Points: 180
Solved by: Az3z3l & Captain-Kay
Challenge Description
Jason has the coolest site. He knows so many languages, and he, uh, well… trust me, he’s cool. So cool, in fact, that he claims to be unhackable. He even released his source code!
Downloads: jason.zip
Solution
First Impression
The challenge runs on NodeJS and uses res.jsonp
to send back responses from endpoints. One of the endpoints, /passcode
takes in POST data and appends the value to the cookie. For a secret cookie value(which is set in the admin bot), flag
endpoint returns us the flag. Another thing to note is that there is a referrer check, which checks the referrer and if it is set, it must start with the actual domain name.
Basic Understanding
The referrer is being checked like this,
1 | function sameOrigin (req, res, next) { |
The condition says req.get('referrer') && !req.get('referer').startsWith(process.env.URL)
. So, to bypass this all we need to do is make sure that referrer is not being sent. Coz, in this case, req.get(‘referrer’) would fail and 403 won’t be sent.
res.jsonp
endpoint has a defult endpoint called callback that could be used to get back JSONp data. Using a script tag and an endpoint with jsonp callback, we can retrieve the data.
Soooo,
1 |
|
The Problem:
To retrieve flag, we need to send the passcode cookie to the flag endpoint. The issue is that, with chrome’s latest update, all the cookies are defaulted to lax and this prevents the cookies from being sent cross-site.
Intended Solution
Recent changes in chrome made lax default. Due to this, the cookies dont get sent in cross origin requests. Though Chrome did this, they added some compatibility fixes.
1 | Q: What is the Lax + POST mitigation? |
source : link
Now, all we need to do is append ; secure; samesite=none
to the cookie and then read flag using script tag.
1 | <html> |
1 |
|
Although this method is amazing, we failed to notice this while solving and resorted to an unintended way.
Unintended
This challenge was running on https://jason.2021.chall.actf.co
. And when the cookie was being set, the domain for it, by default is set to the domain recieving the cookie. In this case https://jason.2021.chall.actf.co
. We aren’t allowed to set other domains other than the recieving one, but… we can set cookies for all subdomains of the particular domain. I.e, in this case, by adding ;Domain:.actf.co
, we can set the passcode cookie across all .actf.co
domains.
We don’t have xss in this challenge, but, if we had any on one of the .actf.co
domains, we can exfiltrate the cookie.
There were two more client side challenges in this CTF - Reaction.py, Nomnom (we won’t be using nomnom as the payload works only on FireFox) and they ran on…. .actf.co subdomains \o/
Writeup for reaction.py
-> TBD
The flow to solve this challenge is:
Setup xss payload in reaction.py challenge (This is done on our end before sending link to admin) ->
CSRF to add ;Domain:.actf.co
on payload (Now admin’s passcode would be accessible across all .actf.co domains) ->
Login to your account that has the xss payload in reaction.py
Payloads
1 |
|
1 |
|
1 |
|
Flag
actf{jason’s_site_isn’t_so_lax_after_all}