Example #1
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)
Example #2
0
    def _analyze_param(self, request, response, parameter_name,
                       parameter_value, language, serialized_object_re):
        """
        Check if one parameter holds a serialized object

        :param request: The HTTP request which holds the parameter
        :param response: The HTTP response
        :param parameter_name: The name of the parameter
        :param parameter_value: The parameter value (might have been decoded from b64)
        :param language: The programming language
        :param serialized_object_re: The regular expression to match
        :return: None. We just save the vulnerability to the KB
        """
        if not serialized_object_re.search(parameter_value):
            return

        # We found a match! The parameter value is a serialized object
        # Just report this to get the user's attention
        desc = ('Identified a %s serialized object being sent by the web'
                ' application in a request to "%s" in a parameter named "%s".'
                ' While this is not a vulnerability by itself, it is a strong'
                ' indicator of potential insecure deserialization issues.')
        desc %= (language, request.get_url(), parameter_name)

        v = Vuln('Serialized object', desc, severity.LOW, response.id,
                 self.get_name())

        v.set_url(response.get_url())
        v.add_to_highlight(parameter_value)
        v[SerializedObjectInfoSet.ITAG] = parameter_name

        self.kb_append_uniq_group(self,
                                  'serialized_object',
                                  v,
                                  group_klass=SerializedObjectInfoSet)
Example #3
0
    def _analyze_html(self, request, response):
        """
        Search for IP addresses in the HTML
        """
        if not response.is_text_or_html():
            return

        # Performance improvement!
        if not (('10.' in response) or ('172.' in response) or
               ('192.168.' in response) or ('169.254.' in response)):
            return

        for regex in self._regex_list:
            for match in regex.findall(response.get_body()):
                match = match.strip()

                # Some proxy servers will return errors that include headers in the body
                # along with the client IP which we want to ignore
                if re.search("^.*X-Forwarded-For: .*%s" % match, response.get_body(), re.M):
                    continue

                # 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 and \
                not request.sent(match):
                    desc = 'The URL: "%s" returned an HTML document'\
                           ' 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, 'HTML', v)
Example #4
0
    def grep(self, request, response):
        """
        Plugin entry point, find the SSN numbers.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None.
        """
        if not response.is_text_or_html() or response.get_code() != 200 \
                or response.get_clear_text_body() is None:
            return

        found_ssn, validated_ssn = self._find_SSN(
            response.get_clear_text_body())

        if validated_ssn:
            uri = response.get_uri()
            desc = 'The URL: "%s" possibly discloses a US Social Security' \
                   ' Number: "%s".'
            desc = desc % (uri, validated_ssn)
            v = Vuln('US Social Security Number disclosure', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_uri(uri)

            v.add_to_highlight(found_ssn)
            self.kb_append_uniq(self, 'ssn', v, 'URL')
Example #5
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
Example #6
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')
Example #7
0
    def grep(self, request, response):
        """
        Plugin entry point, find the SSN numbers.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None.
        """
        if not response.is_text_or_html() or response.get_code() != 200 \
        or response.get_clear_text_body() is None:
            return

        found_ssn, validated_ssn = self._find_SSN(response.get_clear_text_body())
        
        if validated_ssn:
            uri = response.get_uri()
            desc = 'The URL: "%s" possibly discloses a US Social Security'\
                   ' Number: "%s".'
            desc = desc % (uri, validated_ssn)
            v = Vuln('US Social Security Number disclosure', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_uri(uri)

            v.add_to_highlight(found_ssn)
            self.kb_append_uniq(self, 'ssn', v, 'URL')
Example #8
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)
Example #9
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')
Example #10
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)
Example #11
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)
Example #12
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)
Example #13
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)
Example #14
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
Example #15
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())
Example #16
0
    def _analyze_match(self, match, request, response):
        # This if is to avoid false positives
        if request.sent(match):
            return False

        if self._is_attr_value(match, response):
            return False

        # Decode the URL, this will transform things like
        #     http://host.tld/?id=%2Fhome
        # into,
        #     http://host.tld/?id=/home
        realurl = response.get_url().url_decode()

        # Check for dups
        if (realurl, match) in self._already_added:
            return False

        #   There is a rare bug also, which is triggered in cases like this one:
        #
        #   >>> import re
        #   >>> re.findall('/var/www/.*','/var/www/foobar/htdocs/article.php')
        #   ['/var/www/foobar/htdocs/article.php']
        #   >>> re.findall('/htdocs/.*','/var/www/foobar/htdocs/article.php')
        #   ['/htdocs/article.php']
        #   >>>
        #
        #   What I need to do here, is to keep the longest match.
        for realurl_added, match_added in self._already_added:
            if match_added.endswith(match):
                break
        else:
            #   Note to self: I get here when "break" is NOT executed.
            #   It's a new one, report!
            self._already_added.append((realurl, match))

            desc = 'The URL: "%s" has a path disclosure'\
                   ' vulnerability which discloses "%s".'
            desc = desc % (response.get_url(), match)

            v = Vuln('Path disclosure vulnerability', desc, severity.LOW,
                     response.id, self.get_name())

            v.set_url(realurl)
            v['path'] = match
            v.add_to_highlight(match)

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

        return False
Example #17
0
    def grep(self, request, response):
        """
        Plugin entry point, test existence of HTML auto-completable forms
        containing password-type inputs. Either form's <autocomplete> attribute
        is not present or is 'off'.

        :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

        try:
            doc_parser = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException:
            return

        for form in doc_parser.get_forms():

            # Only analyze forms which have autocomplete enabled at <form>
            if form.get_autocomplete() is False:
                continue

            for form_field_list in form.meta.itervalues():
                for form_field in form_field_list:
                    if form_field.input_type != INPUT_TYPE_PASSWD:
                        continue

                    if not form_field.autocomplete:
                        continue

                    url = response.get_url()
                    desc = ('The URL: "%s" has a "<form>" element with '
                            'auto-complete enabled.')
                    desc %= url

                    v = Vuln('Auto-completable form',
                             desc, severity.INFORMATION, response.id,
                             self.get_name())
                    v.add_to_highlight('autocomplete')
                    v.set_url(url)

                    #om.out.vulnerability(v.get_desc(), severity=severity.INFORMATION)
                    self.kb_append_uniq(self,
                                        'form_autocomplete',
                                        v,
                                        filter_by='URL')
                    break
Example #18
0
    def _grep_worker(self, request, response, kb_key, domain=None):
        """
        Helper method for using in self.grep()

        :param request: The HTTP request
        :param response: The HTTP response
        :param kb_key: Knowledge base dict key
        :param domain: Target domain for get_emails filter
        :return: None
        """
        try:
            dp = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException:
            msg = 'Failed to get document parser for "%s" at get_emails.'
            om.out.debug(msg % response.get_url())
            return

        emails = set(dp.get_emails(domain))

        for mail_address in emails:
            # Reduce false positives
#            if request.sent(mail_address):
#                continue

            # Email address are case insensitive
            mail_address = mail_address.lower()
            url = response.get_url()
            uniq_key = (mail_address, url)

            if uniq_key in self._already_reported:
                continue

            # Avoid dups
            self._already_reported.add(uniq_key)

            # Create a new info object, and report it
            desc = 'The mail account: "%s" was found at "%s".'
            desc = desc % (mail_address, url)
            
            v = Vuln('Email address disclosure', desc, severity.INFORMATION, response.id,
                     self.get_name())
            v.add_to_highlight(mail_address)
            v.set_url(url)
            v[EmailInfoSet.ITAG] = mail_address
            v['user'] = mail_address.split('@')[0]

            self.kb_append_uniq_group('emails', kb_key, v,
                                      group_klass=EmailInfoSet)
Example #19
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the code disclosures.

        Unit tests are available at plugins/grep/tests.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        response_is_404 = is_404(response)

        # This is a performance improvement to prevent the plugin from
        # applying contains_source_code to a 404 response that will be
        # discarded even if it matches
        if response_is_404 and not self._report_404_match:
            return

        match, lang = contains_source_code(response)

        if not match:
            return

        # Only report 404 findings once
        if response_is_404 and self._report_404_match:
            self._report_404_match = False

            desc = (u'The URL: "%s" has a %s code disclosure'
                    u' vulnerability in the customized 404 script.')
            name = u'Code disclosure vulnerability in 404 page'
        else:
            desc = u'The URL: "%s" has a %s code disclosure vulnerability.'
            name = u'Code disclosure vulnerability'

        # Report the vulnerability
        desc %= (response.get_url(), ' or '.join(list(lang)))

        v = Vuln(name, desc, severity.LOW, response.id, self.get_name())
        v.set_url(response.get_url())
        v.add_to_highlight(match.group())

        self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
Example #20
0
    def _analyze_html(self, request, response):
        """
        Search for IP addresses in the HTML
        """
        if not response.is_text_or_html():
            return

        # Performance improvement!
        if not (('10.' in response) or ('172.' in response) or
                ('192.168.' in response) or ('169.254.' in response)):
            return

        for regex in self.RE_LIST:
            for ip_address in regex.findall(response.get_body()):
                ip_address = ip_address.strip()

                # Some proxy servers will return errors that include headers
                # in the body along with the client IP which we want to ignore
                if re.search("^.*X-Forwarded-For: .*%s" % ip_address,
                             response.get_body(), re.M):
                    continue

                # If i'm requesting 192.168.2.111 then I don't want to be
                # alerted about it
                if ip_address in self._ignore_if_match:
                    continue

                # Don't match things I've sent
                if request.sent(ip_address):
                    continue

                desc = 'The URL: "%s" returned an HTML document which' \
                       ' contains the private IP address: "%s".'
                desc = desc % (response.get_url(), ip_address)
                v = Vuln('Private IP disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(ip_address)
                v[HTMLPrivateIPInfoSet.ITAG] = ip_address

                self.kb_append_uniq_group(self,
                                          'HTML',
                                          v,
                                          group_klass=HTMLPrivateIPInfoSet)
Example #21
0
    def _check_x_power(self, fuzzable_request):
        """
        Analyze X-Powered-By header.
        """
        response = self._uri_opener.GET(fuzzable_request.get_url(), cache=True)

        for header_name in response.get_headers().keys():
            for i in ['ASPNET', 'POWERED']:
                if i in header_name.upper() or header_name.upper() in i:
                    powered_by = response.get_headers()[header_name]

                    # Only get the first one
                    self._x_powered = False

                    #
                    #    Check if I already have this info in the KB
                    #
                    pow_by_kb = kb.kb.get('server_header', 'powered_by')
                    powered_by_in_kb = [j['powered_by'] for j in pow_by_kb]
                    if powered_by not in powered_by_in_kb:

                        #
                        #    I don't have it in the KB, so I need to add it,
                        #
                        desc = 'The %s header for the target HTTP server is "%s".'
                        desc = desc % (header_name, powered_by)
                        
                        v = Vuln('Powered-by header', desc, severity.INFORMATION, response.id,
                                 self.get_name())
                        v['powered_by'] = powered_by
                        v.add_to_highlight(header_name + ':')

                        # Save the results in the KB so that other plugins can
                        # use this information. Before knowing that some servers
                        # may return more than one poweredby header I had:
                        #     kb.kb.raw_write( self , 'powered_by' , powered_by )
                        # But I have seen an IIS server with PHP that returns
                        # both the ASP.NET and the PHP headers
                        kb.kb.append(self, 'powered_by', v)
                        
                        # Update the list and save it,
                        powered_by_in_kb.append(powered_by)
                        kb.kb.raw_write(self, 'powered_by_string',
                                        powered_by_in_kb)
Example #22
0
    def _analyze_html(self, request, response):
        """
        Search for IP addresses in the HTML
        """
        if not response.is_text_or_html():
            return

        # Performance improvement!
        if not (('10.' in response) or ('172.' in response) or
               ('192.168.' in response) or ('169.254.' in response)):
            return

        for regex in self.RE_LIST:
            for ip_address in regex.findall(response.get_body()):
                ip_address = ip_address.strip()

                # Some proxy servers will return errors that include headers
                # in the body along with the client IP which we want to ignore
                if re.search("^.*X-Forwarded-For: .*%s" % ip_address,
                             response.get_body(), re.M):
                    continue

                # If i'm requesting 192.168.2.111 then I don't want to be
                # alerted about it
                if ip_address in self._ignore_if_match:
                    continue

                # Don't match things I've sent
                if request.sent(ip_address):
                    continue

                desc = 'The URL: "%s" returned an HTML document which' \
                       ' contains the private IP address: "%s".'
                desc = desc % (response.get_url(), ip_address)
                v = Vuln('Private IP disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(ip_address)
                v[HTMLPrivateIPInfoSet.ITAG] = ip_address

                self.kb_append_uniq_group(self, 'HTML', v,
                                          group_klass=HTMLPrivateIPInfoSet)
Example #23
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the code disclosures.

        Unit tests are available at plugins/grep/tests.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        # https://github.com/andresriancho/w3af/issues/5379
        # Avoid some (rather common) false positives that appear in JS files
        if 'javascript' in response.content_type:
            return

        match, lang = is_source_file(response.get_body())

        if not match:
            return

        # Only report 404 findings once
        if is_404(response) and self._report_404_match:
            self._report_404_match = False

            desc = u'The URL: "%s" has a %s code disclosure' \
                   u' vulnerability in the customized 404 script.'
            name = u'Code disclosure vulnerability in 404 page'
        else:
            desc = u'The URL: "%s" has a %s code disclosure vulnerability.'
            name = u'Code disclosure vulnerability'

        # Report the vulnerability
        desc %= (response.get_url(), lang)

        v = Vuln(name, desc, severity.INFORMATION, response.id, self.get_name())
        v.set_url(response.get_url())
        v.add_to_highlight(match.group())
        
        om.out.vulnerability(v.get_desc(), severity=severity.INFORMATION)
        self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
Example #24
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the code disclosures.

        Unit tests are available at plugins/grep/tests.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        # https://github.com/andresriancho/w3af/issues/5379
        # Avoid some (rather common) false positives that appear in JS files
        if 'javascript' in response.content_type:
            return

        match, lang = is_source_file(response.get_body())

        if not match:
            return

        # Only report 404 findings once
        if is_404(response) and self._report_404_match:
            self._report_404_match = False

            desc = u'The URL: "%s" has a %s code disclosure' \
                   u' vulnerability in the customized 404 script.'
            name = u'Code disclosure vulnerability in 404 page'
        else:
            desc = u'The URL: "%s" has a %s code disclosure vulnerability.'
            name = u'Code disclosure vulnerability'

        # Report the vulnerability
        desc %= (response.get_url(), lang)

        v = Vuln(name, desc, severity.LOW, response.id, self.get_name())
        v.set_url(response.get_url())
        v.add_to_highlight(match.group())
        
        self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
Example #25
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the code disclosures.

        Unit tests are available at plugins/grep/tests.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        match, lang = is_source_file(response.get_body())

        if match:
            # Check also for 404
            if not is_404(response):
                desc = 'The URL: "%s" has a %s code disclosure vulnerability.'
                desc = desc % (response.get_url(), lang)

                v = Vuln('Code disclosure vulnerability', desc, severity.LOW,
                         response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(match.group())

                self.kb_append_uniq(self, 'code_disclosure', v, 'URL')

            else:
                self._first_404 = False

                desc = 'The URL: "%s" has a %s code disclosure'\
                       ' vulnerability in the customized 404 script.'
                desc = desc % (response.get_url(), lang)

                v = Vuln('Code disclosure vulnerability in 404 page', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(match.group())
                self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
Example #26
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the code disclosures.

        Unit tests are available at plugins/grep/tests.

        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return
        
        match, lang = is_source_file(response.get_body())

        if match:
            # Check also for 404
            if not is_404(response):
                desc = 'The URL: "%s" has a %s code disclosure vulnerability.'
                desc = desc % (response.get_url(), lang)
                
                v = Vuln('Code disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(match.group())
                
                self.kb_append_uniq(self, 'code_disclosure', v, 'URL')

            else:
                self._first_404 = False
                
                desc = 'The URL: "%s" has a %s code disclosure'\
                       ' vulnerability in the customized 404 script.'
                desc = desc % (response.get_url(), lang)
                
                v = Vuln('Code disclosure vulnerability in 404 page', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(match.group())
                self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
Example #27
0
    def _analyze_401(self, response):
        """
        Analyze a 401 response and report it.
        :return: None
        """
        realm = self._get_realm(response)
        
        if realm is None:
            self._report_no_realm(response)
            return
        
        insecure = response.get_url().get_protocol() == 'http'
        vuln_severity = severity.HIGH if insecure else severity.LOW
        
        desc = 'The resource: "%s" requires HTTP authentication'
        if insecure:
            desc += ' over a non-encrypted channel, which allows'\
                    ' potential intruders to sniff traffic and capture'\
                    ' valid credentials.'
        else:
            desc += '.'
        
        desc += ' The received authentication realm is: "%s".'
        desc = desc % (response.get_url(), realm)
        
        # Report the common case, were a realm is set.
        if 'ntlm' in realm.lower():
            
            v = Vuln('NTLM authentication', desc,
                     vuln_severity, response.id, self.get_name())

        else:
            v = Vuln('HTTP Basic authentication', desc,
                     vuln_severity, response.id, self.get_name())

        v.set_url(response.get_url())
        v['message'] = realm
        v.add_to_highlight(realm)

        kb.kb.append(self, 'auth', v)
        om.out.information(v.get_desc())
Example #28
0
    def _analyze_401(self, response):
        """
        Analyze a 401 response and report it.
        :return: None
        """
        realm = self._get_realm(response)

        if realm is None:
            self._report_no_realm(response)
            return

        insecure = response.get_url().get_protocol() == 'http'
        vuln_severity = severity.HIGH if insecure else severity.LOW

        desc = 'The resource: "%s" requires HTTP authentication'
        if insecure:
            desc += ' over a non-encrypted channel, which allows' \
                    ' potential intruders to sniff traffic and capture' \
                    ' valid credentials.'
        else:
            desc += '.'

        desc += ' The received authentication realm is: "%s".'
        desc = desc % (response.get_url(), realm)

        # Report the common case, were a realm is set.
        if 'ntlm' in realm.lower():

            v = Vuln('NTLM authentication', desc, vuln_severity, response.id,
                     self.get_name())

        else:
            v = Vuln('HTTP Basic authentication', desc, vuln_severity,
                     response.id, self.get_name())

        v.set_url(response.get_url())
        v['message'] = realm
        v.add_to_highlight(realm)

        kb.kb.append(self, 'auth', v)
        om.out.information(v.get_desc())
Example #29
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.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")
Example #30
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the DOM XSS vulns.
        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        for vuln_code in self._smart_grep(response):
            desc = 'The URL: "%s" has a DOM XSS (insecure javascript code)'\
                   ' bug using: "%s".'
            desc = desc % (response.get_url(), vuln_code)
            
            v = Vuln('DOM Cross site scripting', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())
            v.add_to_highlight(vuln_code)
            
            self.kb_append_uniq(self, 'dom_xss', v, filter_by='URL')
Example #31
0
    def grep(self, request, response):
        """
        Plugin entry point, search for the DOM XSS vulns.
        :param request: The HTTP request object.
        :param response: The HTTP response object
        :return: None
        """
        if not response.is_text_or_html():
            return

        for vuln_code in self._smart_grep(response):
            desc = 'The URL: "%s" has a DOM XSS (insecure javascript code)' \
                   ' bug using: "%s".'
            desc = desc % (response.get_url(), vuln_code)

            v = Vuln('DOM Cross site scripting', desc, severity.LOW,
                     response.id, self.get_name())
            v.set_url(response.get_url())
            v.add_to_highlight(vuln_code)

            self.kb_append_uniq(self, 'dom_xss', v, filter_by='URL')
Example #32
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.RE_LIST:
            for ip_address in regex.findall(headers_string):
                ip_address = ip_address.strip()

                # If i'm requesting 192.168.2.111 then I don't want to be
                # alerted about it
                if ip_address in self._ignore_if_match:
                    continue

                # I want to know the header name, this shouldn't consume much
                # CPU since we're only doing it when the headers already match
                # the initial regex run
                header_name = self._get_header_name(response, ip_address,
                                                    regex)

                desc = 'The URL "%s" returned the private IP address: "%s"'\
                       ' in the HTTP response header "%s"'
                desc = desc % (response.get_url(), ip_address, header_name)

                v = Vuln('Private IP disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(ip_address)
                v['ip_address'] = ip_address
                v['header_name'] = header_name
                v[HeaderPrivateIPInfoSet.ITAG] = (ip_address, header_name)

                self.kb_append_uniq_group(self,
                                          'header',
                                          v,
                                          group_klass=HeaderPrivateIPInfoSet)
Example #33
0
    def _check_server_header(self, fuzzable_request):
        """
        HTTP GET and analyze response for server header
        """
        response = self._uri_opener.GET(fuzzable_request.get_url(), cache=True)

        for hname, hvalue in response.get_lower_case_headers().iteritems():
            if hname == 'server':
                server = hvalue
                
                desc = 'The server header for the remote web server is: "%s".'
                desc = desc % server
                
                v = Vuln('Server header', desc, severity.INFORMATION, response.id, self.get_name())
                v['server'] = server
                v.add_to_highlight(hname + ':')
                
                # Save the results in the KB so the user can look at it
                kb.kb.append(self, 'server', v)

                # Also save this for easy internal use
                # other plugins can use this information
                kb.kb.raw_write(self, 'server_string', server)
                break

        else:
            # strange !
            desc = 'The remote HTTP Server omitted the "server" header in'\
                  ' its response.'
            v = Vuln('Omitted server header', desc, severity.INFORMATION, response.id,
                     self.get_name())

            # Save the results in the KB so that other plugins can use this
            # information
            kb.kb.append(self, 'ommited_server_header', v)

            # Also save this for easy internal use
            # other plugins can use this information
            kb.kb.raw_write(self, 'server_string', '')
Example #34
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        match_list = []
        body_text = response.get_body()
        real_url = response.get_url().url_decode()

        for match, _, _ in self._signature_re.query(body_text):
            match_list.append(match.group(1))

        # Sort by the longest match, this is needed for filtering out
        # some false positives please read the note below.
        match_list.sort(longest_cmp)

        for match in match_list:
            # Avoid duplicated reports
            if (real_url, match) in self._reported:
                continue

            # Remove false positives
            if self._is_false_positive(match, request, response):
                continue

            # Found!
            self._reported.append((real_url, match))

            desc = ('The URL: "%s" has a path disclosure vulnerability which'
                    ' discloses "%s".')
            desc %= (response.get_url(), match)

            v = Vuln('Path disclosure vulnerability', desc, severity.LOW,
                     response.id, self.get_name())
            v.add_to_highlight(match)
            v.set_url(real_url)
            v['path'] = match

            self.kb_append(self, 'path_disclosure', v)
            return v
Example #35
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        body_text = response.get_body()
        match_list = []

        for match, _, _ in self._signature_re.query(body_text):
            match_list.append(match.group(1))

        # Sort by the longest match, this is needed for filtering out
        # some false positives please read the note below.
        match_list.sort(longest_cmp)
        real_url = response.get_url().url_decode()

        for match in match_list:
            # Avoid duplicated reports
            if (real_url, match) in self._reported:
                continue

            # Remove false positives
            if self._is_false_positive(match, request, response):
                continue

            # Found!
            self._reported.append((real_url, match))

            desc = ('The URL: "%s" has a path disclosure vulnerability which'
                    ' discloses "%s".')
            desc %= (response.get_url(), match)

            v = Vuln('Path disclosure vulnerability', desc, severity.LOW,
                     response.id, self.get_name())
            v.add_to_highlight(match)
            v.set_url(real_url)
            v['path'] = match

            self.kb_append(self, 'path_disclosure', v)
            return v
Example #36
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        html_string = response.get_body()

        for potential_disclosure in self._potential_disclosures(html_string):

            path_disc_regex = self._compiled_regexes[potential_disclosure]
            match_list = path_disc_regex.findall(html_string)

            # Sort by the longest match, this is needed for filtering out
            # some false positives please read the note below.
            match_list.sort(longest_cmp)
            real_url = response.get_url().url_decode()

            for match in match_list:
                # Avoid duplicated reports
                if (real_url, match) in self._reported:
                    continue

                # Remove false positives
                if not self._is_false_positive(match, request, response):
                    self._reported.append((real_url, match))

                    desc = 'The URL: "%s" has a path disclosure'\
                           ' vulnerability which discloses "%s".'
                    desc = desc % (response.get_url(), match)

                    v = Vuln('Path disclosure vulnerability', desc,
                             severity.LOW, response.id, self.get_name())

                    v.set_url(real_url)
                    v['path'] = match
                    v.add_to_highlight(match)

                    self.kb_append(self, 'path_disclosure', v)
                    return v
Example #37
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        html_string = response.get_body()

        for potential_disclosure in self._potential_disclosures(html_string):

            path_disc_regex = self._compiled_regexes[potential_disclosure]
            match_list = path_disc_regex.findall(html_string)

            # Sort by the longest match, this is needed for filtering out
            # some false positives please read the note below.
            match_list.sort(longest_cmp)
            real_url = response.get_url().url_decode()

            for match in match_list:
                # Avoid duplicated reports
                if (real_url, match) in self._reported:
                    continue

                # Remove false positives
                if not self._is_false_positive(match, request, response):
                    self._reported.append((real_url, match))

                    desc = 'The URL: "%s" has a path disclosure'\
                           ' vulnerability which discloses "%s".'
                    desc = desc % (response.get_url(), match)

                    v = Vuln('Path disclosure vulnerability', desc,
                             severity.LOW, response.id, self.get_name())

                    v.set_url(real_url)
                    v['path'] = match
                    v.add_to_highlight(match)

                    self.kb_append(self, 'path_disclosure', v)
                    return v
Example #38
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.RE_LIST:
            for ip_address in regex.findall(headers_string):
                ip_address = ip_address.strip()

                # If i'm requesting 192.168.2.111 then I don't want to be
                # alerted about it
                if ip_address in self._ignore_if_match:
                    continue

                # I want to know the header name, this shouldn't consume much
                # CPU since we're only doing it when the headers already match
                # the initial regex run
                header_name = self._get_header_name(response, ip_address, regex)

                desc = 'The URL "%s" returned the private IP address: "%s"'\
                       ' in the HTTP response header "%s"'
                desc = desc % (response.get_url(), ip_address, header_name)

                v = Vuln('Private IP disclosure vulnerability', desc,
                         severity.LOW, response.id, self.get_name())

                v.set_url(response.get_url())
                v.add_to_highlight(ip_address)
                v['ip_address'] = ip_address
                v['header_name'] = header_name
                v[HeaderPrivateIPInfoSet.ITAG] = (ip_address, header_name)

                self.kb_append_uniq_group(self, 'header', v,
                                          group_klass=HeaderPrivateIPInfoSet)
Example #39
0
    def _analyze_html(self, request, response):
        """
        Search for IP addresses in the HTML
        """
        if not response.is_text_or_html():
            return

        # Performance improvement!
        if not (('10.' in response) or ('172.' in response) or
                ('192.168.' in response) or ('169.254.' in response)):
            return

        for regex in self._regex_list:
            for match in regex.findall(response.get_body()):
                match = match.strip()

                # Some proxy servers will return errors that include headers in the body
                # along with the client IP which we want to ignore
                if re.search("^.*X-Forwarded-For: .*%s" % match,
                             response.get_body(), re.M):
                    continue

                # 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 and \
                not request.sent(match):
                    desc = 'The URL: "%s" returned an HTML document'\
                           ' 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, 'HTML', v)
Example #40
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.
        """
        try:
            dp = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException:
            return

        # Note:
        # - With parsed_references I'm 100% that it's really something in the
        #   HTML that the developer intended to add.
        #
        # - The re_references are the result of regular expressions, which in
        #   some cases are just false positives.
        #
        parsed_references, _ = dp.get_references()

        for ref in parsed_references:

            qs = ref.querystring

            for param_name in qs:
                # This for loop is to address the repeated parameter name issue
                for element_index in xrange(len(qs[param_name])):
                    if self._is_strange(request, param_name, qs[param_name][element_index])\
                    and (ref.uri2url(), param_name) not in self._already_reported:
                        # Don't repeat findings
                        self._already_reported.add((ref.uri2url(), param_name))

                        desc = 'The URI: "%s" has a parameter named: "%s"'\
                               ' with value: "%s", which is very uncommon.'\
                               ' and requires manual verification.'
                        desc = desc % (response.get_uri(), param_name,
                                       qs[param_name][element_index])

                        i = Info('Uncommon query string parameter', desc,
                                 response.id, self.get_name())
                        i.set_uri(ref)
                        i.set_var(param_name)
                        i['parameter_value'] = qs[param_name][element_index]
                        i.add_to_highlight(qs[param_name][element_index])

                        self.kb_append(self, 'strange_parameters', i)

                    # To find this kind of vulns
                    # http://thedailywtf.com/Articles/Oklahoma-
                    # Leaks-Tens-of-Thousands-of-Social-Security-Numbers,-Other-
                    # Sensitive-Data.aspx
                    if self._is_SQL(request, param_name, qs[param_name][element_index])\
                    and ref not in self._already_reported:

                        # Don't repeat findings
                        self._already_reported.add(ref)
                        desc = 'The URI: "%s" has a parameter named: "%s"'\
                               ' with value: "%s", which is a SQL query.'
                        desc = desc % (response.get_uri(), param_name,
                                       qs[param_name][element_index])
                        v = Vuln('Parameter has SQL sentence', desc,
                                 severity.LOW, response.id, self.get_name())
                        v.set_uri(ref)
                        v.set_var(param_name)
                        v['parameter_value'] = qs[param_name][element_index]
                        
                        v.add_to_highlight(qs[param_name][element_index])
                        self.kb_append(self, 'strange_parameters', v)
Example #41
0
            url_list.extend(parsed_references)
            url_list.extend(re_references)

        for url in url_list:

            if ('@' in url.url_string
                    and self._auth_uri_regex.match(url.url_string)):
                desc = 'The resource: "%s" has a user and password in the' \
                       ' body. The offending URL is: "%s".'
                desc = 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 _get_realm(self, response):
        for key in response.get_headers():
            if key.lower() == 'www-authenticate':
                realm = response.get_headers()[key]
                return realm

        return None

    def _report_no_realm(self, response):
        # Report this strange case
        desc = 'The resource: "%s" requires authentication (HTTP Code' \
Example #42
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        html_string = response.get_body()

        for potential_disclosure in self._potential_disclosures(html_string):

            path_disc_regex = self._compiled_regexes[potential_disclosure]
            match_list = path_disc_regex.findall(html_string)

            # Decode the URL, this will transform things like
            #     http://host.tld/?id=%2Fhome
            # into,
            #     http://host.tld/?id=/home
            realurl = response.get_url().url_decode()

            #   Sort by the longest match, this is needed for filtering out
            #   some false positives please read the note below.
            match_list.sort(self._longest)

            for match in match_list:

                # This if is to avoid false positives
                if not request.sent(match) and not \
                self._attr_value(match, html_string):

                    # Check for dups
                    if (realurl, match) in self._already_added:
                        continue

                    #   There is a rare bug also, which is triggered in cases like this one:
                    #
                    #   >>> import re
                    #   >>> re.findall('/var/www/.*','/var/www/foobar/htdocs/article.php')
                    #   ['/var/www/foobar/htdocs/article.php']
                    #   >>> re.findall('/htdocs/.*','/var/www/foobar/htdocs/article.php')
                    #   ['/htdocs/article.php']
                    #   >>>
                    #
                    #   What I need to do here, is to keep the longest match.
                    for realurl_added, match_added in self._already_added:
                        if match_added.endswith(match):
                            break
                    else:

                        #   Note to self: I get here when "break" is NOT executed.
                        #   It's a new one, report!
                        self._already_added.append((realurl, match))

                        desc = 'The URL: "%s" has a path disclosure'\
                               ' vulnerability which discloses "%s".'
                        desc = desc % (response.get_url(), match)

                        v = Vuln('Path disclosure vulnerability', desc,
                                 severity.LOW, response.id, self.get_name())

                        v.set_url(realurl)
                        v['path'] = match
                        v.add_to_highlight(match)
                        
                        self.kb_append(self, 'path_disclosure', v)
                        return True
                    
        return False
Example #43
0
    def find_path_disclosure(self, request, response):
        """
        Actually find the path disclosure vulnerabilities
        """
        html_string = response.get_body()

        for potential_disclosure in self._potential_disclosures(html_string):

            path_disc_regex = self._compiled_regexes[potential_disclosure]
            match_list = path_disc_regex.findall(html_string)

            # Decode the URL, this will transform things like
            #     http://host.tld/?id=%2Fhome
            # into,
            #     http://host.tld/?id=/home
            realurl = response.get_url().url_decode()

            #   Sort by the longest match, this is needed for filtering out
            #   some false positives please read the note below.
            match_list.sort(self._longest)

            for match in match_list:

                # This if is to avoid false positives
                if not request.sent(match) and not \
                self._attr_value(match, html_string):

                    # Check for dups
                    if (realurl, match) in self._already_added:
                        continue

                    #   There is a rare bug also, which is triggered in cases like this one:
                    #
                    #   >>> import re
                    #   >>> re.findall('/var/www/.*','/var/www/foobar/htdocs/article.php')
                    #   ['/var/www/foobar/htdocs/article.php']
                    #   >>> re.findall('/htdocs/.*','/var/www/foobar/htdocs/article.php')
                    #   ['/htdocs/article.php']
                    #   >>>
                    #
                    #   What I need to do here, is to keep the longest match.
                    for realurl_added, match_added in self._already_added:
                        if match_added.endswith(match):
                            break
                    else:

                        #   Note to self: I get here when "break" is NOT executed.
                        #   It's a new one, report!
                        self._already_added.append((realurl, match))

                        desc = 'The URL: "%s" has a path disclosure'\
                               ' vulnerability which discloses "%s".'
                        desc = desc % (response.get_url(), match)

                        v = Vuln('Path disclosure vulnerability', desc,
                                 severity.LOW, response.id, self.get_name())

                        v.set_url(realurl)
                        v['path'] = match
                        v.add_to_highlight(match)

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

        return False
Example #44
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.
        """
        try:
            dp = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException:
            return

        # Note:
        # - With parsed_references I'm 100% that it's really something in the
        #   HTML that the developer intended to add.
        #
        # - The re_references are the result of regular expressions, which in
        #   some cases are just false positives.
        #
        parsed_references, _ = dp.get_references()

        for ref in parsed_references:

            qs = ref.querystring

            for param_name in qs:
                # This for loop is to address the repeated parameter name issue
                for element_index in xrange(len(qs[param_name])):
                    if self._is_strange(request, param_name, qs[param_name][element_index])\
                    and (ref.uri2url(), param_name) not in self._already_reported:
                        # Don't repeat findings
                        self._already_reported.add((ref.uri2url(), param_name))

                        desc = 'The URI: "%s" has a parameter named: "%s"'\
                               ' with value: "%s", which is very uncommon.'\
                               ' and requires manual verification.'
                        desc = desc % (response.get_uri(), param_name,
                                       qs[param_name][element_index])

                        i = Info('Uncommon query string parameter', desc,
                                 response.id, self.get_name())
                        i.set_uri(ref)
                        i.set_var(param_name)
                        i['parameter_value'] = qs[param_name][element_index]
                        i.add_to_highlight(qs[param_name][element_index])

                        self.kb_append(self, 'strange_parameters', i)

                    # To find this kind of vulns
                    # http://thedailywtf.com/Articles/Oklahoma-
                    # Leaks-Tens-of-Thousands-of-Social-Security-Numbers,-Other-
                    # Sensitive-Data.aspx
                    if self._is_SQL(request, param_name, qs[param_name][element_index])\
                    and ref not in self._already_reported:

                        # Don't repeat findings
                        self._already_reported.add(ref)
                        desc = 'The URI: "%s" has a parameter named: "%s"'\
                               ' with value: "%s", which is a SQL query.'
                        desc = desc % (response.get_uri(), param_name,
                                       qs[param_name][element_index])
                        v = Vuln('Parameter has SQL sentence', desc,
                                 severity.LOW, response.id, self.get_name())
                        v.set_uri(ref)
                        v.set_var(param_name)
                        v['parameter_value'] = qs[param_name][element_index]

                        v.add_to_highlight(qs[param_name][element_index])
                        self.kb_append(self, 'strange_parameters', v)
Example #45
0
            url_list.extend(re_references)

        for url in url_list:

            if ('@' in url.url_string and
                    self._auth_uri_regex.match(url.url_string)):

                desc = 'The resource: "%s" has a user and password in the'\
                       ' body. The offending URL is: "%s".'
                desc = 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 _get_realm(self, response):
        for key in response.get_headers():
            if key.lower() == 'www-authenticate':
                realm = response.get_headers()[key]
                return realm
        
        return None
        
    def _report_no_realm(self, response):
        # Report this strange case
        desc = 'The resource: "%s" requires authentication (HTTP Code'\