PwnMe CTF CTF Quals 2025 - ProfileEditor (WEB)
I couldn’t get the remote flag because I solved it from local after the CTF ended. However, I solved it correctly and got the local flag, so I’m sharing how to access and solve it.
The challenge provided the full source code, making it a white-box web challenge written in Python using Flask.
Analysis
There were 4 endpoints:
/login
: Logs in with a username and password, creating a session./register
: Creates an account with a username and password./profile
: Allows users to view and edit their profile./show_profile
: Displays the profile without allowing edits.
The most interesting endpoint was /show_profile
, as it read the profile directly from a file. Since there was a flag.txt
file on the server, I wanted to exploit it to read the flag using the /show_profile
endpoint.
I didn’t use /profile
because, even though it also reads profile files, it appends .html
to the username when reading the file. So, if my username were flag.txt
, it would attempt to read flag.txt.html
instead. You can see this behavior in the implementation below:
1 | profiles_file = 'profile/' + session.get('username') |
Now, let’s take a look at /show_profile
:
1 |
|
Since the file it reads depends on the username, if the file exists, you can read it. However, as seen in [1], profiles_file
is formatted as profile/username
, meaning you need to use ../
to climb up directories. Since flag.txt
is not in the profile
directory. This is known as Path Traversal
.
Solution Summary
- Register and Log in with the username
../flag.txt
. - Access
/show_profile
, and it will display the contens offlag.txt
.