InCTF Internationals 2021 - MD-Notes Write-up
Table of Contents
tl;dr
- Leak admin’s hash using wildcard target origin in postMessage or by calculating
sha256(''). - Create an XSS payload to read
/api/flagand send it to attacker server.
Challenge Author: imp3ri0n
Challenge Points: 1000
#
Introduction
A brief write-up of MD-Notes, web exploitation challenge from InCTF Internationals 2021. The source code of the challenge can be downloaded from here.
We’re provided with a markdown editor and an admin bot. The admin bot visits any link that is provided to it.
#
Initial Analysis 🔎

When a note is previewed, a POST request is made to /api/filter which returns a Hash, sanitized text and raw input. Preview is rendered inside an iframe using the following script.
| |
The preview iframe sends back the filtered input (note that it contains Hash).
To save the post, a request has to be made to /api/create, which contains the hash and raw body. The created post is encoded if the hash does not belong to the admin.
| |
There’s a /_debug endpoint that returns the admin_bucket. There is also /api/flag endpoint which returns the flag if admin token (which is in turn the flag) matches the cookie value.
#
Exploit 💥
From the above observations, we can conclude that:
- We require XSS to read
/api/flag. - XSS is possible only with the admin’s hash.
##
Retrieving the Hash
The admin’s hash can be retrieved in two ways:
- By sending the bot to an attacker controlled website that contains an iframe pointing to /demo and sending a postMessage to it.
| |
- The value of
hashis always equal tosha256('')sinceCONFIG.admin_tokenwill be undefined. That means, the hash will bee3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
##
Creating an XSS payload
Once the hash is retrieved, it is trivial to create a post that contains an XSS payload.
| |
Sending a request as above creates a post in admin’s bucket.
| |
#
Final Payload
exploit.py
| |
exploit.js
| |
#
Flag ✨
| |
Thanks for reading.
Cheers. 🍻