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
- Browse to the password reset form at
/reset_step1.php. - Submit victim’s username (no password required at this step).
- Session now has
$_SESSION['Username'] = 'victim'. - Instead of completing the reset, navigate directly to
/profile.php. - The profile page only checks
isset($_SESSION['Username'])— which is true. - 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
- Submit username at step 1 → session has
Username=admin. - Skip step 2 — go directly to step 3:
/reset_3.php. - 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:
- Submit a request to
/upload_avatar.phpwithusername=admin. - Navigate to any page that checks
$_SESSION['current_user']. - 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:
- Start the email verification flow.
- After step 1, navigate directly to
/admin/. $_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:
- Complete step 1 (submit valid username/password).
- 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
- Proxy — intercept every step of multi-step flows; record which session cookie is set and what response comes back.
- Repeater — after step 1 of a reset/MFA flow, send requests to protected pages with the same session cookie before completing subsequent steps.
- Session Handling Rules — configure Burp to re-use session cookies across requests automatically.
- Sequencer — test session ID entropy (see weak-session-ids.md for full workflow).
- Compare
set-cookieresponses in step 1 vs the login flow — are the same variables being used?