Skip to content

Fix Session Management 5: forgeable password-reset token - #345

Closed
beanbeah wants to merge 1 commit into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/r2-challenge-challenge-19-session-mgmt-5
Closed

beanbeah wants to merge 1 commit into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/r2-challenge-challenge-19-session-mgmt-5

Conversation

@beanbeah

@beanbeah beanbeah commented Aug 9, 2026

Copy link
Copy Markdown

Fixes Challenge-19-Session-Mgmt-5 (A07 - Identification and Authentication Failures).

Vulnerability: SessionManagement5SetToken claimed to email a password-reset token but never
actually generated or stored one server-side, and SessionManagement5ChangePassword validated the
submitted resetPasswordToken purely by base64-decoding it into a timestamp and checking that the
timestamp was "recent" (within 10 minutes) - no server-side secret or randomness was ever involved.
Since the token was entirely self-describing (just the current time, base64'd), any attacker could
forge a valid token for any username - including admin - purely from their own clock, without ever
receiving a real reset email, then use it to set that user's password and log in.

SessionManagement5 (the login handler) also only verified the submitted password when a prior,
password-less username lookup already returned the admin role - any other role was granted a signed
in "Pleb" session without the password ever being checked. That's not directly key-granting, but it's
the same missing-authentication-order class of bug living in the same file, so it's tightened as part
of the same fix.

Fix:

  • SessionManagement5SetToken now generates a real cryptographically random per-user token
    (SecureRandom, 32 bytes) and records it server-side (with issue time) the moment a reset is
    requested for an existing user - nothing about the token is derivable from the client-visible
    timestamp anymore.
  • SessionManagement5ChangePassword now requires the exact previously-issued token for that user
    name (constant-time compared), still enforces the original 10-minute freshness window, and
    consumes (single-uses) the token on both success and expiry so it can't be replayed.
  • SessionManagement5 now checks the password on every login attempt before trusting the looked-up
    role, instead of only for rows that already resolved to admin.

Local verification (WSL, full docker-compose Tomcat+MariaDB+Mongo stack built from this branch):

  • mvn -o compile is clean.
  • Built and booted the full stack, registered/logged in as a normal player, and hit the deployed
    servlets over real HTTP:
    • Forging the pre-patch exploit token (Base64(current timestamp)) for userName=admin and
      POSTing it to .../ChangePass is now rejected ("Token is invalid").
    • The legitimate flow works end-to-end: requesting a reset via .../SendToken issues a real
      server-side token; submitting that exact token to .../ChangePass succeeds, and logging in to
      the sub-app with the new password then returns the admin result key.
    • The token is single-use: replaying the same (already-redeemed) token is rejected.
    • Sub-app login still correctly reports "user not found" for unknown usernames.

Files changed:

  • src/main/java/servlets/module/challenge/SessionManagement5.java
  • src/main/java/servlets/module/challenge/SessionManagement5ChangePassword.java
  • src/main/java/servlets/module/challenge/SessionManagement5SetToken.java

SessionManagement5SetToken claimed to email a reset token but never
generated or stored one; SessionManagement5ChangePassword accepted
any base64'd timestamp within the last 10 minutes as valid, so an
attacker could forge a token for any user (including admin) purely
from their own clock, with no server interaction required.

- SessionManagement5SetToken now issues a real SecureRandom token
  per user and records it server-side with an issue time.
- SessionManagement5ChangePassword now requires that exact token
  (constant-time compared), keeps the 10-minute freshness window,
  and consumes the token on success or expiry (single use).
- SessionManagement5 now verifies the password for every login
  attempt before trusting the looked-up role, instead of only when
  the role lookup already resolved to admin.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🏆 Security Shepherd — CTF Patch Score

█░░░░░░░░░░░░░░░░░░░  3 / 79 pts  (4%)

1 / 40 challenges patched

Per-challenge detail is withheld — it would reveal the rubric.

Commit: 9a4f22b · scoring run

🎉 Your result is on the leaderboard — see where you rank! 🏆

@beanbeah

beanbeah commented Aug 9, 2026

Copy link
Copy Markdown
Author

Closing as part of a full stand-down of this CTF push.

@beanbeah beanbeah closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant