Mystic

Intigriti November Challenge 2025 From JWT Forgery to RCE


This write-up details the steps taken to solve the Intigriti November Challenge 2025 , a Web Security challenge focused on achieving Remote Code Execution (RCE). The vulnerability chain exploited was a combination of insecure JWT validation leading to Privilege Escalation, followed by a Server-Side Template Injection (SSTI) vulnerability in the administrative interface.

Goal:

Achieve RCE to find the flag in the format INTIGRITI{.*}.

The challenge rules required leveraging RCE on the challenge , not using self-XSS or MiTM attacks , and requiring no user interaction.


Phase 1 : Reconnaissance & Initial Access

The target application, named AquaCommerce!, presented a standard ecommerce interface with pages for Home, Shop, Cart, Login, and Sign Up.

image

Initial reconnaissance using Dirsearch revealed several key endpoints that required authentication:

image

- /admin (redirecting to /login)
- /dashboard (redirecting to /login)
- /checkout (redirecting to /login)

JWT Forgery and Privilege Escalation

The primary goal of the first phase was to escalate privileges to reach an administrative function that could be exploited for RCE.

Account Registration:

I registered a standard user account (attacker1234) and immediately intercepted the requests using Burp Proxy. The session cookie contained a JWT token.

image

Token Analysis:

Decoding the JWT using FusionAuth JWT Decoder showed that the token used the HS256 algorithm and contained four fields in the payload:

image

Exploiting alg: none Confusion: I tested for the JWT Signature Confusion vulnerability by modifying the token's header.

Original Header: {"alg": "HS256", "typ": "JWT"}

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

By setting the algorithm to "none", the backend was forced to skip signature verification. I simultaneously modified the payload to elevate my privileges

Modified Payload: {"user_id": 4, "username": "attacker1234", "role": "admin", "exp": 1763724828}

image

Privilege Escalation:

I replaced the original JWT token in the browser’s cookie storage with the forged token.

image

Upon refreshing the dashboard, my role was successfully elevated to admin, and the Admin Panel button became accessible.

image

Phase 2: Exploiting SSTI to Achieve RCE

With administrative privileges, I began searching for vulnerable endpoints. I discovered the /admin/profile path, which allowed the display name to be updated via an input field.

image

Server-Side Template Injection (SSTI)

The next step was to test the input field for Server-Side Template Injection (SSTI), which was hinted at by the challenge’s objective to achieve RCE.

Confirmation: I injected the common test payload {{7*7}} into the "Display Name" field.

image

Result: The application displayed the result 49 on the profile page. This confirmed the presence of a vulnerability and indicated that the application was using the Jinja2 template engine (Python).

Achieving Remote Code Execution**

With SSTI confirmed, the path to RCE involved enumerating Python template internals to access OS-level functionality.

{{‘’.class.mro()[1].subclasses()[444].init.globals}}

I used a well-known payload structure, often seen in Jinja2 SSTI exploits, to directly import the os module and execute commands.

Another easier method by referencing an existing SSTI-to-RCE CVE from this GitHub repository.

Command Execution Test: I injected the following payload into the “Display Name” field:

{{ self.__init__.__globals__.__builtins__.__import__(‘os’).popen(‘id’).read()

Output: The command successfully executed, and the output uid=999(appuser) gid=999(appuser) groups=999(appuser) was returned. This confirmed full RCE capability.

image

Retrieving the Flag

The final step was to use the confirmed RCE to locate and read the challenge flag.

Locating the Flag: After directory searching, the flag was found to be stored at /app/.aquacommerce/019a82cf.txt.

image

Final Payload:

The RCE payload was modified to read the contents of the flag file

{{ self.__init__.__globals__.__builtins__.__import__(‘os’).popen(‘cat /app/.aquacommerce/019a82cf.txt ’).read()

Flag Retrieved: The execution successfully retrieved the flag: INTIGRITI{019a82cf-ca32-716f-8291-2d0ef30bea32}


Conclusion

The Intigriti November Challenge 2025 was solved by chaining two critical vulnerabilities:

Insecure JWT validation (JWT alg: none) enabled privilege escalation from user to admin. Server-Side Template Injection (SSTI) in Jinja2 within the newly accessible admin panel was exploited to achieve full Remote Code Execution (RCE), enabling the retrieval of the flag.


References

www.hacktivesecurity.com

https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection/jinja2-ssti

https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2/

https://docs.cobalt.io/bestpractices/prevent-ssti/