Hello everyone, this won't be a "normal" write-up, full of complicated technical terms. Instead, I'd like to talk about my experience (even if little) and how I managed to find my first bug in an Intigriti CTF. I'm writing this especially for those who, like me, struggle to find a bug and want to understand how, and where to look.
Methodology:
As soon as I arrived on the site and logged in with a fake user, I noticed a POST request to the server (the request the site makes when you perform an action) and saw a cookie that looked exactly like a JWT (JSON Web Token).
For those who don't know what a JWT is (and how we tricked it):
In simple terms, it's like a VIP pass that the site gives you to remember who you are. Normally, it has a secret signature at the end so you can't modify it yourself with a marker. But here, The server was overly trusting: we gave it a modified pass saying "Look, this one doesn't need a signature" (alg: none), and blindly, it believed us and threw open the Admin doors.
When you remove the signature part, do not delete the final dot (
.) at the end of the token!
The structure must always remain header.payload. (with the trailing dot). If you delete it, the format becomes invalid and the server will reject it. It's a small detail that drives many people crazy!
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo2LCJ1c2VybmFtZSI6InZpY3RpbSIsInJvbGUiOiJ1c2VyIiwiZXhwIjoxNzYzNTQ1MzI0fQ.OS2PPoI-rj5DFSe4yJTzgUmkSXbZANAynGI20uRHcV4
Decoding it, it looked like this:
{
"alg": "HS256",
"typ": "JWT"
}
{
"user_id": 6,
"username": "victim",
"role": "user",
"exp": 1763545324
}
So very simply I thought: "What if the server accepted the none algorithm?".
Well, trying doesn't hurt, so I modified it: initially, I put admin as the role and changed the algorithm to none... and it worked!
I effectively became admin.
Once I became admin I thought: "Game over! I'm in! I just have to find the flag!".
Well, those were my famous last words before the disaster... It's not exactly that simple.
So I rolled up my sleeves and kept looking until I thought: "What if I put admin as username and 1 as user_id?".
I did that and got into the real administrator account. I could do many things, including entering the admin profile, where I noticed a quite strange field in the request:
POST /admin/profile HTTP/1.1
Host: challenge-1125.intigriti.io
[...]
Cookie: token=eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzYzNTQ1MzI0fQ.
display_name=ss
After a few failed attempts and tests, I managed to find the RCE (Remote Code Execution) that allowed sending commands to the operating system, and it is precisely through this that I found the flag which allowed me to complete the CTF.
But now you are surely asking yourselves "how?". It's very simple in the end: I tried to see what would happen if I wrote {{7*7}} and the site answered 49.
So I can say I found an SSTI (Server-Side Template Injection) vulnerability inside this field.
For those who don't know what an SSTI is:
In simple terms, it happens when a website takes what you write and brutally inserts it into the page code (the template) without checking. It's as if in a form you wrote a math operation and the person reading the form, instead of reading the numbers, did the calculation. Only here, instead of calculations, you can make it execute server commands!
Without further ado, I found a payload that imported os in Python and used it:
POST /admin/profile HTTP/1.1
Host: challenge-1125.intigriti.io
[...]
Cookie: token=eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzYzNTQ1MzI0fQ.
display_name={{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
Sending this POST, the output of the id command appeared inside that field, showing the user I was logged in as inside the operating system.
Now only the flag is missing, which I leave for you to find for fun.
I write this write-up to be helpful and inspiring to those who, like me, are having trouble finding their first bug.
Read the full Write-up on MediumHappy Hacking! 🚩