""" MikroTik RouterBoard Password Generator Reverse-engineered password generation algorithm based on MAC address analysis. IMPORTANT DISCOVERY: Two different MAC addresses generate the SAME password: MAC: 18:FD:74:F9:04:FC → Password: c8fd-8bff MAC: 18:FD:74:F9:04:90 → Password: c8fd-8bff The only difference is the last byte (FC vs 90), proving it's NOT used! Pattern discovered: - Only uses first 5 MAC bytes (byte 5 is ignored) - Byte 0: MAC[0] XOR 0xD0 - Byte 1: MAC[1] (direct copy) - Byte 2: NOT(MAC[2]) - Byte 3: 0xFF (constant or derived) WARNING: This is based on reverse engineering two MAC addresses that both produce the same password. More data points would help verify the constants. """ class MikroTikPasswordGenerator: """Generate MikroTik RouterBoard passwords from MAC addresses.""" @staticmethod def parse_mac(mac_address): """ Parse a MAC address string into a list of bytes. Accepts formats like "18:FD:74:F9:04:FC" or "18-FD-74-F9-04-FC" Args: mac_address (str): MAC address string Returns: list: List of 6 integers (0-255) Raises: ValueError: If MAC address format is invalid """ mac_address = mac_address.upper() # Split by colon or dash import re parts = re.split(r'[:-]', mac_address) if len(parts) != 6: raise ValueError(f"Invalid MAC address: {mac_address}. Expected 6 octets.") try: mac_bytes = [int(part, 16) for part in parts] except ValueError: raise ValueError(f"Invalid MAC address format: {mac_address}") return mac_bytes @staticmethod def bitwise_not(byte): """ Bitwise NOT operation (inverts all bits in a byte). Args: byte (int): Byte value (0-255) Returns: int: NOT(byte) as a byte (0-255) """ return byte ^ 0xFF @staticmethod def xor_op(byte, mask): """ XOR operation on a byte with a mask. Args: byte (int): Byte value (0-255) mask (int): XOR mask (0-255) Returns: int: byte XOR mask (0-255) """ return (byte ^ mask) & 0xFF @staticmethod def format_password(pwd_bytes): """ Format password bytes into MikroTik format "XXXX-XXXX". Args: pwd_bytes (list): List of 4 bytes Returns: str: Formatted password like "c8fd-8bff" """ if len(pwd_bytes) != 4: raise ValueError(f"Expected 4 password bytes, got {len(pwd_bytes)}") hex_string = ''.join(f'{byte:02x}' for byte in pwd_bytes) return f"{hex_string[:4]}-{hex_string[4:]}" @staticmethod def generate_password(mac_address): """ Generate a password from a MAC address. Uses only the first 5 bytes of the MAC address (byte 5 is ignored). Algorithm: PWD[0] = MAC[0] XOR 0xD0 PWD[1] = MAC[1] (direct copy) PWD[2] = NOT(MAC[2]) (bitwise NOT) PWD[3] = 0xFF (constant or derived) Args: mac_address (str): MAC address string (e.g., "18:FD:74:F9:04:FC") Returns: str: Generated password (e.g., "c8fd-8bff") Example: >>> gen = MikroTikPasswordGenerator() >>> pwd1 = gen.generate_password("18:FD:74:F9:04:FC") >>> pwd2 = gen.generate_password("18:FD:74:F9:04:90") >>> pwd1 == pwd2 True 'c8fd-8bff' """ mac_bytes = MikroTikPasswordGenerator.parse_mac(mac_address) if len(mac_bytes) != 6: raise ValueError(f"Expected 6 MAC bytes, got {len(mac_bytes)}") # Extract the first 5 MAC bytes (byte 5 is ignored) b0, b1, b2, b3, b4 = mac_bytes[:5] # Generate password bytes based on discovered pattern pwd_byte_0 = MikroTikPasswordGenerator.xor_op(b0, 0xD0) pwd_byte_1 = b1 # Direct copy pwd_byte_2 = MikroTikPasswordGenerator.bitwise_not(b2) # NOT operation pwd_byte_3 = 0xFF # Constant (or possibly derived from b3) pwd_bytes = [pwd_byte_0, pwd_byte_1, pwd_byte_2, pwd_byte_3] # Format as hex string with dash return MikroTikPasswordGenerator.format_password(pwd_bytes) def test(): """ Test the generator with the two known MAC/password pairs. Both MACs should generate the same password. """ mac1 = "18:FD:74:F9:04:FC" mac2 = "18:FD:74:F9:04:90" expected = "c8fd-8bff" gen = MikroTikPasswordGenerator() generated1 = gen.generate_password(mac1) generated2 = gen.generate_password(mac2) print("Testing MikroTik Password Generator") print("=" * 45) print() print("Test 1: First MAC address") print(f" MAC Address: {mac1}") print(f" Expected Password: {expected}") print(f" Generated Password: {generated1}") result1 = generated1 == expected print(f" Result: {'✓ PASS' if result1 else '✗ FAIL'}") print() print("Test 2: Second MAC address (last byte different)") print(f" MAC Address: {mac2}") print(f" Expected Password: {expected}") print(f" Generated Password: {generated2}") result2 = generated2 == expected print(f" Result: {'✓ PASS' if result2 else '✗ FAIL'}") print() # Key insight: both should be the same print(f"Both generate same password: {'✓ YES' if generated1 == generated2 else '✗ NO'}") print(f"Proves last byte is ignored: {'✓ CONFIRMED' if result1 and result2 else '✗ NOT CONFIRMED'}") return result1 and result2 def main(): """Main entry point with example usage.""" import sys print("MikroTik RouterBoard Password Generator") print("=" * 45) print() # Run test test_passed = test() print() # Example usage if len(sys.argv) > 1: mac_address = sys.argv[1] try: gen = MikroTikPasswordGenerator() password = gen.generate_password(mac_address) print(f"MAC: {mac_address}") print(f"Password: {password}") except ValueError as e: print(f"Error: {e}") sys.exit(1) else: print("Usage:") print(" python mikrotik_password.py ") print() print("Examples:") print(" python mikrotik_password.py 18:FD:74:F9:04:FC") print(" python mikrotik_password.py 18-FD-74-F9-04:FC") print() print("Algorithm:") print(" PWD[0] = MAC[0] XOR 0xD0") print(" PWD[1] = MAC[1]") print(" PWD[2] = NOT(MAC[2])") print(" PWD[3] = 0xFF") print() print("Note: Only first 5 MAC bytes are used (byte 5 is ignored)") sys.exit(0 if test_passed else 1) if __name__ == "__main__": main()