Beispiel #1
0
    def _origin_echo(self, forged_req, url, origin, response,
                     allow_origin, allow_credentials_str, allow_methods):
        """
        First check if the @allow_origin is set to the value we sent
        (@origin) and if the allow_credentials is set to True. If this test
        is successful (most important vulnerability) then do not check for
        the @allow_origin is set to the value we sent.

        :return: A list of vulnerability objects with the identified vulns
                 (if any).
        """
        if allow_origin is None:
            return

        allow_origin = allow_origin.lower()

        allow_credentials = False
        if allow_credentials_str is not None:
            allow_credentials = 'true' in allow_credentials_str.lower()

        if origin not in allow_origin:
            return

        if allow_credentials:
            sev = severity.HIGH
            name = 'Insecure Access-Control-Allow-Origin with credentials'
            msg = ('The remote Web application, specifically "%s", returned'
                   ' a "%s" header with the value set to the value sent in the'
                   ' request\'s Origin header and a %s header with the value'
                   ' set to "true", which is insecure and leaves the'
                   ' application open to Cross-domain attacks which can'
                   ' affect logged-in users.')
            msg = msg % (forged_req.get_url(),
                         ACCESS_CONTROL_ALLOW_ORIGIN,
                         ACCESS_CONTROL_ALLOW_CREDENTIALS)

            v = Vuln(name, msg, sev, response.get_id(), self.get_name())
            v.set_url(forged_req.get_url())
            v[DOMAIN] = forged_req.get_url().get_domain()

            self.kb_append_uniq_group(self, 'cors_origin', v,
                                      group_klass=OriginEchoWithCredsInfoSet)

        else:
            sev = severity.LOW
            name = 'Insecure Access-Control-Allow-Origin'
            msg = ('The remote Web application, specifically "%s", returned'
                   ' a "%s" header with the value set to the value sent in the'
                   ' request\'s Origin header, which is insecure and leaves'
                   ' the application open to Cross-domain attacks.')
            msg = msg % (forged_req.get_url(),
                         ACCESS_CONTROL_ALLOW_ORIGIN)

            v = Vuln(name, msg, sev, response.get_id(), self.get_name())
            v.set_url(forged_req.get_url())
            v[DOMAIN] = forged_req.get_url().get_domain()

            self.kb_append_uniq_group(self, 'cors_origin', v,
                                      group_klass=OriginEchoInfoSet)
Beispiel #2
0
    def _find_auth_uri(self, response):
        """
        Analyze a 200 response and report any findings of http://user:[email protected]/
        :return: None
        """
        #
        #   Analyze the HTTP URL
        #
        if self._url_has_auth(response.get_uri()):
            # An authentication URI was found!
            desc = ('The resource: "%s" has a user and password in'
                    ' the URI.')
            desc %= response.get_uri()
            v = Vuln('Basic HTTP credentials', desc, severity.HIGH,
                     response.id, self.get_name())

            v.set_url(response.get_url())
            v.add_to_highlight(response.get_uri().url_string)

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

        #
        #   Analyze the HTTP response body
        #
        url_list = []
        try:
            document_parser = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException as e:
            msg = 'Failed to find a suitable document parser. Exception: "%s"'
            om.out.debug(msg % e)
        else:
            parsed_references, re_references = document_parser.get_references()
            url_list.extend(parsed_references)
            url_list.extend(re_references)

        for url in url_list:

            if self._url_has_auth(url):

                desc = ('The resource: "%s" has a user and password in the'
                        ' body. The offending URL is: "%s".')
                desc %= (response.get_url(), url)
                
                v = Vuln('Basic HTTP credentials', desc,
                         severity.HIGH, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(url.url_string)

                kb.kb.append(self, 'userPassUri', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
    def grep(self, request, response):
        """
        Plugin entry point, test existence of HTML forms containing
        password-type inputs.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None, all results are saved in the kb.
        """
        url = request.get_url()
        proto = url.get_protocol()
        url_string = url.url_string

        try:
            dp = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException:
            # Failed to find a suitable parser for the document
            return

        for form in dp.get_forms():
            for p in form.keys():
                type = form._types.get(p)
                if type == 'password':
                    action = form.get_action()
                    action_proto = action.get_protocol()
                    # form is to be submitted over http
                    if action_proto == 'http':
                        desc = 'The URL: "%s" contains a <form> tag' \
                               ' which submits credentials over HTTP'
                        desc = desc % url_string
                        v = Vuln('Insecure password submission over HTTP',
                                 desc, severity.MEDIUM, response.id,
                                 self.get_name())
                        v.set_url(response.get_url())
                        self.kb_append_uniq(self, 'form_cleartext_password', v)
                        break

                    else:
                        # form was received over http
                        if proto == 'http':
                            desc = 'The URL: "%s" was delivered over the' \
                                   ' insecure HTTP protocol and has <form>' \
                                   ' which contains a password input'
                            desc = desc % url_string
                            v = Vuln('Insecure password form access over HTTP',
                                     desc, severity.MEDIUM, response.id,
                                     self.get_name())
                            self.kb_append_uniq(self,
                                                'form_cleartext_password', v)
                            break
Beispiel #4
0
    def _classic_worker(self, gh, search_term):
        """
        Perform the searches and store the results in the kb.
        """
        google_list = self._google_se.get_n_results(search_term, 9)

        for result in google_list:
            # I found a vuln in the site!
            response = self._uri_opener.GET(result.URL, cache=True)
            if not is_404(response):
                desc = ('ghdb plugin found a vulnerability at URL: "%s".'
                        ' According to GHDB the vulnerability description'
                        ' is "%s".')
                desc %= (response.get_url(), gh.desc)

                v = Vuln('Google hack database match', desc, severity.MEDIUM,
                         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=severity.LOW)

                # Create the fuzzable requests
                fr = FuzzableRequest(response.get_url())
                self.output_queue.put(fr)
Beispiel #5
0
    def _PROPFIND(self, domain_path):
        """
        Test PROPFIND method
        """
        content = "<?xml version='1.0'?>\r\n"
        content += "<a:propfind xmlns:a='DAV:'>\r\n"
        content += "<a:prop>\r\n"
        content += "<a:displayname:/>\r\n"
        content += "</a:prop>\r\n"
        content += "</a:propfind>\r\n"

        headers = copy.deepcopy(self.CONTENT_TYPE)
        headers['Depth'] = '1'

        res = self._uri_opener.PROPFIND(domain_path,
                                        data=content,
                                        headers=headers)

        if "D:href" in res and res.get_code() in xrange(200, 300):
            msg = 'Directory listing with HTTP PROPFIND method was found at' \
                  ' directory: "%s".' % domain_path

            v = Vuln('Insecure DAV configuration', msg, severity.MEDIUM,
                     res.id, self.get_name())

            v.set_url(res.get_url())
            v.set_method('PROPFIND')

            self.kb_append(self, 'dav', v)
Beispiel #6
0
    def _find_auth_uri(self, response):
        """
        Analyze a 200 response and report any findings of http://user:[email protected]/
        :return: None
        """
        #
        #   Analyze the HTTP URL
        #
        if ('@' in response.get_uri()
                and self._auth_uri_regex.match(response.get_uri().url_string)):
            # An authentication URI was found!
            desc = 'The resource: "%s" has a user and password in' \
                   ' the URI.'
            desc = desc % response.get_uri()
            v = Vuln('Basic HTTP credentials', desc, severity.HIGH,
                     response.id, self.get_name())

            v.set_url(response.get_url())
            v.add_to_highlight(response.get_uri().url_string)

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

        #
        #   Analyze the HTTP response body
        #
        url_list = []
        try:
            DocumentParser = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException, w3:
            msg = 'Failed to find a suitable document parser. ' \
                  'Exception: ' + str(w3)
            om.out.debug(msg)
Beispiel #7
0
    def _analyze_SQL(self, request, response, ref, token_name, token_value):
        """
        To find this kind of vulns

        http://thedailywtf.com/Articles/Oklahoma-
            Leaks-Tens-of-Thousands-of-Social-Security-Numbers,-Other-
            Sensitive-Data.aspx

        :return: True if the parameter value contains SQL sentences
        """
        for match in SQL_RE.findall(token_value):
            if request.sent(match):
                continue

            desc = ('The URI: "%s" has a parameter named: "%s" with value:'
                    ' "%s", which is a SQL query.')
            desc %= (response.get_uri(), token_name, token_value)

            v = Vuln('Parameter has SQL sentence', desc, severity.LOW,
                     response.id, self.get_name())
            v['parameter_value'] = token_value
            v.add_to_highlight(token_value)
            v.set_uri(ref)

            self.kb_append(self, 'strange_parameters', v)
            return True

        return False
Beispiel #8
0
    def _send_and_check(self, repo_url, repo_get_files, repo, domain_path):
        """
        Check if a repository index exists in the domain_path.

        :return: None, everything is saved to the self.out_queue.
        """
        http_response = self.http_get_and_parse(repo_url)

        if not is_404(http_response):

            filenames = repo_get_files(http_response.get_body())

            parsed_url_set = set()

            for filename in self._clean_filenames(filenames):
                test_url = domain_path.url_join(filename)
                if test_url not in self._analyzed_filenames:
                    parsed_url_set.add(test_url)
                    self._analyzed_filenames.add(filename)

            self.worker_pool.map(self.http_get_and_parse, parsed_url_set)

            if parsed_url_set:
                desc = 'A %s was found at: "%s"; this could indicate that'\
                       ' a %s is accessible. You might be able to download'\
                       ' the Web application source code.'
                desc = desc % (repo, http_response.get_url(), repo)
                
                v = Vuln('Source code repository', desc, severity.MEDIUM,
                         http_response.id, self.get_name())
                v.set_url(http_response.get_url())
                
                kb.kb.append(self, repo, v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Beispiel #9
0
    def end(self):
        # If all URLs implement protection, don't report anything.
        if not self._vuln_count:
            return

        response_ids = [_id for _id in self._ids]

        # If none of the URLs implement protection, simply report
        # ONE vulnerability that says that.
        if self._total_count == self._vuln_count:
            desc = 'The whole target has no protection (X-Frame-Options'\
                  ' header) against Click-Jacking attacks'
        # If most of the URLs implement the protection but some
        # don't, report ONE vulnerability saying: "Most are protected,
        # but x, y are not.
        if self._total_count > self._vuln_count:
            desc = 'Some URLs have no protection (X-Frame-Options header) '\
                  'against Click-Jacking attacks. Among them:\n '\
                  ' '.join([str(url) + '\n' for url in self._vulns])

        v = Vuln('Click-Jacking vulnerability', desc, severity.MEDIUM,
                 response_ids, self.get_name())

        self.kb_append(self, 'click_jacking', v)

        self._vulns.cleanup()
        self._ids.cleanup()
Beispiel #10
0
    def end(self):
        """
        This method is called when the plugin wont be used anymore.

        The real job of this plugin is done here, where I will try to see if
        one of the error_500 responses were not identified as a vuln by some
        of my audit plugins
        """
        all_vuln_ids = set()

        for info in kb.kb.get_all_findings_iter():
            for _id in info.get_id():
                all_vuln_ids.add(_id)

        for request, error_500_response_id in self._error_500_responses:

            if error_500_response_id not in all_vuln_ids:
                # Found a error 500 that wasn't identified !
                desc = ('An unidentified web application error (HTTP response'
                        ' code 500) was found at: "%s". Enable all plugins and'
                        ' try again, if the vulnerability still is not'
                        ' identified, please verify manually and report it to'
                        ' the w3af developers.')
                desc %= request.get_url()

                v = Vuln('Unhandled error in web application',
                         desc, severity.MEDIUM, error_500_response_id,
                         self.get_name())

                v.set_uri(request.get_uri())

                self.kb_append_uniq(self, 'error_500', v, 'VAR')

        self._error_500_responses.cleanup()
Beispiel #11
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the credit cards.
        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        if not response.get_code() == 200:
            return

        clear_text_body = response.get_clear_text_body()

        if clear_text_body is None:
            return

        found_cards = self._find_card(clear_text_body)

        for card in found_cards:
            desc = u'The URL: "%s" discloses the credit card number: "%s"'
            desc %= (response.get_url(), card)

            v = Vuln('Credit card number disclosure', desc,
                     severity.LOW, response.id, self.get_name())

            v.set_url(response.get_url())
            v.add_to_highlight(card)

            self.kb_append_uniq(self, 'credit_cards', v, 'URL')
Beispiel #12
0
    def test_no_duplicate_vuln_reports(self):
        # The xml_file plugin had a bug where vulnerabilities were written to
        # disk multiple times, this test makes sure I fixed that vulnerability

        # First we create one vulnerability in the KB
        self.kb.cleanup()
        desc = 'Just a test for the XML file output plugin.'
        v = Vuln('SQL injection', desc, severity.HIGH, 1, 'sqli')
        self.kb.append('sqli', 'sqli', v)

        self.assertEqual(len(self.kb.get_all_vulns()), 1)

        # Setup the plugin
        plugin_instance = xml_file()

        # Set the output file for the unittest
        ol = OptionList()
        d = 'Output file name where to write the XML data'
        o = opt_factory('output_file', self.FILENAME, d, OUTPUT_FILE)
        ol.add(o)

        # Then we flush() twice to disk, this reproduced the issue
        plugin_instance.set_options(ol)
        plugin_instance.flush()
        plugin_instance.flush()
        plugin_instance.flush()

        # Now we parse the vulnerabilities from disk and confirm only one
        # is there
        file_vulns = self._from_xml_get_vulns(self.FILENAME)
        self.assertEqual(len(file_vulns), 1, file_vulns)
Beispiel #13
0
    def grep(self, request, response):
        """
        Plugin entry point, search for directory indexing.
        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        if response.get_url().get_domain_path() in self._already_visited:
            return

        self._already_visited.add(response.get_url().get_domain_path())

        html_string = response.get_body()
        if self._multi_in.query(html_string):

            desc = 'The URL: "%s" has a directory indexing vulnerability.'
            desc = desc % response.get_url()

            v = Vuln('Directory indexing', desc, severity.LOW, response.id,
                     self.get_name())
            v.set_url(response.get_url())

            self.kb_append_uniq(self, 'directory', v, 'URL')
Beispiel #14
0
    def _universal_allow(self, forged_req, url, origin, response, allow_origin,
                         allow_credentials, allow_methods):
        """
        Check if the allow_origin is set to *.

        :return: A list of vulnerability objects with the identified vulns
                 (if any).
        """
        if allow_origin == '*':
            msg = 'The remote Web application, specifically "%s", returned' \
                  ' an %s header with the value set to "*" which is insecure'\
                  ' and leaves the application open to Cross-domain attacks.'
            msg = msg % (forged_req.get_url(), ACCESS_CONTROL_ALLOW_ORIGIN)

            v = Vuln('Access-Control-Allow-Origin set to "*"', msg,
                     severity.LOW, response.get_id(), self.get_name())

            v.set_url(forged_req.get_url())

            self.kb_append(self, 'cors_origin', v)

            return self._filter_report('_universal_allow_counter',
                                       'universal allow-origin',
                                       severity.MEDIUM, [
                                           v,
                                       ])

        return []
Beispiel #15
0
    def _analyze_headers(self, request, response):
        """
        Search for IP addresses in HTTP headers
        """
        # Get the headers string
        headers_string = response.dump_headers()

        #   Match the regular expressions
        for regex in self._regex_list:
            for match in regex.findall(headers_string):

                # If i'm requesting 192.168.2.111 then I don't want to be
                # alerted about it
                if match not in self._ignore_if_match:
                    desc = 'The URL: "%s" returned an HTTP header with a'\
                           ' private IP address: "%s".'
                    desc = desc % (response.get_url(), match)
                    v = Vuln('Private IP disclosure vulnerability', desc,
                             severity.LOW, response.id, self.get_name())

                    v.set_url(response.get_url())

                    v['IP'] = match
                    v.add_to_highlight(match)
                    self.kb_append(self, 'header', v)
Beispiel #16
0
        def write_vuln_to_kb(vulnty, url, funcs):
            vulndata = php_sca.KB_DATA[vulnty]
            for f in funcs:
                vuln_sev = vulndata['severity']
                desc = name = vulndata['name']

                v = Vuln(name, desc, vuln_sev, 1, 'PHP Static Code Analyzer')
                v.set_uri(url)
                v.set_token((f.vulnsources[0], 0))

                args = list(vulndata['kb_key']) + [v]

                # TODO: Extract the method from the PHP code
                #     $_GET == GET
                #     $_POST == POST
                #     $_REQUEST == GET
                v.set_method('GET')

                # TODO: Extract all the other variables that are
                # present in the PHP file using the SCA
                v.set_dc(DataContainer())

                #
                # TODO: This needs to be checked! OS Commanding specific
                #       attributes.
                v['os'] = 'unix'
                v['separator'] = ''

                kb.kb.append(*args)
Beispiel #17
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)
Beispiel #18
0
    def crawl(self, fuzzable_request):
        """
        Plugin entry point, performs all the work.
        """
        to_check = self._get_to_check(fuzzable_request.get_url())

        # I found some URLs, create fuzzable requests
        pt_matches = self._is_in_phishtank(to_check)

        for ptm in pt_matches:
            fr = FuzzableRequest(ptm.url)
            self.output_queue.put(fr)

        # Only create the vuln object once
        if pt_matches:
            desc = 'The URL: "%s" seems to be involved in a phishing scam.' \
                   ' Please see %s for more info.'
            desc = desc % (ptm.url, ptm.more_info_url)

            v = Vuln('Phishing scam', desc, severity.MEDIUM, [],
                     self.get_name())
            v.set_url(ptm.url)

            kb.kb.append(self, 'phishtank', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Beispiel #19
0
    def crawl(self, fuzzable_request, debugging_id):
        """
        Plugin entry point, performs all the work.

        :param debugging_id: A unique identifier for this call to discover()
        :param fuzzable_request: A fuzzable_request instance that contains
                                    (among other things) the URL to test.
        """
        to_check = self._get_to_check(fuzzable_request.get_url())

        # I found some URLs, create fuzzable requests
        pt_matches = self._is_in_phishtank(to_check)

        if not pt_matches:
            return

        for ptm in pt_matches:
            fr = FuzzableRequest(ptm.url)
            self.output_queue.put(fr)

        desc = ('The URL: "%s" seems to be involved in a Phishing scam.'
                ' Please see %s for more info.')
        desc %= (ptm.url, ptm.more_info_url)

        v = Vuln('Phishing scam', desc, severity.MEDIUM, [], self.get_name())
        v.set_url(ptm.url)

        kb.kb.append(self, 'phishtank', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Beispiel #20
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)
Beispiel #21
0
    def end(self):
        # If all URLs implement protection, don't report anything.
        if not self._vuln_count:
            return

        # If none of the URLs implement protection, simply report
        # ONE vulnerability that says that.
        if self._total_count == self._vuln_count:
            desc = 'The whole target web application has no protection (Pragma'\
                   ' and Cache-Control headers) against sensitive content'\
                   ' caching.'
            
        # If most of the URLs implement the protection but some
        # don't, report ONE vulnerability saying: "Most are protected, but x, y
        # are not.
        if self._total_count > self._vuln_count:
            desc = 'Some URLs have no protection (Pragma and Cache-Control'\
                   ' headers) against sensitive content caching. Among them:\n'
            desc += ' '.join([str(url) + '\n' for url in self._vulns])
        
        response_ids = [_id for _id in self._ids]
        
        v = Vuln('Missing cache control for HTTPS content', desc,
                 severity.LOW, response_ids, self.get_name())
        
        self.kb_append_uniq(self, 'cache_control', v, 'URL')
        
        self._vulns.cleanup()
        self._ids.cleanup()
Beispiel #22
0
    def grep(self, request, response):
        """
        Plugin entry point.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None, all results are saved in the kb.
        """
        if not response.is_text_or_html():
            return

        uri = response.get_uri()

        for regex in self.RE_LIST:
            for m in regex.findall(response.get_body()):
                user = m[0]

                desc = 'The URL: "%s" contains a SVN versioning signature' \
                       ' with the username "%s".'
                desc = desc % (uri, user)

                v = Vuln('SVN user disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())
                v.add_to_highlight(user)
                v.set_uri(uri)
                v[SVNUserInfoSet.ITAG] = user

                self.kb_append_uniq_group(self,
                                          'users',
                                          v,
                                          group_klass=SVNUserInfoSet)
Beispiel #23
0
    def _check_methods(self, url):
        """
        Perform some requests in order to check if we are able to retrieve
        some data with methods that may be wrongly enabled.
        """
        allowed_methods = []
        for method in ['GET', 'POST', 'ABCD', 'HEAD']:
            method_functor = getattr(self._uri_opener, method)
            try:
                response = apply(method_functor, (url, ), {})
                code = response.get_code()
            except:
                pass
            else:
                if code not in self.BAD_METHODS:
                    allowed_methods.append((method, response.id))

        if len(allowed_methods) > 0:

            response_ids = [i for m, i in allowed_methods]
            methods = ', '.join([m for m, i in allowed_methods]) + '.'
            desc = 'The resource: "%s" requires authentication but the access'\
                   ' is misconfigured and can be bypassed using these'\
                   ' methods: %s.'
            desc = desc % (url, methods)

            v = Vuln('Misconfigured access control', desc, severity.MEDIUM,
                     response_ids, self.get_name())

            v.set_url(url)
            v['methods'] = allowed_methods

            self.kb_append(self, 'auth', v)
Beispiel #24
0
    def _lowest_privilege_test(self, response):
        regex_str = 'User/Group </td><td class="v">(.*?)\((\d.*?)\)/(\d.*?)</td>'
        lowest_privilege_test = re.search(regex_str, response.get_body(), re.I)
        if lowest_privilege_test:
            lpt_uname = lowest_privilege_test.group(1)
            lpt_uid = lowest_privilege_test.group(2)
            lpt_uid = int(lpt_uid)
            lpt_gid = lowest_privilege_test.group(3)
            if lpt_uid < 99 or lpt_gid < 99 or \
            re.match('root|apache|daemon|bin|operator|adm', lpt_uname, re.I):

                desc = 'phpinfo()::PHP may be executing as a higher privileged'\
                       ' group. Username: %s, UserID: %s, GroupID: %s.' 
                desc = desc % (lpt_uname, lpt_uid, lpt_gid)
                
                v = Vuln('PHP lowest_privilege_test:fail', 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())
            else:
                lpt_name = 'privilege:' + lpt_uname
                lpt_desc = 'phpinfo()::PHP is executing under '
                lpt_desc += 'username: '******', '
                lpt_desc += 'userID: ' + str(lpt_uid) + ', '
                lpt_desc += 'groupID: ' + lpt_gid
                i = Info(lpt_name, lpt_desc, response.id, self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', i)
                om.out.information(i.get_desc())
Beispiel #25
0
    def end(self):
        """
        This method is called when the plugin wont be used anymore.

        The real job of this plugin is done here, where I will try to see if
        one of the error_500 responses were not identified as a vuln by some
        of my audit plugins
        """
        all_vulns = kb.kb.get_all_vulns()
        all_vulns_tuples = [(v.get_uri(), v.get_dc()) for v in all_vulns]

        for request, error_500_response_id in self._error_500_responses:
            if (request.get_uri(), request.get_dc()) not in all_vulns_tuples:
                # Found a err 500 that wasnt identified !!!
                desc = 'An unidentified web application error (HTTP response'\
                       ' code 500) was found at: "%s". Enable all plugins and'\
                       ' try again, if the vulnerability still is not identified'\
                       ', please verify manually and report it to the w3af'\
                       ' developers.'
                desc = desc % request.get_url()

                v = Vuln('Unhandled error in web application',
                         desc, severity.MEDIUM, error_500_response_id,
                         self.get_name())

                v.set_uri(request.get_uri())

                self.kb_append_uniq(self, 'error_500', v, 'VAR')

        self._error_500_responses.cleanup()
Beispiel #26
0
def disable_functions(response):
    regex_str = 'disable_functions</td><td class="v">(.*?)</td>'
    disable_functions_mo = re.search(regex_str, response.get_body(), re.I)

    if not disable_functions_mo:
        return

    secure_df = 8
    df = disable_functions_mo.group(1)
    dfe = df.split(',')

    if len(dfe) >= secure_df:
        return

    desc = ('The phpinfo()::disable_functions does NOT seem to be set. This'
            ' configuration parameter is a good indicator of a security'
            '-enabled PHP installation. The disabled functions are: %s')
    desc %= (', '.join(dfe), )

    v = Vuln('PHP disable_functions weakness', desc, severity.MEDIUM,
             response.id, 'phpinfo')
    v.set_url(response.get_url())

    kb.kb.append('phpinfo', 'phpinfo', v)
    om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Beispiel #27
0
    def _SEARCH(self, domain_path):
        """
        Test SEARCH method.
        """
        content = "<?xml version='1.0'?>\r\n"
        content += "<g:searchrequest xmlns:g='DAV:'>\r\n"
        content += "<g:sql>\r\n"
        content += "Select 'DAV:displayname' from scope()\r\n"
        content += "</g:sql>\r\n"
        content += "</g:searchrequest>\r\n"

        res = self._uri_opener.SEARCH(domain_path,
                                      data=content,
                                      headers=self.CONTENT_TYPE)

        content_matches = '<a:response>' in res or '<a:status>' in res or \
            'xmlns:a="DAV:"' in res

        if content_matches and res.get_code() in xrange(200, 300):
            msg = 'Directory listing with HTTP SEARCH method was found at' \
                  'directory: "%s".' % domain_path

            v = Vuln('Insecure DAV configuration', msg, severity.MEDIUM,
                     res.id, self.get_name())

            v.set_url(res.get_url())
            v.set_method('SEARCH')

            self.kb_append(self, 'dav', v)
Beispiel #28
0
def upload_max_filesize(response):
    regex_str = 'upload_max_filesize</td><td class="v">(\d.*?)</td>'
    upload_max_filesize_mo = re.search(regex_str, response.get_body(),
                                       re.IGNORECASE)

    if not upload_max_filesize_mo:
        return

    secure_umf = 20
    umf = upload_max_filesize_mo.group(1) + ''
    umf = umf.replace('M', '')
    umf = int(umf)

    if umf <= secure_umf:
        return

    desc = 'The phpinfo()::upload_max_filesize is set to a high value: %s'
    desc %= (upload_max_filesize_mo.group(1), )

    v = Vuln('PHP upload_max_filesize:high', desc, severity.LOW, response.id,
             'phpinfo')
    v.set_url(response.get_url())

    kb.kb.append('phpinfo', 'phpinfo', v)
    om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Beispiel #29
0
    def discover(self, fuzzable_request, debugging_id):
        """
        Detect CVE-2015-2080 aka. JetLeak

        :param debugging_id: A unique identifier for this call to discover()
        :param fuzzable_request: A fuzzable_request instance that contains
                                    (among other things) the URL to test.
        """
        url = fuzzable_request.get_url()
        headers = Headers([('Referer', '\x00')])

        response = self._uri_opener.GET(url,
                                        cache=False,
                                        grep=False,
                                        headers=headers)

        if response.get_code() != 400:
            return

        if 'Illegal character 0x0 in state' not in response.get_msg():
            return

        desc = ('The application appears to be running a version of Jetty'
                ' vulnerable to CVE-2015-2080, which allows attackers to'
                ' read arbitrary server memory buffers')

        v = Vuln('JetLeak', desc, HIGH, response.id, self.get_name())
        v.set_url(response.get_url())

        self.kb_append_uniq(self, 'jetleak', v)
Beispiel #30
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the credit cards.
        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if response.is_text_or_html() and response.get_code() == 200 \
                and response.get_clear_text_body() is not None:

            found_cards = self._find_card(response.get_clear_text_body())

            for card in found_cards:
                desc = 'The URL: "%s" discloses the credit card number: "%s"'
                desc = desc % (response.get_url(), card)

                v = Vuln('Credit card number disclosure', desc,
                         severity.INFORMATION, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(card)

                om.out.vulnerability(v.get_desc(),
                                     severity=severity.INFORMATION)
                self.kb_append_uniq(self, 'credit_cards', v, 'URL')