haadi@portfolio:~$ cat old-sessions.md
CTF writeup · picoCTF 2025
Old Sessions
Session hijacking made trivial: sessions that never expire, and an endpoint that lists everyone's tokens, including the admin's.
Challenge Description
Proper session timeout controls are critical for securing user accounts. If a user logs in on a public or shared computer but doesn't explicitly log out, and session expiration dates are misconfigured, the session may remain active indefinitely. This allows an attacker using the same browser later to access the user's account without needing credentials.
First Look
Launched the challenge instance and opened the website. My first step was just to interact with it normally: registered an account and logged in to see what the application looked like.
The home page showed a comments section. One comment stood out immediately:
it mentioned that there was a static page at /sessions.
That was a clear hint. I navigated to http://[challenge-ip]/sessions.
Exploring /sessions
The /sessions page listed active user sessions on the server. This is
already a serious vulnerability on its own: an application should never
expose its session list to any logged-in user.
Looking through the list, I could see multiple users with active sessions,
including one for admin. The page showed each user's session cookie value
alongside their username.
The description mentioned "sessions never expire", and that was exactly what I was looking at. These sessions had been sitting active indefinitely, including the admin's.
Stealing the Admin Session
I now had the admin's session cookie value. The question was how to use it.
Sessions work like this: when you log in, the server gives your browser a cookie. On every subsequent request, your browser sends that cookie back and the server says "I recognize this cookie: you're logged in as [user]." The server doesn't check your username or password again. It just checks the cookie.
So if I replace my session cookie with the admin's, the server will think I am the admin.
How I did it:
- Went back to the home page
- Right-clicked → Inspect → clicked the
>>arrow on the top navigation bar → selected Application - In the left sidebar, expanded Cookies and clicked on the site's URL
- Found my session cookie: a key-value pair where the value was my session token
- Double-clicked the value field and replaced my cookie value with the admin's session token I found on
/sessions - Refreshed the page
The page reloaded and I was now logged in as admin. The flag was displayed on the admin home page.
What This Vulnerability Is
This is called Session Hijacking: specifically made possible here by two compounding vulnerabilities:
Vulnerability 1: Sessions never expire. The admin session had been active indefinitely. A properly configured application expires sessions after a period of inactivity (typically 15 to 30 minutes for sensitive applications). Here, nothing expired.
Vulnerability 2: Session tokens were publicly visible.
The /sessions page exposed every user's session token to any authenticated
user. Even if sessions had proper expiration, this endpoint alone would be
a critical vulnerability. Session tokens must be kept secret: they are
effectively passwords.
What a Developer Should Do
- Set session expiration: both absolute (e.g. 8 hours max) and idle (e.g. 15 minutes of inactivity)
- Never expose session tokens to any user, including authenticated ones
- Regenerate session tokens on privilege escalation (e.g. after login)
- Use
HttpOnlyandSecureflags on session cookies so JavaScript cannot read them and they only transmit over HTTPS
What I Learned
Before this challenge I understood cookies conceptually. This was the first
time I actually modified a cookie in DevTools and saw the server accept it.
The /sessions endpoint making it trivial was the point: in a real
application, an attacker who somehow obtained a valid session token through
any other means (XSS, network sniffing, a log exposure) would do exactly
this same step. The vulnerability here is the exposure, not the browser tool.
Flag
picoCTF{s3t_s3ss10n_3xp1rat10n5_efbf6d5f}
Originally published on GitHub
view-source