Portswigger Labs
Lab 1: Username Enumeration
To solve this lab, brute force the credentials with the given wordlists to login.
This website shows 'Invalid username` when an invalid username is used:
I scripted this entire process. First, I brute forced the username to find that archie
was valid.
Afterwards, brute force the password based on the fact that 'Incorrect password' is printed on the screen:
zxcvbn
is the correct password. This script auto-solves the lab.
Lab 2: 2FA Bypass
This lab gives us valid credentials, and requires us to bypass the 2FA to solve the lab. I have access to an email client for this lab.
When logging in using wiener
credentials, I can see that I am emailed a code:
This is used for the 2FA mechanism:
I noticed that when logging in with carlos
creds, I saw this GET request to /login2
:
The above led to the 2FA portion. I dropped this request, and directly visited /my-account?id=carlos
. This solved the lab!
Lab 3: Broken Password Reset
This lab has a password reset feature that's broken. This requires a username / email:
Submitting that results in this email:
This brought me here:
When submitted, it resulted in a POST request being sent, and it had a username
parameter:
I changed the username
to carlos
, and could login with the password of test
which I specified.
Lab 4: Username Enum using Subtly different responses
This lab requires us to brute force again, but this time the condition for a valid username results in a subtly different response.
Entering random creds results in the same error:
For this case, I used the same brute force script, but this time I outputted the response text into a file and then compared it when the next request.
This would ensure that I capture every difference. I copied the HTML from a request into a sample.txt
.
However, this method didn't really work since each of the responses had a different ID for analytics purposes:
In this case, I opted to compare the error message of each file:
This can be done using a simple regex check to see if the string exists on the page:
The above would return a different result for the atlas
user, which I manually verified:
The above message does not have a fullstop, and as such I could find a valid user and solve the lab:
Lab 5: Response Timing Enumeration with Brute Force Bypass
When testing with a valid user wiener
, the length of the password entered changes the response time.
With a short password it takes 389 ms. With a much longer password, it takes longer!
A few attempts causes this error message to appear though:
This can be bypassed using the X-Forwarded-For
header. Using this, I can create a script to enter a really long password, and check the response time. If I get blocked, I can just modify the X-Forwarded-For
header to bypass the IP ban.
I used a really long password to get a very long response time. Here's the find_user
function:
This would find the usename affiliate
. From here, the find_password
function is similar. Note that this uses 192.168.2.0/24
now.
When find_password
exits, the lab will be solved.
Lab 6: Brute Force Protection Bypass
This lab has a similar protection to the previous lab, except that now there is no X-Forwarded-For
header to use. This time, the lab gave us the valid username of carlos
.
When I tried 3 times, it blocked me:
I tried again, and this time before my third try, I logged into the wiener
account. This reset the number of tries I had, and I could continue after logging out.
This script was pretty easy to code.
Lab 7: Username Enumeration via Account Lock
This lab has account locking, but contains a logic flaw. To solve the lab, login as the valid user.
Based on the lab hint, I expected that brute force attempts would eventually block my account, but that was not the case with the random usernames I was using.
My guess was that repeated attempts with the valid username would result in me getting blocked.
As such, I created a script to send 5 requests per username, and check whether the response contained the Invalid username or password
error.
This would return a different response for the alabama
user:
When checking the response, I saw that it displayed the account lockout error:
Now, time to brute force the password. While I could make the script sleep for 61s after encountering account lockout, that would take too long. Instead, I tried to brute force the password by checking whether the Invalid username
and You have many too many incorrect login attempts
errors were present.
This worked! Here's the final script to solve the lab:
Lab 8: 2FA Broken Logic
This lab has vulnerable 2FA logic. When taking a look at the login process for the wiener
user, I saw this:
It seems that the page with the 2FA logic has a verify
cookie that looks exploitable.
There's also a GET request with the same parameters:
I also noticed that the 2FA feature did not have any brute force protection, and I was free to try this as many times as I wanted. Resending the GET request generates another 2FA code.
There seemed to be no other way of getting credentials, so I scripted the following:
Send a GET request to
login2
to generate the 2FA code forcarlos
.Brute force all 4 digit numbers.
This script will solve the lab...eventually.
Lab 9: Stay-Logged-In Cookie
This lab has a vulnerable stay logged in cookie. For this, I have to do brute forcing of the password for carlos
.
When I logged in as wiener
and chose to stay logged in, there was a cookie passed:
A quick check on CrackStation reveals that this hash was an MD5 hash for peter
.
I can quickly create a brute force script for this, since I can attempt to access carlos
account using this cookie.
The script above solves the lab.
Lab 10: Offline password cracking
To solve this lab, delete carlos
account. T his lab contains an XSS in the comment section, and I am given an exploit server.
Tested the XSS:
And found that it works:
Now, I need to set the URL to the exploit server's, and steal the user's cookie via document.cookie
.
I used this payload:
And received the callback immediately:
The stay-logged-in
cookie can be decoded using base64
:
And the hash can be cracked on CrackStation:
Log in as carlos
and delete the account to solve the lab.
Lab 11: Password Reset Poisoning via Middleware
I'm given an exploit server with an email account. The carlos
user also clicks on any links received. To solve the lab, log in as carlos
.
I sent a password reset email to myself:
The POST request for this is rather interesting. Repeating the request sends another email.
I tampered with the request, and played around with it. I read through all the headers in the Mozilla documentation, and found that X-Forwarded-Host
had some interesting effects.
I changed the value to test.com
.
So I can change the host. This header is used to identify the original host requested by the client in the Host
HTTP request header.
Since the user does not check the URL, I can redirect carlos
to the exploit server by setting the header to the exploit server URL.
In the request, change the username
parameter to carlos
. In the access log, I will see this after sending the POST request.
I can then use the temp-password-token
to reset the password for carlos
.
Lab 12: Password Brute Force via Password Change
This lab has a vulnerable reset password feature. Logging in as wiener
shows this:
Using this feature sends a POST request:
This returns a redirect to /login
if I use a bogus current-password
. Using the correct current-password
results in a 200 being returned with this page:
I can change the username
to carlos
and attempt to brute force this password. However, this method does not work.
I noticed that when I used the correct current password, but different values for new-password-1
and new-password-2
, this error is displayed:
When I used the wrong current password, it shows this instead:
That's a pretty easy vulnerability to script and exploit:
Lab 13: Multiple Creds per Request
To solve this lab, access the account of carlos
. This lab uses JSON to send its login credentials:
For this, the lab tells us 'multiple credentials'. Similar to PHP, one can attempt to send an array in as the password instead of having a single string.
Sending an array does not trigger any funny errors:
Sending multiple passwords raises no errors, and so I created an array with ALL the possible passwords.
This returned a 302:
Repeating the request in the browser solves the lab!
Lab 14: 2FA Brute Force Bypass
This lab gives me carlos
credentials, but has a faulty 2FA mechanism. Attempting to login requires a 2FA code:
The 3 main requests sent are:
When entering false codes, I have 2 tries before it sends me back to the /login
page.
One attack path is logging in at /login
, then sending a GET request to /login2
. Afterwards, I can try brute-forcing the POST request to /login2
. If I get kicked out, I can just reset the 'setup' process:
This lab eventually solves the lab!
Last updated