def setDc(self, dataCont): if isinstance(dataCont, dc): self._dc = dataCont else: msg = "Invalid call to fuzzableRequest.setDc(), the argument must be a" msg += " dataContainer instance." raise w3afException(msg)
def is_private_site(domain_or_IP_address): ''' @parameter domain_or_IP_address: The domain or IP address that we want to check @return: Get the IP address of the domain, return True if its a private address. ''' if re.match('(10\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(172\.[1-3]\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(192\.168\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(127\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address): return True else: addrinfo = None try: addrinfo = socket.getaddrinfo(domain_or_IP_address, 0) except: raise w3afException('Could not resolve hostname: ' + domain_or_IP_address) else: ip_address_list = [info[4][0] for info in addrinfo] for ip_address in ip_address_list: if re.match('(10\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(172\.[1-3]\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(192\.168\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(127\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address): return True return False
def getParams(self, ignoreExceptions=True): ''' Parses the params string and returns a dict. @return: A QueryString object. >>> u = url_object('http://abc/xyz.txt;id=1?file=2') >>> u.getParams() {'id': '1'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?file=2') >>> u.getParams() {'id': '1', 'file': '2'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?spam=2') >>> u.getParams() {'id': '1', 'file': '2'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?spam=3') >>> u.getParams() {'id': '1', 'file': '2'} ''' parsedData = None result = {} if self.hasParams(): try: parsedData = cgi.parse_qs(self.params, keep_blank_values=True, strict_parsing=True) except Exception, e: if not ignoreExceptions: raise w3afException( 'Strange things found when parsing params string: ' + self.params) else: for i in parsedData.keys(): result[i] = parsedData[i][0]
def is_private_site( domain_or_IP_address ): ''' @parameter domain_or_IP_address: The domain or IP address that we want to check @return: Get the IP address of the domain, return True if its a private address. ''' if re.match('(10\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(172\.[1-3]\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(192\.168\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address) or\ re.match('(127\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', domain_or_IP_address): return True else: addrinfo = None try: addrinfo = socket.getaddrinfo(domain_or_IP_address, 0) except: raise w3afException('Could not resolve hostname: ' + domain_or_IP_address ) else: ip_address_list = [info[4][0] for info in addrinfo] for ip_address in ip_address_list: if re.match('(10\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(172\.[1-3]\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(192\.168\.\d?\d?\d?\.\d?\d?\d?)', ip_address) or\ re.match('(127\.\d?\d?\d?\.\d?\d?\d?\.\d?\d?\d?)', ip_address): return True return False
def setDc(self, dataCont): if isinstance(dataCont, dc): self._dc = dataCont else: msg = 'Invalid call to fuzzableRequest.setDc(), the argument must be a' msg += ' dataContainer instance.' raise w3afException(msg)
def createRandNum(length=0, excludeNumbers=[]): ''' Create a random string ONLY with numbers @return: A random string only composed by numbers. >>> x = createRandNum( length=1 ) >>> int(x) in range(10) True >>> x = createRandNum( length=2 ) >>> int(x) in range(100) True >>> x = createRandNum( length=3 ) >>> int(x) in range(1000) True ''' if length == 0: jibber = ''.join([digits]) ru = ''.join([choice(jibber) for x in range(randint(10, 30))]) else: jibber = ''.join([digits]) ru = ''.join([choice(jibber) for x in range(length)]) if int(ru) in excludeNumbers: try: return createRandNum(length, excludeNumbers) except: # a recursion exceeded could happend here. raise w3afException('Failed return random number.') return ru
def createRandNum( length=0, excludeNumbers=[] ): ''' Create a random string ONLY with numbers @return: A random string only composed by numbers. >>> x = createRandNum( length=1 ) >>> int(x) in range(10) True >>> x = createRandNum( length=2 ) >>> int(x) in range(100) True >>> x = createRandNum( length=3 ) >>> int(x) in range(1000) True ''' if length == 0: jibber = ''.join([digits]) ru = ''.join([choice(jibber) for x in range(randint(10, 30))]) else: jibber = ''.join([digits]) ru = ''.join([choice(jibber) for x in range(length)]) if int(ru) in excludeNumbers: try: return createRandNum( length, excludeNumbers ) except: # a recursion exceeded could happend here. raise w3afException('Failed return random number.') return ru
def getParams( self, ignoreExceptions=True ): ''' Parses the params string and returns a dict. @return: A QueryString object. >>> u = url_object('http://abc/xyz.txt;id=1?file=2') >>> u.getParams() {'id': '1'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?file=2') >>> u.getParams() {'id': '1', 'file': '2'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?spam=2') >>> u.getParams() {'id': '1', 'file': '2'} >>> u = url_object('http://abc/xyz.txt;id=1&file=2?spam=3') >>> u.getParams() {'id': '1', 'file': '2'} ''' parsedData = None result = {} if self.hasParams(): try: parsedData = cgi.parse_qs( self.params, keep_blank_values=True, strict_parsing=True) except Exception, e: if not ignoreExceptions: raise w3afException('Strange things found when parsing params string: ' + self.params) else: for i in parsedData.keys(): result[ i ] = parsedData[ i ][0]
def setModValue( self, val ): ''' Set the value of the variable that this mutant modifies. ''' try: self._freq._cookie[ self.getVar() ][ self._index ] = val except Exception, e: raise w3afException('The cookie mutant object wasn\'t correctly initialized.')
def getModValue( self ): try: return self._freq._dc[ self.getVar() ][ self._index ] except: msg = 'The mutant object wasn\'t correctly initialized. Either the variable to be' msg += ' modified, or the index of that variable are incorrect. This error was' msg += ' found in mutant.getModValue()' raise w3afException( msg )
def setModValue(self, val): ''' Set the value of the variable that this mutant modifies. ''' try: self._freq._cookie[self.getVar()][self._index] = val except Exception, e: raise w3afException( 'The cookie mutant object wasn\'t correctly initialized.')
def equal( self, body1, body2 ): ''' Determines if two pages are equal using some tricks. ''' if self._equAlgorithm == 'setIntersection': return self._setIntersection( body1, body2) elif self._equAlgorithm == 'stringEq': return self._stringEq( body1, body2) raise w3afException('Unknown algorithm selected.')
def _analyzeResult(self, mutant, res): ''' Analyze the result of sending the mutant to the remote web server. @parameter mutant: The mutated request. @parameter res: The HTTP response. ''' msg = 'You must override the "_analyzeResult" method of basePlugin if' msg += ' you want to use "_sendMutant" with the default callback.' raise w3afException( msg )
def setModValue( self, val ): ''' Set the value of the variable that this mutant modifies. ''' try: self._freq._dc[ self.getVar() ][ self._index ] = val except Exception: msg = 'The mutant object wasn\'t correctly initialized. Either the variable to be' msg += ' modified, or the index of that variable are incorrect. This error was' msg += ' found in mutant.setModValue()' raise w3afException( msg )
def setOptions( self, optionsMap ): ''' 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 options that were retrieved from the plugin using getOptions() This method MUST be implemented on every plugin. @return: No value is returned. ''' raise w3afException('Plugin "'+self.getName()+'" is not implementing required method setOptions' )
def setCookie(self, c): """ @parameter cookie: A cookie object as defined in core.data.dc.cookie, or a string. """ if isinstance(c, cookie): self._cookie = c elif isinstance(c, basestring): self._cookie = cookie(c) elif c is None: self._cookie = None else: om.out.error('[fuzzableRequest error] setCookie received: "' + str(type(c)) + '" , "' + repr(c) + '"') raise w3afException("Invalid call to fuzzableRequest.setCookie()")
def setCookie(self, c): ''' @parameter cookie: A cookie object as defined in core.data.dc.cookie, or a string. ''' if isinstance(c, cookie): self._cookie = c elif isinstance(c, basestring): self._cookie = cookie(c) elif c is None: self._cookie = None else: om.out.error('[fuzzableRequest error] setCookie received: "' + str(type(c)) + '" , "' + repr(c) + '"') raise w3afException('Invalid call to fuzzableRequest.setCookie()')
def setOptions( self, optionsMap ): ''' This method sets all the options that are configured using the user interface generated by the framework using the result of getOptions(). @parameter optionsMap: A dictionary with the options for the plugin. @return: No value is returned. ''' self._listen_address = optionsMap['listenAddress'].getValue() self._listen_port = optionsMap['listenPort'].getValue() self._use_w3af_site = optionsMap['usew3afSite'].getValue() if not self._correctly_configured(): raise w3afException(CONFIG_ERROR_MSG)
def setOptions(self, optionsMap): ''' This method sets all the options that are configured using the user interface generated by the framework using the result of getOptions(). @parameter optionsMap: A dictionary with the options for the plugin. @return: No value is returned. ''' self._listen_address = optionsMap['listenAddress'].getValue() self._listen_port = optionsMap['listenPort'].getValue() self._use_w3af_site = optionsMap['usew3afSite'].getValue() if not self._correctly_configured(): raise w3afException(CONFIG_ERROR_MSG)
def parse_qs(url_encoded_string, ignoreExceptions=True): ''' Parse a url encoded string (a=b&c=d) into a queryString object. @param url_encoded_string: The string to parse @return: A queryString object (a dict wrapper). >>> parse_qs('id=3') {'id': ['3']} >>> parse_qs('id=3&id=4') {'id': ['3', '4']} >>> parse_qs('id=3&ff=4&id=5') {'id': ['3', '5'], 'ff': ['4']} ''' parsed_qs = None result = queryString() if url_encoded_string: try: parsed_qs = cgi.parse_qs(url_encoded_string, keep_blank_values=True, strict_parsing=False) except Exception, e: if not ignoreExceptions: raise w3afException( 'Strange things found when parsing query string: "' + url_encoded_string + '"') else: # # Before we had something like this: # #for i in parsed_qs.keys(): # result[ i ] = parsed_qs[ i ][0] # # But with that, we fail to handle web applications that use "duplicated parameter # names". For example: http://host.tld/abc?sp=1&sp=2&sp=3 # # (please note the lack of [0]) , and that if the value isn't a list... # I create an artificial list for p, v in parsed_qs.iteritems(): if type(v) is not list: v = [v] result[p] = v
def _get_allowed_chars(self, mutant): ''' These are the special characters that are tested: ['<', '>', '"', "'", '(', ')'] I'm aware that this doesn't work if the filter also filters by length. The idea of this method is to reduce the amount of tests to be performed, if I start testing each char separately, I loose that performance enhancement that I want to get. @return: A list with the special characters that are allowed by the XSS filter ''' # Create a random number and assign it to the mutant modified parameter rndNum = str( createRandAlNum( 4 ) ) oldValue = mutant.getModValue() joined_list = rndNum.join(self._special_characters) list_delimiter = str( createRandAlNum( 5 ) ) joined_list = list_delimiter + joined_list + list_delimiter mutant.setModValue(joined_list) # send response = self._sendMutant( mutant, analyze=False ) # restore the mutant values mutant.setModValue(oldValue) # Analyze the response allowed = [] if response.getBody().count(list_delimiter) == 2: start = response.getBody().find(list_delimiter) end = response.getBody().find(list_delimiter, start+1) the_list = response.getBody()[start+len(list_delimiter):end] split_list = the_list.split(rndNum) for i, char in enumerate(split_list): if char == self._special_characters[i]: allowed.append(char) else: raise w3afException('The delimiter was not echoed back!') if allowed == self._special_characters: om.out.debug('All special characters are allowed.') return allowed
def audit(self, freq): ''' Tests an URL for remote file inclusion vulnerabilities. @param freq: A fuzzableRequest object ''' # Sanity check if not self._correctly_configured(): # Report error to the user only once self._error_reported = True raise w3afException(CONFIG_ERROR_MSG) if not self._error_reported: # 1- create a request that will include a file from a local web server self._local_test_inclusion(freq) # The plugin is going to use two different techniques: # 2- create a request that will include a file from the w3af official site if self._use_w3af_site: self._w3af_site_test_inclusion(freq)
def audit(self, freq): ''' Tests an URL for remote file inclusion vulnerabilities. @param freq: A fuzzableRequest object ''' # Sanity check if not self._correctly_configured(): # Report error to the user only once self._error_reported = True raise w3afException(CONFIG_ERROR_MSG) if not self._error_reported: # 1- create a request that will include a file from a local web server self._local_test_inclusion(freq) # The plugin is going to use two different techniques: # 2- create a request that will include a file from the w3af official site if self._use_w3af_site: self._w3af_site_test_inclusion(freq)
def parse_qs( url_encoded_string, ignoreExceptions=True ): ''' Parse a url encoded string (a=b&c=d) into a queryString object. @param url_encoded_string: The string to parse @return: A queryString object (a dict wrapper). >>> parse_qs('id=3') {'id': ['3']} >>> parse_qs('id=3&id=4') {'id': ['3', '4']} >>> parse_qs('id=3&ff=4&id=5') {'id': ['3', '5'], 'ff': ['4']} ''' parsed_qs = None result = queryString() if url_encoded_string: try: parsed_qs = cgi.parse_qs( url_encoded_string ,keep_blank_values=True,strict_parsing=False) except Exception, e: if not ignoreExceptions: raise w3afException('Strange things found when parsing query string: "' + url_encoded_string + '"') else: # # Before we had something like this: # #for i in parsed_qs.keys(): # result[ i ] = parsed_qs[ i ][0] # # But with that, we fail to handle web applications that use "duplicated parameter # names". For example: http://host.tld/abc?sp=1&sp=2&sp=3 # # (please note the lack of [0]) , and that if the value isn't a list... # I create an artificial list for p, v in parsed_qs.iteritems(): if type(v) is not list: v = [v] result[p] = v
def setURL(self, u): raise w3afException( 'You can\'t change the value of the URL in a mutantFileName instance.' )
def getPluginDeps( self ): ''' @return: A list with the names of the plugins that should be runned before the current one. ''' raise w3afException('Plugin is not implementing required method getPluginDeps' )
def getOptions(self): ''' @return: A list of option objects for this plugin. ''' raise w3afException('Plugin "'+self.getName()+'" is not implementing required method getOptions' )
def getMutantType( self ): msg = 'You should implement the getMutantType method when inhereting from mutant.' raise w3afException( msg )
def getLongDesc( self ): ''' @return: A DETAILED description of the plugin functions and features. ''' raise w3afException('Plugin is not implementing required method getLongDesc' )
def setURL( self, u ): raise w3afException('You can\'t change the value of the URL in a mutantFileName instance.')
def getModValue(self): try: return self._freq._cookie[self.getVar()][self._index] except: raise w3afException( 'The cookie mutant object was\'nt correctly initialized.')
def getModValue( self ): try: return self._freq._cookie[ self.getVar() ][ self._index ] except: raise w3afException('The cookie mutant object was\'nt correctly initialized.')
def getAllShells( self ): ''' @return: A list of all vulns reported by all plugins. ''' return w3afException("Not Implemented In Adam's hack job.")