#!/usr/bin/env python3 """Read-only RouterOS API dump. Empty password login.""" import socket import sys HOST = "192.168.88.1" PORT = 8728 USER = "admin" PASSWORD = "" def encode_len(n: int) -> bytes: if n < 0x80: return bytes([n]) if n < 0x4000: n |= 0x8000 return bytes([(n >> 8) & 0xFF, n & 0xFF]) if n < 0x200000: n |= 0xC00000 return bytes([(n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF]) n |= 0xE0000000 return bytes([(n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF]) def write_word(sock: socket.socket, word: str) -> None: b = word.encode("utf-8") sock.sendall(encode_len(len(b)) + b) def write_sentence(sock: socket.socket, words: list[str]) -> None: for w in words: write_word(sock, w) sock.sendall(b"\x00") def read_len(sock: socket.socket) -> int: c = sock.recv(1) if not c: raise ConnectionError("closed") n = c[0] if (n & 0x80) == 0: return n if (n & 0xC0) == 0x80: n &= ~0xC0 b = sock.recv(1) return (n << 8) + b[0] if (n & 0xE0) == 0xC0: n &= ~0xE0 b = sock.recv(2) return (n << 16) + (b[0] << 8) + b[1] raise RuntimeError("len too big") def read_word(sock: socket.socket) -> str: n = read_len(sock) if n == 0: return "" data = b"" while len(data) < n: chunk = sock.recv(n - len(data)) if not chunk: raise ConnectionError("closed") data += chunk return data.decode("utf-8", "replace") def read_sentence(sock: socket.socket) -> list[str]: words = [] while True: w = read_word(sock) if w == "": break words.append(w) return words def talk(sock: socket.socket, words: list[str]) -> list[list[str]]: write_sentence(sock, words) out = [] while True: s = read_sentence(sock) if not s: break out.append(s) if s[0] in ("!done", "!trap", "!fatal"): break return out def fmt(replies: list[list[str]]) -> str: lines = [] for s in replies: lines.append(" ".join(s)) return "\n".join(lines) def main() -> None: sock = socket.create_connection((HOST, PORT), 8) # RouterOS 6.43+ login r = talk(sock, ["/login", f"=name={USER}", f"=password={PASSWORD}"]) print("LOGIN", fmt(r)) chal = None for s in r: for w in s: if w.startswith("=ret="): chal = w[5:] if chal: import hashlib, binascii h = hashlib.md5() h.update(b"\x00" + PASSWORD.encode() + binascii.unhexlify(chal)) r = talk(sock, ["/login", f"=name={USER}", "=response=00" + h.hexdigest()]) print("LOGIN2", fmt(r)) cmds = [ ["/system/resource/print"], ["/system/identity/print"], ["/interface/print"], ["/ip/address/print"], ["/ip/route/print"], ["/ip/dhcp-client/print"], ["/ip/dhcp-server/print"], ["/ip/firewall/nat/print"], ["/ip/hotspot/print"], ["/ip/hotspot/profile/print"], ["/interface/bridge/print"], ["/interface/bridge/port/print"], ["/ppp/profile/print"], ["/interface/pppoe-server/server/print"], ["/ip/service/print"], ["/system/package/print"], ] for cmd in cmds: print("\n====", cmd[0], "====") try: print(fmt(talk(sock, cmd))) except Exception as e: print("ERR", e) sock.close() if __name__ == "__main__": main()