Web

Session Puzzling (Session Variable Overloading)

Session puzzling: exploit session variable reuse across auth and non-auth flows to bypass authentication, skip steps, achieve account takeover, and exploit premature session population. CWEE module 6 core topic.

What is Session Puzzling

Session puzzling (also called session variable overloading) occurs when an application uses the same session variable for multiple purposes in different workflows. For example, a Username session variable is populated during both login AND during a password reset flow — even before the user proves they control the account.

An attacker who can populate the session variable through a low-security path can access functionality that checks the same variable for authentication.


Detection

Step 1 — Map all multi-step flows

Identify flows that set session variables across multiple steps:

  • Password reset (step 1: username → step 2: security question → step 3: new password)
  • Multi-factor auth (step 1: password → step 2: OTP → step 3: logged in)
  • Registration (step 1: personal info → step 2: email verify → step 3: active account)
  • Checkout (step 1: cart → step 2: shipping → step 3: payment)

Step 2 — Track what each step sets in session

In Burp Proxy, intercept requests in each step. Use Burp Engagement Tools → Compare site maps or manually trace which session variables are set at each step.

Key question: Is a privileged session variable set before the user completes all security checks?

Step 3 — Test step-skipping

After completing step 1 of a flow (username submission), directly access a protected resource that should require full authentication:

GET /profile.php
Cookie: PHPSESSID=SESSION_FROM_STEP_1

If the protected page loads → the session variable set in step 1 is sufficient for authentication → session puzzling confirmed.


Exploit 1: Authentication Bypass via Password Reset

Vulnerable code pattern

// reset_step1.php — just sets Username in session
$_SESSION['Username'] = $_POST['username'];

// profile.php — checks Username in session (same variable login also sets)
if (!isset($_SESSION['Username'])) { redirect('/login'); }
echo "Welcome, " . $_SESSION['Username'];

Attack flow

  1. Browse to the password reset form at /reset_step1.php.
  2. Submit victim’s username (no password required at this step).
  3. Session now has $_SESSION['Username'] = 'victim'.
  4. Instead of completing the reset, navigate directly to /profile.php.
  5. The profile page only checks isset($_SESSION['Username']) — which is true.
  6. You are now authenticated as the victim without their password.

In Burp Repeater:

POST /reset_step1.php HTTP/1.1
Cookie: PHPSESSID=ATTACKER_SESSION

username=admin

Then immediately:

GET /profile.php HTTP/1.1
Cookie: PHPSESSID=ATTACKER_SESSION

Exploit 2: Skipping Security Question (Step Skip)

Vulnerable flow

  • Step 1 (/reset_1.php): submit username → sets $_SESSION['Username']
  • Step 2 (/reset_2.php): answer security question → sets $_SESSION['verified'] = true
  • Step 3 (/reset_3.php): enter new password → requires $_SESSION['Username'] only

If step 3 only checks for Username (not verified):

Attack flow

  1. Submit username at step 1 → session has Username=admin.
  2. Skip step 2 — go directly to step 3: /reset_3.php.
  3. If step 3 only requires Username → submit a new password for admin without answering the security question.

Exploit 3: Account Takeover via Session Variable Pollution

If the session is shared between an authenticated user and reset flows, an attacker can pollute the victim’s session:

Scenario: Shared session on profile picture upload

// upload_avatar.php — sets Username from POST data without checking auth
$_SESSION['current_user'] = $_POST['username'];

Attack:

  1. Submit a request to /upload_avatar.php with username=admin.
  2. Navigate to any page that checks $_SESSION['current_user'].
  3. The session now identifies you as admin.

Exploit 4: Premature Session Population

The application sets privileged session data before completing verification:

// verify_email.php — step 1 of 2
$_SESSION['role'] = 'admin';  // Set prematurely!
// step 2 would verify email — but never required
redirect('/verify_email_step2.php');

Attack:

  1. Start the email verification flow.
  2. After step 1, navigate directly to /admin/.
  3. $_SESSION['role'] = 'admin' is already set → admin access granted.

Exploit 5: MFA Bypass via Session Sharing

// login.php (step 1) — password check
if (password_verify($pass, $hash)) {
    $_SESSION['Username'] = $username;
    redirect('/mfa.php');
}

// mfa.php (step 2) — OTP check
if ($_POST['otp'] == $_SESSION['otp']) {
    $_SESSION['authenticated'] = true;
}

// dashboard.php — checks Username only
if (!isset($_SESSION['Username'])) { redirect('/login'); }

Since dashboard.php only checks Username (set at step 1), skip step 2:

  1. Complete step 1 (submit valid username/password).
  2. Navigate directly to /dashboard.php — skip the MFA step entirely.

Exploit 6: Logout Bypass (Session Not Destroyed)

If logout sets the session variable to null/0 instead of destroying the session:

// Vulnerable logout
$_SESSION['Username'] = 0;   // just clears — doesn't destroy

// Protected page check
if (!isset($_SESSION['Username'])) { redirect('/login'); }
// isset(0) === true in PHP → bypasses!

Set $_SESSION['Username'] = 0 and then access protected pages — isset() returns true for 0.


Burp Suite workflow

  1. Proxy — intercept every step of multi-step flows; record which session cookie is set and what response comes back.
  2. Repeater — after step 1 of a reset/MFA flow, send requests to protected pages with the same session cookie before completing subsequent steps.
  3. Session Handling Rules — configure Burp to re-use session cookies across requests automatically.
  4. Sequencer — test session ID entropy (see weak-session-ids.md for full workflow).
  5. Compare set-cookie responses in step 1 vs the login flow — are the same variables being used?