示例#1
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            if self._is_possible_backdoor(response):
                desc = 'A web backdoor was found at: "%s"; this could ' \
                       'indicate that the server has been compromised.'
                desc = desc % response.get_url()

                v = Vuln('Potential web backdoor', desc, severity.HIGH,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'backdoors', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)
示例#2
0
    def send_and_check(self, url):

        response = self.http_get_and_parse(url)

        for regex in self.ORACLE_RE:
            mo = regex.search(response.get_body(), re.DOTALL)

            if mo:
                desc = '"%s" version "%s" was detected at "%s".'
                desc %= (mo.group(1).title(), mo.group(2).title(),
                         response.get_url())

                i = Info('Oracle Application Server', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'oracle_discovery', i)
                om.out.information(i.get_desc())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)

                break

        else:
            msg = ('oracle_discovery found the URL: "%s" but failed to'
                   ' parse it as an Oracle page. The first 50 bytes of'
                   ' the response body is: "%s".')
            body_start = response.get_body()[:50]
            om.out.debug(msg % (response.get_url(), body_start))
示例#3
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            signature = self._match_signature(response)
            if signature is None:
                return

            desc = (u'An HTTP response matching the web backdoor signature'
                    u' "%s" was found at: "%s"; this could indicate that the'
                    u' server has been compromised.')
            desc %= (signature, response.get_url())

            # It's probability is higher if we found a long signature
            _severity = severity.HIGH if len(signature) > 8 else severity.MEDIUM

            v = Vuln(u'Potential web backdoor', desc, _severity,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'backdoors', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)
示例#4
0
    def crawl(self, fuzzable_request):
        """
        Get the sitemap.xml file and parse it.

        :param fuzzable_request: A fuzzable_request instance that contains
                                   (among other things) the URL to test.
        """
        base_url = fuzzable_request.get_url().base_url()
        sitemap_url = base_url.url_join('sitemap.xml')
        response = self._uri_opener.GET(sitemap_url, cache=True)

        if '</urlset>' not in response:
            return

        if is_404(response):
            return

        # Send response to core
        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)

        om.out.debug('Parsing xml file with xml.dom.minidom.')
        try:
            dom = xml.dom.minidom.parseString(response.get_body())
        except Exception, e:
            msg = 'Exception while parsing sitemap.xml from %s: "%s"'
            args = (response.get_url(), e)
            om.out.debug(msg % args)
            return
示例#5
0
    def crawl(self, fuzzable_request):
        """
        Get the sitemap.xml file and parse it.

        :param fuzzable_request: A fuzzable_request instance that contains
                                   (among other things) the URL to test.
        """
        base_url = fuzzable_request.get_url().base_url()
        sitemap_url = base_url.url_join('sitemap.xml')
        response = self._uri_opener.GET(sitemap_url, cache=True)

        if '</urlset>' in response and not is_404(response):
            # Send response to core
            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)

            om.out.debug('Parsing xml file with xml.dom.minidom.')
            try:
                dom = xml.dom.minidom.parseString(response.get_body())
            except:
                raise BaseFrameworkException('Error while parsing sitemap.xml')
            else:
                raw_url_list = dom.getElementsByTagName("loc")
                parsed_url_list = []
                for url in raw_url_list:
                    try:
                        url = url.childNodes[0].data
                        url = URL(url)
                    except ValueError, ve:
                        msg = 'Sitemap file had an invalid URL: "%s"'
                        om.out.debug(msg % ve)
                    except:
                        om.out.debug('Sitemap file had an invalid format')
示例#6
0
    def _do_request(self, url, mutant):
        """
        Perform a simple GET to see if the result is an error or not, and then
        run the actual fuzzing.
        """
        response = self._uri_opener.GET(mutant,
                                        cache=True,
                                        headers=self._headers)

        if not (is_404(response) or response.get_code() in (403, 401)
                or self._return_without_eval(mutant)):

            # Create the fuzzable request and send it to the core
            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)

            #
            #   Save it to the kb (if new)!
            #
            if response.get_url() not in self._seen and response.get_url(
            ).get_file_name():
                desc = 'A potentially interesting file was found at: "%s".'
                desc = desc % response.get_url()

                i = Info('Potentially interesting file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'files', i)
                om.out.information(i.get_desc())

                # Report only once
                self._seen.add(response.get_url())
示例#7
0
    def crawl(self, fuzzable_request):
        """
        Get the sitemap.xml file and parse it.

        :param fuzzable_request: A fuzzable_request instance that contains
                                   (among other things) the URL to test.
        """
        base_url = fuzzable_request.get_url().base_url()
        sitemap_url = base_url.url_join('sitemap.xml')
        response = self._uri_opener.GET(sitemap_url, cache=True)

        if '</urlset>' in response and not is_404(response):
            # Send response to core
            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)

            om.out.debug('Parsing xml file with xml.dom.minidom.')
            try:
                dom = xml.dom.minidom.parseString(response.get_body())
            except:
                raise BaseFrameworkException('Error while parsing sitemap.xml')
            else:
                raw_url_list = dom.getElementsByTagName("loc")
                parsed_url_list = []
                for url in raw_url_list:
                    try:
                        url = url.childNodes[0].data
                        url = URL(url)
                    except ValueError, ve:
                        msg = 'Sitemap file had an invalid URL: "%s"'
                        om.out.debug(msg % ve)
                    except:
                        om.out.debug('Sitemap file had an invalid format')
示例#8
0
    def _do_request(self, url, mutant):
        """
        Perform a simple GET to see if the result is an error or not, and then
        run the actual fuzzing.
        """
        response = self._uri_opener.GET(
            mutant, cache=True, headers=self._headers)

        if not (is_404(response) or
        response.get_code() in (403, 401) or
        self._return_without_eval(mutant)):

            # Create the fuzzable request and send it to the core
            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)
            
            #
            #   Save it to the kb (if new)!
            #
            if response.get_url() not in self._seen and response.get_url().get_file_name():
                desc = 'A potentially interesting file was found at: "%s".'
                desc = desc % response.get_url()

                i = Info('Potentially interesting file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())
                
                kb.kb.append(self, 'files', i)
                om.out.information(i.get_desc())

                # Report only once
                self._seen.add(response.get_url())
示例#9
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            signature = self._match_signature(response)
            if signature is None:
                return

            desc = (u'An HTTP response matching the web backdoor signature'
                    u' "%s" was found at: "%s"; this could indicate that the'
                    u' server has been compromised.')
            desc %= (signature, response.get_url())

            # It's probability is higher if we found a long signature
            _severity = severity.HIGH if len(
                signature) > 8 else severity.MEDIUM

            v = Vuln(u'Potential web backdoor', desc, _severity, response.id,
                     self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'backdoors', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)
示例#10
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            if self._is_possible_backdoor(response):
                desc = 'A web backdoor was found at: "%s"; this could ' \
                       'indicate that the server has been compromised.'
                desc = desc % response.get_url()

                v = Vuln('Potential web backdoor', desc, severity.HIGH,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'backdoors', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)
示例#11
0
    def _send_and_check(self, nikto_test):
        """
        This method sends the request to the server.

        :return: True if the requested URI responded as expected.
        """
        #
        #    Small performance improvement. If all we want to know is if the
        #    file exists or not, lets use HEAD instead of GET. In 99% of the
        #    cases this will work as expected and we'll have a significant
        #    performance improvement.
        #
        if nikto_test.is_vulnerable.checks_only_response_code():
            try:
                http_response = self._uri_opener.HEAD(nikto_test.uri)
            except Exception:
                return
            else:
                if not nikto_test.is_vulnerable.check(http_response):
                    return False

        function_ptr = getattr(self._uri_opener, nikto_test.method)

        try:
            http_response = function_ptr(nikto_test.uri)
        except BaseFrameworkException as e:
            msg = ('An exception was raised while requesting "%s", the error'
                   ' message is: "%s".')
            om.out.error(msg % (nikto_test.uri, e))
            return False

        if nikto_test.is_vulnerable.check(http_response) and \
        not is_404(http_response):

            vdesc = ('pykto plugin found a vulnerability at URL: "%s".'
                     ' Vulnerability description: "%s".')
            vdesc = vdesc % (http_response.get_url(), nikto_test.message)

            v = Vuln('Insecure URL', vdesc, severity.LOW, http_response.id,
                     self.get_name())
            v.set_uri(http_response.get_uri())
            v.set_method(nikto_test.method)

            kb.kb.append(self, 'vuln', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest.from_http_response(http_response)
            self.output_queue.put(fr)
示例#12
0
    def _analyze_gears_manifest(self, url, response, file_name):
        if '"entries":' not in response:
            return

        # Save it to the kb!
        desc = ('A gears manifest file was found at: "%s".'
                ' Each file should be manually reviewed for sensitive'
                ' information that may get cached on the client.')
        desc %= url

        i = Info('Gears manifest resource', desc, response.id, self.get_name())
        i.set_url(url)

        kb.kb.append(self, url, i)
        om.out.information(i.get_desc())

        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)
示例#13
0
    def _check_and_analyze(self, domain_path, php_info_filename):
        """
        Check if a php_info_filename exists in the domain_path.
        :return: None, everything is put() into the self.output_queue.
        """
        php_info_url = domain_path.url_join(php_info_filename)

        response = self._uri_opener.GET(php_info_url,
                                        cache=True,
                                        grep=False)

        if is_404(response):
            return

        # Check if it is a phpinfo file
        php_version = self.PHP_VERSION_RE.search(response.get_body(), re.I)
        sysinfo = self.SYSTEM_RE.search(response.get_body(), re.I)

        if not php_version:
            return

        if not sysinfo:
            return

        # Create the fuzzable request and send it to the core
        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)

        desc = ('The phpinfo() file was found at: %s. The version'
                ' of PHP is: "%s" and the system information is:'
                ' "%s".')
        desc %= (response.get_url(), php_version.group(2), sysinfo.group(1))

        v = Vuln('phpinfo() file found', desc, severity.MEDIUM,
                 response.id, self.get_name())
        v.set_url(response.get_url())

        kb.kb.append(self, 'phpinfo', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())

        if not self._has_audited:
            self._has_audited = True
            self.audit_phpinfo(response)
示例#14
0
    def _send_request(self, functor, url, mutant):
        response = functor(mutant, cache=True)

        if is_404(response):
            return

        # Create the fuzzable request and send it to the core
        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)

        #
        # Save it to the kb!
        #
        desc = 'A potentially interesting URL was found at: "%s".'
        desc %= response.get_url()

        i = Info('Potentially interesting URL', desc, response.id,
                 self.get_name())
        i.set_url(response.get_url())

        kb.kb.append_uniq(self, 'url', i, filter_by='URL')
        om.out.information(i.get_desc())
示例#15
0
class pykto(CrawlPlugin):
    """
    A nikto port to python.
    :author: Andres Riancho ([email protected])
    """
    def __init__(self):
        CrawlPlugin.__init__(self)

        # internal variables
        self._exec = True
        self._already_analyzed = ScalableBloomFilter()

        # User configured parameters
        self._db_file = os.path.join(ROOT_PATH, 'plugins', 'crawl', 'pykto',
                                     'scan_database.db')
        self._extra_db_file = os.path.join(ROOT_PATH, 'plugins', 'crawl',
                                           'pykto', 'w3af_scan_database.db')

        self._cgi_dirs = ['/cgi-bin/']
        self._admin_dirs = ['/admin/', '/adm/']

        self._users = ['adm', 'bin', 'daemon', 'ftp', 'guest', 'listen', 'lp',
                       'mysql', 'noaccess', 'nobody', 'nobody4', 'nuucp',
                       'operator', 'root', 'smmsp', 'smtp', 'sshd', 'sys',
                       'test', 'unknown']

        self._nuke = ['/', '/postnuke/', '/postnuke/html/', '/modules/',
                      '/phpBB/', '/forum/']

        self._mutate_tests = False

    def crawl(self, fuzzable_request):
        """
        Runs pykto to the site.

        :param fuzzable_request: A fuzzable_request instance that contains
                                 (among other things) the URL to test.
        """
        if not self._exec and not self._mutate_tests:
            # dont run anymore
            raise RunOnce()

        else:
            # Run the basic scan (only once)
            url = fuzzable_request.get_url().base_url()
            if url not in self._already_analyzed:
                self._already_analyzed.add(url)
                self._run(url)
                self._exec = False

            # And now mutate if the user configured it...
            if self._mutate_tests:

                # Tests need to be mutated
                url = fuzzable_request.get_url().get_domain_path()
                if url not in self._already_analyzed:
                    # Save the directories I already have tested in order to
                    # avoid testing them more than once...
                    self._already_analyzed.add(url)
                    self._run(url)

    def _run(self, url):
        """
        Really run the plugin.

        :param url: The URL object I have to test.
        """
        config = Config(self._cgi_dirs, self._admin_dirs, self._nuke,
                        self._mutate_tests, self._users)
                
        for db_file in [self._db_file, self._extra_db_file]:
            
            parser = NiktoTestParser(db_file, config, url)
            
            # Send the requests using threads:
            self.worker_pool.map_multi_args(self._send_and_check,
                                            parser.test_generator(),
                                            chunksize=10)

    def _send_and_check(self, nikto_test):
        """
        This method sends the request to the server.

        :return: True if the requested URI responded as expected.
        """
        #
        #    Small performance improvement. If all we want to know is if the
        #    file exists or not, lets use HEAD instead of GET. In 99% of the
        #    cases this will work as expected and we'll have a significant
        #    performance improvement.
        #
        if nikto_test.is_vulnerable.checks_only_response_code():
            try:
                http_response = self._uri_opener.HEAD(nikto_test.uri)
            except Exception:
                return
            else:
                if not nikto_test.is_vulnerable.check(http_response):
                    return False

        function_ptr = getattr(self._uri_opener, nikto_test.method)

        try:
            http_response = function_ptr(nikto_test.uri)
        except BaseFrameworkException, e:
            msg = ('An exception was raised while requesting "%s", the error'
                   ' message is: "%s".')
            om.out.error(msg % (nikto_test.uri, e))
            return False

        if nikto_test.is_vulnerable.check(http_response) and \
        not is_404(http_response):
            
            vdesc = ('pykto plugin found a vulnerability at URL: "%s".'
                     ' Vulnerability description: "%s".')
            vdesc = vdesc % (http_response.get_url(), nikto_test.message)

            v = Vuln('Insecure URL', vdesc, severity.LOW,
                     http_response.id, self.get_name())
            v.set_uri(http_response.get_uri())
            v.set_method(nikto_test.method)

            kb.kb.append(self, 'vuln', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest.from_http_response(http_response)
            self.output_queue.put(fr)
示例#16
0
            if is_404(http_response):
                return
            #
            #   Looking good, but lets see if this is a false positive
            #   or not...
            #
            dir_url = base_path.url_join(directory_name + rand_alnum(5) + '/')

            invalid_http_response = self._uri_opener.GET(dir_url, cache=False)

            if is_404(invalid_http_response):
                #
                #    Good, the directory_name + rand_alnum(5) return a
                #    404, the original directory_name is not a false positive.
                #
                fr = FuzzableRequest.from_http_response(http_response)
                self.output_queue.put(fr)

                msg = ('dir_file_brute plugin found "%s" with HTTP response '
                       'code %s and Content-Length: %s.')

                om.out.information(
                    msg % (http_response.get_url(), http_response.get_code(),
                           len(http_response.get_body())))

    def _bruteforce_directories(self, base_path):
        """
        :param base_path: The base path to use in the bruteforcing process,
                          can be something like http://host.tld/ or
                          http://host.tld/images/ .
示例#17
0
    def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name):

        # https://github.com/andresriancho/w3af/issues/14491
        if file_name not in self.FILE_TAG_ATTR:
            return

        try:
            dom = xml.dom.minidom.parseString(response.get_body())
        except Exception:
            # Report this, it may be interesting for the final user
            # not a vulnerability per-se... but... it's information after all
            if 'allow-access-from' in response.get_body() or \
            'cross-domain-policy' in response.get_body() or \
            'cross-domain-access' in response.get_body():

                desc = 'The "%s" file at: "%s" is not a valid XML.'
                desc %= (file_name, response.get_url())

                i = Info('Invalid RIA settings file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())

            return

        tag, attribute = self.FILE_TAG_ATTR.get(file_name)
        url_list = dom.getElementsByTagName(tag)

        for url in url_list:
            url = url.getAttribute(attribute)

            if url == '*':
                desc = 'The "%s" file at "%s" allows flash / silverlight'\
                       ' access from any site.'
                desc %= (file_name, response.get_url())

                v = Vuln('Insecure RIA settings', desc, severity.LOW,
                         response.id, self.get_name())
                v.set_url(response.get_url())
                v.set_method('GET')

                kb.kb.append(self, 'vuln', v)
                om.out.vulnerability(v.get_desc(),
                                     severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)

            else:
                desc = 'The "%s" file at "%s" allows flash / silverlight'\
                       ' access from "%s".'
                desc %= (file_name, response.get_url(), url)

                i = Info('Cross-domain allow ACL', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())
                i.set_method('GET')

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)
示例#18
0
文件: phpinfo.py 项目: ElAleyo/w3af
            # when scanning phpinfo in window box
            # the problem is generating a lot of results
            # due to all-the-same-for-windows files phpVersion.php, phpversion.php ..etc
            # Well, how to solve it?
            # Finding one phpinfo file is enough for auditing for the target
            # So, we report every phpinfo file found
            # but we do and report auditing once. Sounds logical?
            #
            # Feb/17/2009 by Andres Riancho:
            # Yes, that sounds ok for me.

            # Check if it's a phpinfo file
            if not is_404(response):

                # Create the fuzzable request and send it to the core
                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)

                """
                |Modified|
                old: regex_str = 'alt="PHP Logo" /></a><h1 class="p">PHP Version (.*?)</h1>'
                new: regex_str = '(<tr class="h"><td>\n|alt="PHP Logo" /></a>)<h1 class="p">PHP Version (.*?)</h1>'

                by aungkhant - I've been seeing phpinfo pages which don't print php logo image.
                One example, ning.com.

                """
                regex_str = '(<tr class="h"><td>\n|alt="PHP Logo" /></a>)<h1'\
                            ' class="p">PHP Version (.*?)</h1>'
                php_version = re.search(regex_str, response.get_body(), re.I)
示例#19
0
class phpinfo(CrawlPlugin):
    """
    Search PHP Info file and if it finds it will determine the version of PHP.
    :author: Viktor Gazdag ( [email protected] )
    :author: Aung Khant ( aungkhant[at]yehg.net )
    """
    PHP_VERSION_RE = re.compile('(<tr class="h"><td>\n|alt="PHP Logo" /></a>)'
                                '<h1 class="p">PHP Version (.*?)</h1>', re.I)
    SYSTEM_RE = re.compile('System </td><td class="v">(.*?)</td></tr>', re.I)

    def __init__(self):
        CrawlPlugin.__init__(self)

        # Internal variables
        self._analyzed_dirs = DiskSet(table_prefix='phpinfo')
        self._has_audited = False

    def crawl(self, fuzzable_request):
        """
        For every directory, fetch a list of files and analyze the response.

        :param fuzzable_request: A fuzzable_request instance that contains
                                    (among other things) the URL to test.
        """
        for domain_path in fuzzable_request.get_url().get_directories():

            if domain_path in self._analyzed_dirs:
                continue
            
            self._analyzed_dirs.add(domain_path)

            url_repeater = repeat(domain_path)
            args = izip(url_repeater, self._get_potential_phpinfos())

            self.worker_pool.map_multi_args(self._check_and_analyze, args)

    def _get_potential_phpinfos(self):
        """
        :return: Filename of the php info file.
        """
        res = ['phpinfo.php', 'PhpInfo.php', 'PHPinfo.php', 'PHPINFO.php',
               'phpInfo.php', 'info.php', 'test.php?mode=phpinfo',
               'index.php?view=phpinfo', 'index.php?mode=phpinfo',
               'TEST.php?mode=phpinfo', '?mode=phpinfo', '?view=phpinfo',
               'install.php?mode=phpinfo', 'INSTALL.php?mode=phpinfo',
               'admin.php?mode=phpinfo', 'phpversion.php', 'phpVersion.php',
               'test1.php', 'phpinfo1.php', 'phpInfo1.php', 'info1.php',
               'PHPversion.php', 'x.php', 'xx.php', 'xxx.php']

        identified_os = kb.kb.raw_read('fingerprint_os', 'operating_system_str')

        if not isinstance(identified_os, basestring):
            identified_os = cf.cf.get('target_os')

        # pylint: disable=E1103
        if 'windows' in identified_os.lower():
            res = list(set([path.lower() for path in res]))
        # pylint: enable=E1103

        return res

    def _check_and_analyze(self, domain_path, php_info_filename):
        """
        Check if a php_info_filename exists in the domain_path.
        :return: None, everything is put() into the self.output_queue.
        """
        php_info_url = domain_path.url_join(php_info_filename)
        try:
            response = self._uri_opener.GET(php_info_url, cache=True)
        except BaseFrameworkException, w3:
            msg = 'Failed to GET phpinfo file: "%s". Exception: "%s".'
            om.out.debug(msg % (php_info_url, w3))
            return

        # Needs to exist
        if is_404(response):
            return

        # Create the fuzzable request and send it to the core
        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)

        # Check if it's a phpinfo file
        php_version = self.PHP_VERSION_RE.search(response.get_body(), re.I)
        sysinfo = self.SYSTEM_RE.search(response.get_body(), re.I)

        if php_version and sysinfo:
            desc = ('The phpinfo() file was found at: %s. The version'
                    ' of PHP is: "%s" and the system information is:'
                    ' "%s".')
            desc %= (response.get_url(), php_version.group(2), sysinfo.group(1))

            v = Vuln('phpinfo() file found', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            if not self._has_audited:
                self._has_audited = True
                self.audit_phpinfo(response)