Introduction
Try to access the content of the admin user’s secret note.
Solution
The challenge is a blog with authentication.
On the homepage, we can see several posts from different users, and in the header, it says A community of 8 authors
.
By clicking on the name of one user, for example, lolo
, who is the author of the first article, we are taken to the user’s profile page.
Non-essential note for exploiting the challenge: After launching multiple instances, I realized that the 8 users are always the same: admin, bob, alice, and 5 other random users (lolo, tata, toto, …).
The URL of this page is /author/:id
, where :id
is the user’s ID.
Here, the user lolo
has the ID 23
.
By making a curl request to the /author/0
endpoint, we can see in the response that there is a redirection because the user was not found.
|
|
On the other hand, a curl request to the /author/23
endpoint gives us the profile of the user lolo
.
|
|
Based on this information, I performed several commands to test the authors’ IDs from 0 to 50 and display a result if the user exists.
|
|
We found the user admin
with the ID 17
accessible at the URL /author/17
.
Now, we might be able to find the flag in the profile of the user admin
since on a user’s profile page, we can see their posts.
Bingo! We see the post Secret blog post (draft)
with the description: Secret post!!
Unfortunately, clicking on the post gives us an error message: You cannot view the drafts of other users
.
Looking into the provided challenge sources, I tried to understand how post display is handled.
I found this function in the routes.py
file:
|
|
We can see that if the post is a draft and the user is not authenticated or the user is not the author of the post, we are redirected to the homepage.
Therefore, on this endpoint, we must be authenticated and be the author of the post to be able to view it. This means we need to be admin to see the post.
After spending an evening trying to find a way to access the admin account, I reconsidered the challenge description:
Try to access the content of the admin user’s secret note.
For me, the flag is in the post Secret blog post (draft)
since we are in challenge Blogodogo 1/2
, and the challenge Blogodogo 2/2
would be to find a way to access the admin account (that’s my thoughts).
So I looked for a way to view the content of the post without using the /post/:slug
endpoint and without needing to be logged in.
Digging into routes.py
, I found this function:
|
|
With this endpoint, we can view the content of a post by passing the post’s hash as the hash_preview
parameter.
To read the post Secret blog post (draft)
, we need to find the hash of the post.
So, let’s understand how the hash is generated. In the routes.py
file, we have the POST /add
route that allows creating a new post:
|
|
We can see that the hash is generated by the generate_hash()
function in utils.py
:
|
|
When a post is created, the hash is generated using the generate_hash()
function without any parameter, which means the hash is generated with the current timestamp.
A timestamp is a number that represents the number of seconds elapsed since January 1, 1970, at midnight UTC.
To generate the hash of the Secret blog post (draft)
, we need to use the timestamp of the post’s creation date, which is displayed on the admin user’s profile page.
The post was created on 2023-05-13
at 02:53
, but we don’t know the exact time (missing seconds).
So, we need to test all the timestamps between 2023-05-13 02:53:00
and 2023-05-13 02:53:59
to find the correct one.
First, I converted the date to a timestamp using the website https://www.epochconverter.com/, which gave me 1683946380
for 2023-05-13 02:53:00
.
|
|
Then, I wrote a Python script to test all the timestamps between 1683946380
and 1683946380 + 59
:
|
|
Using these timestamps, I generated the corresponding hashes using the generate_hash()
function from utils.py
:
|
|
I copied the hashes into a file named hashes.txt
.
|
|
Next, I used curl
to test all the hashes:
|
|
This will iterate through each hash in hashes.txt
and make a request to the preview endpoint. If the response doesn’t contain the string “Redirecting…”, it means we found a working hash.
Let’s try to view the content of the Secret blog post (draft)
using the hash 20030b5d29001f7856c0e7e034e00b8b715d24237f67cf2ea6ec34faee3bb08b
:
|
|
We find the flag Hero{pr3333vi333wwwws_5973791}
.
And the referral code 83d99a0ac225079db31b44a2e58b19f0
that allows us to register on the site for the next challenge, Blogodogo #2
.
Tips & Tricks
- Check all available routes as soon as you have access to the challenge’s source code or if there is a swagger documentation.
- Always review hash creation functions, as most of the time, if it is poorly implemented, it can be easily cracked or reversed.
- Automate testing as soon as possible. In many cases, with a single bash command, you can achieve the equivalent of several hours of manual testing.