213 lines
No EOL
7.4 KiB
Python
213 lines
No EOL
7.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Verify MikroTik Access - Reliable Authentication Tester
|
|
Tests if credentials actually work by attempting real operations
|
|
"""
|
|
|
|
import requests
|
|
from requests.auth import HTTPBasicAuth
|
|
import socket
|
|
import time
|
|
|
|
def test_http_with_verification(host, username, password):
|
|
"""Test HTTP auth by trying to access actual protected content"""
|
|
print(f"Testing HTTP: {username}:{password}")
|
|
|
|
try:
|
|
# Try to access WebFig directly (should redirect if authenticated)
|
|
session = requests.Session()
|
|
session.auth = HTTPBasicAuth(username, password)
|
|
|
|
# First, try the main page
|
|
response1 = session.get(f"http://{host}/", timeout=5, allow_redirects=False)
|
|
print(f" Main page status: {response1.status_code}")
|
|
|
|
# Try to access a specific WebFig resource
|
|
response2 = session.get(f"http://{host}/webfig/", timeout=5, allow_redirects=True)
|
|
print(f" WebFig status: {response2.status_code}")
|
|
print(f" Response length: {len(response2.text)}")
|
|
|
|
# Check if we actually got WebFig content (not login page)
|
|
if "webfig" in response2.text.lower() and "login" not in response2.text.lower():
|
|
print(f" ✓ Successfully accessed WebFig interface")
|
|
return True
|
|
elif response2.status_code == 200 and len(response2.text) > 1000:
|
|
print(f" ? Got content but uncertain if authenticated")
|
|
print(f" First 200 chars: {response2.text[:200]}")
|
|
return False
|
|
else:
|
|
print(f" ✗ Authentication failed or no WebFig access")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ✗ HTTP test failed: {e}")
|
|
return False
|
|
|
|
def test_api_with_verification(host, username, password):
|
|
"""Test API auth by attempting actual API operations"""
|
|
print(f"Testing API: {username}:{password}")
|
|
|
|
try:
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.settimeout(5)
|
|
sock.connect((host, 8728))
|
|
|
|
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]) # Error for long strings
|
|
|
|
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:
|
|
# Multi-byte length
|
|
second_byte = sock.recv(1)
|
|
if not second_byte:
|
|
return ""
|
|
length = ((length & 0x7F) << 8) + second_byte[0]
|
|
|
|
if length > 1000: # Sanity check
|
|
return ""
|
|
|
|
return sock.recv(length).decode('utf-8', 'ignore')
|
|
except:
|
|
return ""
|
|
|
|
def read_sentence():
|
|
sentence = []
|
|
while True:
|
|
word = read_word()
|
|
if word == "":
|
|
break
|
|
sentence.append(word)
|
|
return sentence
|
|
|
|
# Send login
|
|
write_sentence(["/login", f"=name={username}", f"=password={password}"])
|
|
|
|
# Read login response
|
|
response = read_sentence()
|
|
print(f" Login response: {response}")
|
|
|
|
if response and response[0] == "!done":
|
|
print(f" ✓ Login successful, testing system identity...")
|
|
|
|
# Try to get system identity to verify we're actually authenticated
|
|
write_sentence(["/system/identity/print"])
|
|
identity_response = read_sentence()
|
|
print(f" Identity response: {identity_response}")
|
|
|
|
if identity_response and any("identity" in str(item).lower() for item in identity_response):
|
|
print(f" ✓ Successfully retrieved system information")
|
|
sock.close()
|
|
return True
|
|
else:
|
|
print(f" ? Login seemed successful but couldn't get system info")
|
|
sock.close()
|
|
return False
|
|
else:
|
|
print(f" ✗ Login failed")
|
|
sock.close()
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ✗ API test failed: {e}")
|
|
return False
|
|
|
|
def test_ssh_with_verification(host, username, password):
|
|
"""Test SSH auth with verification"""
|
|
print(f"Testing SSH: {username}:{password}")
|
|
|
|
try:
|
|
import paramiko
|
|
|
|
client = paramiko.SSHClient()
|
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
client.connect(
|
|
host,
|
|
port=22,
|
|
username=username,
|
|
password=password,
|
|
timeout=5,
|
|
allow_agent=False,
|
|
look_for_keys=False,
|
|
)
|
|
|
|
# Try to execute a command to verify we're authenticated
|
|
stdin, stdout, stderr = client.exec_command("/system identity print")
|
|
output = stdout.read().decode()
|
|
|
|
print(f" Command output: {output[:100]}...")
|
|
|
|
if output and len(output) > 10:
|
|
print(f" ✓ SSH authentication and command execution successful")
|
|
client.close()
|
|
return True
|
|
else:
|
|
print(f" ? SSH connected but no command output")
|
|
client.close()
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ✗ SSH test failed: {e}")
|
|
return False
|
|
|
|
def main():
|
|
host = "10.250.2.2"
|
|
username = "admin"
|
|
|
|
# Test some of the passwords that showed "success" earlier
|
|
test_passwords = [
|
|
"", # Empty
|
|
"0000-0000", # Showed success
|
|
"0000-2018", # Showed success
|
|
"admin", # Common default
|
|
"d069-0bff", # Algorithm result
|
|
]
|
|
|
|
print(f"Verifying MikroTik access to {host}")
|
|
print("=" * 60)
|
|
|
|
for password in test_passwords:
|
|
pwd_display = f'"{password}"' if password else "(empty)"
|
|
print(f"\nTesting password: {pwd_display}")
|
|
print("-" * 40)
|
|
|
|
# Test all methods with verification
|
|
http_result = test_http_with_verification(host, username, password)
|
|
api_result = test_api_with_verification(host, username, password)
|
|
ssh_result = test_ssh_with_verification(host, username, password)
|
|
|
|
if any([http_result, api_result, ssh_result]):
|
|
print(f"\n*** VERIFIED SUCCESS: {pwd_display} ***")
|
|
print(f"HTTP: {'✓' if http_result else '✗'}")
|
|
print(f"API: {'✓' if api_result else '✗'}")
|
|
print(f"SSH: {'✓' if ssh_result else '✗'}")
|
|
return password
|
|
else:
|
|
print(f"All methods failed for {pwd_display}")
|
|
|
|
print(f"\nNo working passwords found among tested candidates.")
|
|
print("The earlier 'successes' were likely false positives.")
|
|
|
|
if __name__ == "__main__":
|
|
main() |