def end(self):
     om.out.debug("File upload shell is going to delete the webshell that was uploaded before.")
     file_to_del = urlParser.getFileName(self.getExploitURL())
     try:
         self.unlink(file_to_del)
     except w3afException, e:
         om.out.error("File upload shell cleanup failed with exception: " + str(e))
 def _rm_file(self):
     '''
     Stop the server, remove the file from the webroot.
     '''
     # Remove the file
     filename = urlParser.getFileName(self._rfi_url)
     os.remove(os.path.join(get_home_dir(), 'webroot', filename))
 def audit(self, freq ):
     '''
     Tests an URL for local file inclusion vulnerabilities.
     
     @param freq: A fuzzableRequest
     '''
     om.out.debug( 'localFileInclude plugin is testing: ' + freq.getURL() )
     
     oResponse = self._sendMutant( freq , analyze=False ).getBody()
     
     #   What payloads do I want to send to the remote end?
     local_files = []
     local_files.append( urlParser.getFileName( freq.getURL() ) )
     if not self._open_basedir:
         local_files.extend( self._get_local_file_list(freq.getURL()) )
     
     mutants = createMutants( freq , local_files, oResponse=oResponse )
         
     for mutant in mutants:
         
         # Only spawn a thread if the mutant has a modified variable
         # that has no reported bugs in the kb
         if self._hasNoBug( 'localFileInclude' , 'localFileInclude', mutant.getURL() , mutant.getVar() ):
             
             targs = (mutant,)
             # I don't grep the result, because if I really find a local file inclusion,
             # I will be requesting /etc/passwd and that would generate A LOT of false
             # positives in the grep.pathDisclosure plugin
             kwds = {'grepResult':False}
             self._tm.startFunction( target=self._sendMutant, args=targs , \
                                                 kwds=kwds, ownerObj=self )
                                                 
     self._tm.join( self )
 def _mangle_digits(self, fuzzableRequest):
     '''
     Mangle those digits.
     @param fuzzableRequest: The original fuzzableRequest
     @return: A list of fuzzableRequests.
     '''
     res = []
     # First i'll mangle the digits in the URL file
     filename = urlParser.getFileName( fuzzableRequest.getURL() )
     domain_path = urlParser.getDomainPath( fuzzableRequest.getURL() )
     for fname in self._do_combinations( filename ):
         fr_copy = fuzzableRequest.copy()
         fr_copy.setURL( domain_path + fname)
         res.append( fr_copy )
     
     # Now i'll mangle the query string variables
     if fuzzableRequest.getMethod() == 'GET':
         for parameter in fuzzableRequest.getDc():
             
             # to support repeater parameter names...
             for element_index in xrange(len(fuzzableRequest.getDc()[parameter])):
                 
                 for modified_value in self._do_combinations( fuzzableRequest.getDc()[ parameter ][element_index] ):
                     fr_copy = fuzzableRequest.copy()
                     new_dc = fr_copy.getDc()
                     new_dc[ parameter ][ element_index ] = modified_value
                     fr_copy.setDc( new_dc )
                     res.append( fr_copy )
     
     return res
Exemple #5
0
 def _get_filename( self, url ):
     '''
     @return: The filename, without the extension
     '''
     fname = urlParser.getFileName( url )
     splitted_fname = fname.split('.')
     name = ''
     if len(splitted_fname) != 0:
         name = splitted_fname[0]
     return name
Exemple #6
0
def _createFileNameMutants( freq, mutantClass, mutant_str_list, fuzzableParamList , append ):
    '''
    @parameter freq: A fuzzable request with a dataContainer inside.
    @parameter mutantClass: The class to use to create the mutants
    @parameter fuzzableParamList: What parameters should be fuzzed
    @parameter append: True/False, if we should append the value or replace it.
    @parameter mutant_str_list: a list with mutant strings to use
    
    @return: Mutants that have the filename URL changed with the strings at mutant_str_list
    '''
    res = []
    fileName = urlParser.getFileName( freq.getURL() )
    splittedFileName = [ x for x in re.split( r'([a-zA-Z0-9]+)', fileName ) if x != '' ]
    for i in xrange( len( splittedFileName ) ):
        for mutant_str in mutant_str_list:
            if re.match('[a-zA-Z0-9]', splittedFileName[i] ):
                divided_file_name = dc()
                divided_file_name['start'] = ''.join( splittedFileName[: i] )
                if append:
                    divided_file_name['fuzzedFname'] = splittedFileName[i] + urllib.quote_plus( mutant_str )
                else:
                    divided_file_name['fuzzedFname'] = urllib.quote_plus( mutant_str )
                divided_file_name['end'] = ''.join( splittedFileName[i+1:] )
                
                freq_copy = freq.copy()
                freq_copy.setURL( freq.getURL() )
                
                # Create the mutant
                m = mutantClass( freq_copy ) 
                m.setOriginalValue( splittedFileName[i] )
                m.setVar( 'fuzzedFname' )
                m._mutant_dc = divided_file_name
                m.setModValue( mutant_str )
                # Special for filename fuzzing and some configurations of mod_rewrite
                m.setDoubleEncoding( False )
                
                # The same but with a different type of encoding! (mod_rewrite)
                m2 = m.copy()
                m2.setSafeEncodeChars('/')
                
                res.append( m )
                res.append( m2 )
    return res
    def _generate_URLs(self, original_url):
        '''
        Generate new URLs based on original_url.

        @parameter original_url: The original url that has to be modified in order to trigger errors in the remote application.
        '''
        res = []
        special_chars = ['|', '~']

        filename = urlParser.getFileName( original_url )
        if filename != '' and '.' in filename:
            splitted_filename = filename.split('.')
            extension = splitted_filename[-1:][0]
            name = '.'.join( splitted_filename[0:-1] )

            for char in special_chars:
                new_filename = name + char + '.' + extension
                new_url = urlParser.urlJoin( urlParser.getDomainPath(original_url), new_filename)
                res.append( new_url )

        return res
Exemple #8
0
 def _generate_URL_from_result( self, analyzed_variable, element_index, result_set, fuzzableRequest ):
     '''
     Based on the result, create the new URLs to test.
     
     @parameter analyzed_variable: The parameter name that is being analyzed
     @parameter element_index: 0 in most cases, >0 if we have repeated parameter names
     @parameter result_set: The set of results that wordnet gave use
     @parameter fuzzableRequest: The fuzzable request that we got as input in the first place.
     
     @return: An URL list.
     '''
     if analyzed_variable is None:
         # The URL was analyzed
         url = fuzzableRequest.getURL()
         fname = urlParser.getFileName( url )
         dp = urlParser.getDomainPath( url )
         
         # The result
         result = []
         
         splitted_fname = fname.split('.')
         if len(splitted_fname) == 2:
             name = splitted_fname[0]
             extension = splitted_fname[1]
         else:
             name = '.'.join(splitted_fname[:-1])
             extension = 'html'
         
         for set_item in result_set:
             new_fname = fname.replace( name, set_item )
             frCopy = fuzzableRequest.copy()
             frCopy.setURL( urlParser.urlJoin( dp, new_fname ) )
             result.append( frCopy )
             
         return result
         
     else:
         mutants = createMutants( fuzzableRequest , result_set, \
                                                 fuzzableParamList=[analyzed_variable,] )
         return mutants
    def _find_OS( self, fuzzableRequest ):
        '''
        Analyze responses and determine if remote web server runs on windows or *nix
        @Return: None, the knowledge is saved in the knowledgeBase
        '''
        dirs = urlParser.getDirectories( fuzzableRequest.getURL() )
        filename = urlParser.getFileName( fuzzableRequest.getURL() )
        if len( dirs ) > 1 and filename:
            last = dirs[-1]
            windowsURL = last[0:-1] + '\\' + filename
            windows_response = self._urlOpener.GET( windowsURL )
            
            original_response = self._urlOpener.GET( fuzzableRequest.getURL() )
            self._found_OS = True

            if relative_distance_ge(original_response.getBody(),
                                    windows_response.getBody(), 0.98):
                i = info.info()
                i.setPluginName(self.getName())
                i.setName('Operating system')
                i.setURL( windows_response.getURL() )
                i.setMethod( 'GET' )
                i.setDesc('Fingerprinted this host as a Microsoft Windows system.' )
                i.setId( [windows_response.id, original_response.id] )
                kb.kb.append( self, 'operating_system_str', 'windows' )
                kb.kb.append( self, 'operating_system', i )
                om.out.information( i.getDesc() )
            else:
                i = info.info()
                i.setPluginName(self.getName())
                i.setName('Operating system')
                i.setURL( original_response.getURL() )
                i.setMethod( 'GET' )
                msg = 'Fingerprinted this host as a *nix system. Detection for this operating'
                msg += ' system is weak, "if not windows: is linux".'
                i.setDesc( msg )
                i.setId( [original_response.id, windows_response.id] )
                kb.kb.append( self, 'operating_system_str', 'unix' )
                kb.kb.append( self, 'operating_system', i )
                om.out.information( i.getDesc() )
 def _analyzeResult( self, mutant, response ):
     '''
     Analyze results of the _sendMutant method.
     Try to find the local file inclusions.
     '''
     #
     #   Only one thread at the time can enter here. This is because I want to report each
     #   vulnerability only once, and by only adding the "if self._hasNoBug" statement, that
     #   could not be done.
     #
     with self._plugin_lock:
         
         #
         #   I analyze the response searching for a specific PHP error string that tells me
         #   that open_basedir is enabled, and our request triggered the restriction. If
         #   open_basedir is in use, it makes no sense to keep trying to read "/etc/passwd",
         #   that is why this variable is used to determine which tests to send if it was possible
         #   to detect the usage of this security feature.
         #
         if not self._open_basedir:
             if 'open_basedir restriction in effect' in response\
             and 'open_basedir restriction in effect' not in mutant.getOriginalResponseBody():
                 self._open_basedir = True
         
         #
         #   I will only report the vulnerability once.
         #
         if self._hasNoBug( 'localFileInclude' , 'localFileInclude' , mutant.getURL() , mutant.getVar() ):
             
             #
             #   Identify the vulnerability
             #
             file_content_list = self._find_file( response )
             for file_pattern_regex, file_content in file_content_list:
                 if not file_pattern_regex.search( mutant.getOriginalResponseBody() ):
                     v = vuln.vuln( mutant )
                     v.setPluginName(self.getName())
                     v.setId( response.id )
                     v.setName( 'Local file inclusion vulnerability' )
                     v.setSeverity(severity.MEDIUM)
                     v.setDesc( 'Local File Inclusion was found at: ' + mutant.foundAt() )
                     v['file_pattern'] = file_content
                     v.addToHighlight( file_content )
                     kb.kb.append( self, 'localFileInclude', v )
                     return
             
             #
             #   If the vulnerability could not be identified by matching strings that commonly
             #   appear in "/etc/passwd", then I'll check one more thing...
             #   (note that this is run if no vulns were identified)
             #
             #   http://host.tld/show_user.php?id=show_user.php
             if mutant.getModValue() == urlParser.getFileName( mutant.getURL() ):
                 match, lang = is_source_file( response.getBody() )
                 if match:
                     #   We were able to read the source code of the file that is vulnerable to
                     #   local file read
                     v = vuln.vuln( mutant )
                     v.setPluginName(self.getName())
                     v.setId( response.id )
                     v.setName( 'Local file read vulnerability' )
                     v.setSeverity(severity.MEDIUM)
                     msg = 'An arbitrary local file read vulnerability was found at: '
                     msg += mutant.foundAt()
                     v.setDesc( msg )
                     
                     #
                     #    Set which part of the source code to match
                     #
                     match_source_code = match.group(0)
                     v['file_pattern'] = match_source_code
                     
                     kb.kb.append( self, 'localFileInclude', v )
                     return
                     
             #
             #   Check for interesting errors (note that this is run if no vulns were identified)
             #
             for regex in self.get_include_errors():
                 
                 match = regex.search( response.getBody() )
                 
                 if match and not \
                 regex.search( mutant.getOriginalResponseBody() ):
                     i = info.info( mutant )
                     i.setPluginName(self.getName())
                     i.setId( response.id )
                     i.setName( 'File read error' )
                     i.setDesc( 'A file read error was found at: ' + mutant.foundAt() )
                     kb.kb.append( self, 'error', i )
                        /es/ga.js/google-analytics.com
                        /ga.js/google-analytics.com
                        /es/ga.js/google-analytics.com/ga.js/google-analytics.com/ga.js
                        /ga.js/google-analytics.com/google-analytics.com/ga.js/
                        /es/ga.js/google-analytics.com/google-analytics.com/ga.js/
                        /es/ga.js/google-analytics.com/google-analytics.com/
                        /es/ga.js/google-analytics.com/google-analytics.com/google-analytics.com/ga.js
                        /ga.js/google-analytics.com/google-analytics.com/ga.js
                        /services/google-analytics.com/google-analytics.com/
                        /services/google-analytics.com/google-analytics.com/google-analytics.com/ga.js
                        /es/ga.js/google-analytics.com/ga.js/google-analytics.com/ga.js/
                        /ga.js/google-analytics.com/ga.js/google-analytics.com/ga.js/
                        /ga.js/google-analytics.com/ga.js/google-analytics.com/
                        /ga.js/google-analytics.com/ga.js/google-analytics.com/google-analytics.com/ga.js
                        """
                        filename = urlParser.getFileName(reference)
                        if filename:
                            rindex = reference.rindex(filename)
                            # 'ar9k' is just a random string to get a 404
                            new_reference = reference[:rindex] + "ar9k" + reference[rindex:]

                            check_response = self._urlOpener.GET(new_reference, useCache=True, headers=headers)
                            resp_body = response.getBody()
                            check_resp_body = check_response.getBody()

                            if relative_distance_ge(resp_body, check_resp_body, IS_EQUAL_RATIO):
                                # If they are equal, then they are both a 404 (or something invalid)
                                # om.out.debug( reference + ' was broken!')
                                return

                            else: