On this page
Brute-forcing a Stay-Logged-In Cookie
Lab
Brute-forcing a stay-logged-in cookie · Practitioner
Solution
Given
This lab allows users to stay logged in even after they close their browser session. The cookie used to provide this functionality is vulnerable to brute-forcing.
To solve the lab, brute-force Carlos's cookie to gain access to his My account page.
Your credentials: wiener:peter
Victim's username: carlos
Candidate passwords
Analyzing the task
The site has a "stay logged" mechanism whose cookie is vulnerable to brute-forcing. We have an account on the site, so we'll look at how the mechanism works and run a brute-force attack against user carlos.
Recon
We go to the site, there's a login form. Username and password, there's a "Stay logged in" checkbox — we tick it. We log in, a POST login request:
Set-Cookie: stay-logged-in=d2llbmVyOjUxZGMzMGRkYzQ3M2Q0M2E2MDExZTllYmJhNmNhNzcw; Expires=Wed, 01 Jan 3000 01:00:00 UTC
Set-Cookie: session=XaXGwGwLG5aeRpAyJZfClJJuAMavi7ll; Secure; HttpOnly; SameSite=None
We see that the stay-logged-in cookie is stored indefinitely. And it's not protected from JS access at all. If you select the cookie value, Inspector shows the Base64-decoded string by default, which looks like wiener:51dc30ddc473d43a6011e9ebba6ca770.
Obviously the first part is the username, and the second looks like a password hash. The only question is what it's a hash of — the password or something else. As a start, we can just try computing MD5 of password wiener — peter.
In the terminal echo -n 'peter' | md5sum:
51dc30ddc473d43a6011e9ebba6ca770
Match! That means we can build a dictionary brute-force attack. We can fire requests at GET /my-account?id=carlos, having pre-constructed the stay-logged-in cookie.
First let's see how this route behaves if we drop the session cookie and keep only stay-logged-in. It returned 200, and a session cookie was set.
OK, and now with no cookies at all — in that case it returns 302 and redirects to login. We drop the request into Intruder, remove the session cookie, set a variable in the cookie value. What shape will the value have?
- Take MD5 of the candidate password — we were given 100 of them.
- Build the string
carlos:MD5_password. - Base64-encode the resulting string.
Let's write a bash script to generate the payload list:
while read -r pass; do
hash=$(echo -n "$pass" | md5sum | awk '{print $1}')
echo -n "carlos:$hash" | base64
done < passwords.txt > payloads.txt
We drop the candidate passwords from PortSwigger into passwords.txt.
We feed the payloads into Intruder. A 200 came back for the payload:
Cookie: stay-logged-in=Y2FybG9zOjIxYjcyYzBiN2FkYzVjN2I0YTUwZmZjYjkwZDkyZGQ2
Lab solved!
More in this category
Web Shell Upload via Extension Blacklist Bypass (PortSwigger Lab)
.php is blacklisted, but .htaccess uploads without complaint — we slip our own Apache config in and make the server execute shell.bug as PHP.
Web Shell Upload via Obfuscated File Extension (PortSwigger Lab)
Extension blacklist rejects .php and a double-extension shell.php.jpg is served as an image — a null byte in shell.php%00.jpg bypasses both checks.
Remote Code Execution via Web Shell Upload (PortSwigger Lab)
Avatar upload has no validation — drop a PHP web shell and read /home/carlos/secret.