Example #1
0
    def audit(self, freq, orig_response):
        """
        Test URLs for CSRF vulnerabilities.

        :param freq: A FuzzableRequest
        """
        if not self._is_suitable(freq):
            return

        # Referer/Origin check
        #
        # IMPORTANT NOTE: I'm aware that checking for the referer header does
        # NOT protect the application against all cases of CSRF, but it's a
        # very good first step. In order to exploit a CSRF in an application
        # that protects using this method an intruder would have to identify
        # other vulnerabilities such as XSS or open redirects.
        #
        # TODO: This algorithm has lots of room for improvement
        if self._is_origin_checked(freq, orig_response):
            om.out.debug('Origin for %s is checked' % freq.get_url())
            return

        # Does the request have CSRF token in query string or POST payload?
        if self._find_csrf_token(freq):
            return

        # Ok, we have found vulnerable to CSRF attack request
        msg = 'Cross Site Request Forgery has been found at: ' + freq.get_url()
        
        v = Vuln.from_fr('CSRF vulnerability', msg, severity.MEDIUM,
                         orig_response.id, self.get_name(), freq)
        
        self.kb_append_uniq(self, 'csrf', v)
Example #2
0
    def _analyze_ips(self, ip_address_list, fuzzable_request):
        """
        Search all IP addresses in Bing and determine if they have more than
        one domain hosted on it. Store findings in KB.
        """
        bing_wrapper = bing(self._uri_opener)

        # This is the best way to search, one by one!
        for ip_address in ip_address_list:
            results = bing_wrapper.get_n_results("ip:" + ip_address, self._result_limit)

            results = [r.URL.base_url() for r in results]
            results = list(set(results))

            # not vuln by default
            is_vulnerable = False

            if len(results) > 1:
                # We may have something...
                is_vulnerable = True

                if len(results) == 2:
                    # Maybe we have this case:
                    # [Mon 09 Jun 2008 01:08:26 PM ART] - http://216.244.147.14/
                    # [Mon 09 Jun 2008 01:08:26 PM ART] - http://www.business.com/
                    # Where www.business.com resolves to 216.244.147.14; so we don't really
                    # have more than one domain in the same server.
                    try:
                        res0 = socket.gethostbyname(results[0].get_domain())
                        res1 = socket.gethostbyname(results[1].get_domain())
                    except:
                        pass
                    else:
                        if res0 == res1:
                            is_vulnerable = False

            if is_vulnerable:
                desc = (
                    "The web application under test seems to be in a shared"
                    " hosting. This list of domains, and the domain of the "
                    " web application under test, all point to the same IP"
                    " address (%s):\n" % ip_address
                )

                domain_list = kb.kb.raw_read(self, "domains")

                for url in results:
                    domain = url.get_domain()
                    desc += "- %s\n" % domain

                    domain_list.append(domain)

                kb.kb.raw_write(self, "domains", domain_list)

                v = Vuln.from_fr("Shared hosting", desc, severity.MEDIUM, 1, self.get_name(), fuzzable_request)

                v["also_in_hosting"] = results

                om.out.vulnerability(desc, severity=severity.MEDIUM)
                kb.kb.append(self, "shared_hosting", v)
Example #3
0
File: rfd.py Project: ZionOps/w3af
 def _report_vuln(self, debug_msg, freq, rid):
     debug_msg = debug_msg % (freq.get_uri(), rid)
     om.out.debug(debug_msg)
     desc = u"Reflected File Download has been " u"found at: %s"
     desc = desc % freq.get_url()
     v = Vuln.from_fr(u"Reflected File Download vulnerability", desc, severity.HIGH, rid, self.get_name(), freq)
     self.kb_append_uniq(self, "rfd", v)
Example #4
0
    def check_is_open_web_socket(self, web_socket_url, web_socket_version):
        """
        Note that this method only makes sense if called in a loop with the
        other check_* methods.

        :param web_socket_url: The URL of the web socket
        :param web_socket_version: The protocol version

        :return: True if the web socket is open:
                    * Any Origin can connect
                    * No cookies required for authentication
                    * No basic auth required for authentication
        """
        upgrade_request = build_ws_upgrade_request(web_socket_url,
                                                   web_socket_version=web_socket_version,
                                                   origin=self.W3AF_ORIGIN)
        upgrade_response = self._uri_opener.send_mutant(upgrade_request,
                                                        cookies=False,
                                                        use_basic_auth=False)

        if not is_successful_upgrade(upgrade_response):
            return False

        msg = ('An HTML5 WebSocket which allows connections from any origin'
               ' without authentication was found at "%s"')
        msg %= web_socket_url

        v = Vuln.from_fr('Open WebSocket', msg, severity.LOW,
                         upgrade_response.id, self.get_name(), upgrade_request)
        self.kb_append_uniq(self, 'websocket_hijacking', v)
        return True
Example #5
0
    def _analyze_ips(self, ip_address_list, fuzzable_request):
        """
        Search all IP addresses in Bing and determine if they have more than
        one domain hosted on it. Store findings in KB.
        """
        bing_wrapper = bing(self._uri_opener)

        # This is the best way to search, one by one!
        for ip_address in ip_address_list:
            results = bing_wrapper.get_n_results('ip:' + ip_address,
                                                 self._result_limit)

            results = [r.URL.base_url() for r in results]
            results = list(set(results))

            # not vuln by default
            is_vulnerable = False

            if len(results) > 1:
                # We may have something...
                is_vulnerable = True

                if len(results) == 2:
                    # Maybe we have this case:
                    # [Mon 09 Jun 2008 01:08:26 PM ART] - http://216.244.147.14/
                    # [Mon 09 Jun 2008 01:08:26 PM ART] - http://www.business.com/
                    # Where www.business.com resolves to 216.244.147.14; so we don't really
                    # have more than one domain in the same server.
                    try:
                        res0 = socket.gethostbyname(results[0].get_domain())
                        res1 = socket.gethostbyname(results[1].get_domain())
                    except:
                        pass
                    else:
                        if res0 == res1:
                            is_vulnerable = False

            if is_vulnerable:
                desc = 'The web application under test seems to be in a shared' \
                       ' hosting. This list of domains, and the domain of the ' \
                       ' web application under test, all point to the same IP' \
                       ' address (%s):\n' % ip_address

                domain_list = kb.kb.raw_read(self, 'domains')

                for url in results:
                    domain = url.get_domain()
                    desc += '- %s\n' % domain

                    domain_list.append(domain)

                kb.kb.raw_write(self, 'domains', domain_list)

                v = Vuln.from_fr('Shared hosting', desc, severity.MEDIUM, 1,
                                 self.get_name(), fuzzable_request)

                v['also_in_hosting'] = results

                om.out.vulnerability(desc, severity=severity.MEDIUM)
                kb.kb.append(self, 'shared_hosting', v)
Example #6
0
    def _report_results(self, fuzzable_request, analysis_result):
        """
        Report our findings
        """
        reported = set()
        for vhost, request_id in analysis_result:
            if vhost in reported:
                continue

            reported.add(vhost)

            domain = fuzzable_request.get_url().get_domain()
            desc = (
                u"Found a new virtual host at the target web server, the"
                u' virtual host name is: "%s". To access this site'
                u" you might need to change your DNS resolution settings"
                u' in order to point "%s" to the IP address of "%s".'
            )
            desc %= (vhost, vhost, domain)

            v = Vuln.from_fr(
                "Virtual host identified", desc, severity.LOW, request_id, self.get_name(), fuzzable_request
            )

            kb.kb.append(self, "find_vhosts", v)
            om.out.information(v.get_desc())
Example #7
0
    def _html_in_comment(self, comment, request, response):
        """
        Find HTML code in HTML comments
        """
        html_in_comment = self.HTML_RE.search(comment)

        if html_in_comment is None:
            return

        if (comment, response.get_url()) in self._already_reported:
            return

        # There is HTML code in the comment.
        comment = comment.strip()
        comment = comment.replace('\n', '')
        comment = comment.replace('\r', '')
        comment = comment[:40]

        desc = ('A comment with the string "%s" was found in: "%s".'
                ' This could be interesting.')
        desc %= (comment, response.get_url())

        v = Vuln.from_fr('HTML comment contains HTML code',
                         desc, severity.INFORMATION, response.id,
                         self.get_name(), request)
        v.set_uri(response.get_uri())
        v.add_to_highlight(html_in_comment.group(0))

        om.out.vulnerability(v.get_desc(), severity=severity.INFORMATION)
        kb.kb.append(self, 'html_comment_hides_html', v)
        self._already_reported.add((comment, response.get_url()))
Example #8
0
    def _check_potential_vhosts(self, fuzzable_request, vhosts):
        """
        Send the HTTP requests to check for potential findings

        :param fuzzable_request: The fuzzable request as received by the plugin
        :param vhosts: A generator yielding potential vhosts to check
        :return: None, vulnerabilities (if any) are written to the KB
        """
        # Get some responses to compare later
        base_url = fuzzable_request.get_url().base_url()
        original_response = self._uri_opener.GET(base_url, cache=True)
        orig_resp_body = original_response.get_body()

        non_existent_responses = self._get_non_exist(fuzzable_request)

        for vhost, vhost_response in self._send_in_threads(base_url, vhosts):

            if not self._response_is_different(vhost_response, orig_resp_body, non_existent_responses):
                continue

            domain = fuzzable_request.get_url().get_domain()
            desc = (u'Found a new virtual host at the target web server, the'
                    u' virtual host name is: "%s". To access this site'
                    u' you might need to change your DNS resolution settings'
                    u' in order to point "%s" to the IP address of "%s".')
            desc %= (vhost, vhost, domain)

            ids = [vhost_response.id, original_response.id]
            ids.extend([r.id for r in non_existent_responses])

            v = Vuln.from_fr('Virtual host identified', desc, severity.LOW,
                             ids, self.get_name(), fuzzable_request)

            kb.kb.append(self, 'find_vhosts', v)
            om.out.information(v.get_desc())
Example #9
0
 def _report_vuln(self, debug_msg, freq, rid):
     debug_msg = debug_msg % (freq.get_uri(), rid)
     om.out.debug(debug_msg)
     desc = u'Reflected File Download has been ' \
            u'found at: %s'
     desc = desc % freq.get_url()
     v = Vuln.from_fr(u'Reflected File Download vulnerability', desc,
                      severity.HIGH, rid, self.get_name(), freq)
     self.kb_append_uniq(self, 'rfd', v)
    def audit(self, freq, orig_response):
	url = URL(freq.get_url() + self._PAYLOAD)
	print 'the url is %s', url
	freq_new = FuzzableRequest(url, method='GET')
        response = self._uri_opener.send_mutant(freq_new)
	print response.get_body()
	if 'root:/root' in response.get_body():	
      		msg = 'Directory Traversal Vulnerbility found at ' + freq.get_url()
        	v = Vuln.from_fr('Directory Traversal vulnerability', msg, severity.MEDIUM,
                         orig_response.id, self.get_name(), freq)
        
		print 'hello there'
        	self.kb_append_uniq(self, 'directory_traversal', v)
Example #11
0
    def check_is_restricted_by_origin_with_match_bug(self, web_socket_url,
                                                     web_socket_version):
        """
        Note that this method only makes sense if called in a loop with the
        other check_* methods.

        :param web_socket_url: The URL of the web socket
        :param web_socket_version: The protocol version

        :return: True if the web socket checks the origin for connections but
                 there is a bug in the matching process
        """
        #
        # Keep in mind that we get here only if the websocket is NOT an open
        # (accepts any origin) socket. So we're in a situation where the socket
        # is either verifying by Origin+Cookies, Origin+Basic Auth or just
        # Origin.
        #
        # We want to check for the "just Origin" now, with a twist, we're
        # checking if there is a mistake in the Origin domain match process
        #
        # This is the trick:
        origin_domain = web_socket_url.get_domain()
        origin_domain += '.%s' % self.W3AF_DOMAIN

        for scheme in {'http', 'https'}:
            origin = '%s://%s' % (scheme, origin_domain)
            upgrade_request = build_ws_upgrade_request(web_socket_url,
                                                       web_socket_version=web_socket_version,
                                                       origin=origin)
            upgrade_response = self._uri_opener.send_mutant(upgrade_request,
                                                            cookies=False,
                                                            use_basic_auth=False)

            if not is_successful_upgrade(upgrade_response):
                continue

            msg = ('An HTML5 WebSocket which restricts connections based on the'
                   ' Origin header was found to be vulnerable because of an'
                   ' incorrect matching algorithm. The "%s" Origin was allowed'
                   ' to connect to "%s".')
            msg %= (origin_domain, web_socket_url)

            v = Vuln.from_fr('Insecure WebSocket Origin filter', msg,
                             severity.MEDIUM, upgrade_response.id,
                             self.get_name(), upgrade_request)
            self.kb_append_uniq(self, 'websocket_hijacking', v)
            return True

        return False
    def audit(self, freq, orig_response):
        url = URL(freq.get_url() + self._PAYLOAD)
        print 'the url is %s', url
        freq_new = FuzzableRequest(url, method='GET')
        response = self._uri_opener.send_mutant(freq_new)
        print response.get_body()
        if 'root:/root' in response.get_body():
            msg = 'Directory Traversal Vulnerbility found at ' + freq.get_url()
            v = Vuln.from_fr('Directory Traversal vulnerability',
                             msg, severity.MEDIUM, orig_response.id,
                             self.get_name(), freq)

            print 'hello there'
            self.kb_append_uniq(self, 'directory_traversal', v)
Example #13
0
    def _extract_urls(self, fuzzable_request, response):
        """
        Extract information from the server-status page and return fuzzable
        requests to the caller.
        """
        res = self._create_fuzzable_requests(response)

        # Now really parse the file and create custom made fuzzable requests
        regex = '<td>.*?<td nowrap>(.*?)</td><td nowrap>.*? (.*?) HTTP/1'
        for domain, path in re.findall(regex, response.get_body()):

            if 'unavailable' in domain:
                domain = response.get_url().get_domain()

            # Check if the requested domain and the found one are equal.
            if domain == response.get_url().get_domain():
                proto = response.get_url().get_protocol()
                found_url = proto + '://' + domain + path
                found_url = URL(found_url)

                # They are equal, request the URL and create the fuzzable
                # requests
                tmp_res = self._uri_opener.GET(found_url, cache=True)
                if not is_404(tmp_res):
                    res.extend(self._create_fuzzable_requests(tmp_res))
            else:
                # This is a shared hosting server
                self._shared_hosting_hosts.append(domain)

        # Now that we are outsite the for loop, we can report the possible vulns
        if len(self._shared_hosting_hosts):
            desc = 'The web application under test seems to be in a shared'\
                   ' hosting.'
            v = Vuln.from_fr('Shared hosting', desc, severity.MEDIUM,
                             response.id, self.get_name(), fuzzable_request)

            self._shared_hosting_hosts = list(set(self._shared_hosting_hosts))
            v['also_in_hosting'] = self._shared_hosting_hosts

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

            msg = 'This list of domains, and the domain of the web application'\
                  ' under test, all point to the same server:'
            om.out.vulnerability(msg, severity=severity.MEDIUM)
            for url in self._shared_hosting_hosts:
                om.out.vulnerability('- ' + url, severity=severity.MEDIUM)

        return res
    def _extract_urls(self, fuzzable_request, response):
        """
        Extract information from the server-status page and return fuzzable
        requests to the caller.
        """
        res = self._create_fuzzable_requests(response)

        # Now really parse the file and create custom made fuzzable requests
        regex = "<td>.*?<td nowrap>(.*?)</td><td nowrap>.*? (.*?) HTTP/1"
        for domain, path in re.findall(regex, response.get_body()):

            if "unavailable" in domain:
                domain = response.get_url().get_domain()

            # Check if the requested domain and the found one are equal.
            if domain == response.get_url().get_domain():
                proto = response.get_url().get_protocol()
                found_url = proto + "://" + domain + path
                found_url = URL(found_url)

                # They are equal, request the URL and create the fuzzable
                # requests
                tmp_res = self._uri_opener.GET(found_url, cache=True)
                if not is_404(tmp_res):
                    res.extend(self._create_fuzzable_requests(tmp_res))
            else:
                # This is a shared hosting server
                self._shared_hosting_hosts.append(domain)

        # Now that we are outsite the for loop, we can report the possible vulns
        if len(self._shared_hosting_hosts):
            desc = "The web application under test seems to be in a shared" " hosting."
            v = Vuln.from_fr("Shared hosting", desc, severity.MEDIUM, response.id, self.get_name(), fuzzable_request)

            self._shared_hosting_hosts = list(set(self._shared_hosting_hosts))
            v["also_in_hosting"] = self._shared_hosting_hosts

            kb.kb.append(self, "shared_hosting", v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            msg = (
                "This list of domains, and the domain of the web application"
                " under test, all point to the same server:"
            )
            om.out.vulnerability(msg, severity=severity.MEDIUM)
            for url in self._shared_hosting_hosts:
                om.out.vulnerability("- " + url, severity=severity.MEDIUM)

        return res
Example #15
0
    def check_is_restricted_by_origin(self, web_socket_url, web_socket_version):
        """
        Note that this method only makes sense if called in a loop with the
        other check_* methods.

        :param web_socket_url: The URL of the web socket
        :param web_socket_version: The protocol version

        :return: True if the web socket checks the origin for connections:
                    * Only the same origin can connect
                    * Send any cookie/basic auth known to the scanner
        """
        #
        # Keep in mind that we get here only if the websocket is NOT an open
        # (accepts any origin) socket. So we're in a situation where the socket
        # is either verifying by Origin+Cookies, Origin+Basic Auth or just
        # Origin.
        #
        # We want to check for the "just Origin" now
        #
        origin_domain = web_socket_url.get_domain()

        for scheme in {'http', 'https'}:
            origin = '%s://%s' % (scheme, origin_domain)
            upgrade_request = build_ws_upgrade_request(web_socket_url,
                                                       web_socket_version=web_socket_version,
                                                       origin=origin)
            upgrade_response = self._uri_opener.send_mutant(upgrade_request,
                                                            cookies=False,
                                                            use_basic_auth=False)

            if not is_successful_upgrade(upgrade_response):
                continue

            msg = ('An HTML5 WebSocket which allows connections only when the'
                   ' origin is set to "%s" was found at "%s"')
            msg %= (origin_domain, web_socket_url)

            v = Vuln.from_fr('Origin restricted WebSocket', msg, severity.LOW,
                             upgrade_response.id, self.get_name(),
                             upgrade_request)
            self.kb_append_uniq(self, 'websocket_hijacking', v)
            return True

        return False
Example #16
0
    def _report_shared_hosting(self, fuzzable_request, response):
        # Now that we are outsite the for loop, we can report the possible vulns
        if len(self._shared_hosting_hosts):
            desc = 'The web application under test seems to be in a shared'\
                   ' hosting.'
            v = Vuln.from_fr('Shared hosting', desc, severity.MEDIUM,
                             response.id, self.get_name(), fuzzable_request)

            self._shared_hosting_hosts = list(set(self._shared_hosting_hosts))
            v['also_in_hosting'] = self._shared_hosting_hosts

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

            msg = 'This list of domains, and the domain of the web application'\
                  ' under test, all point to the same server:'
            om.out.vulnerability(msg, severity=v.get_severity())
            for url in self._shared_hosting_hosts:
                om.out.vulnerability('- ' + url, severity=severity.MEDIUM)
Example #17
0
    def _report_shared_hosting(self, fuzzable_request, response):
        # Now that we are outsite the for loop, we can report the possible vulns
        if len(self._shared_hosting_hosts):
            desc = "The web application under test seems to be in a shared" " hosting."
            v = Vuln.from_fr("Shared hosting", desc, severity.MEDIUM, response.id, self.get_name(), fuzzable_request)

            self._shared_hosting_hosts = list(set(self._shared_hosting_hosts))
            v["also_in_hosting"] = self._shared_hosting_hosts

            kb.kb.append(self, "shared_hosting", v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            msg = (
                "This list of domains, and the domain of the web application"
                " under test, all point to the same server:"
            )
            om.out.vulnerability(msg, severity=v.get_severity())
            for url in self._shared_hosting_hosts:
                om.out.vulnerability("- " + url, severity=severity.MEDIUM)
Example #18
0
    def check_need_cookie_origin_not_restricted(self, web_socket_url,
                                                web_socket_version):
        """
        Note that this method only makes sense if called in a loop with the
        other check_* methods.

        :param web_socket_url: The URL of the web socket
        :param web_socket_version: The protocol version

        :return: True if the web socket does NOT check the origin for
                 connections but DOES require cookies to connect
        """
        #
        # Keep in mind that we get here only if:
        #   * The websocket is NOT an open (accepts any origin) socket
        #   * The websocket is NOT verifying by Origin
        #
        # So we're in one of these cases:
        #   * The websocket authenticates by cookie
        #   * The websocket authenticates by basic auth
        #
        # We want to check for the "authenticates by cookie"
        #
        upgrade_request = build_ws_upgrade_request(web_socket_url,
                                                   web_socket_version=web_socket_version,
                                                   origin=self.W3AF_ORIGIN)
        upgrade_response = self._uri_opener.send_mutant(upgrade_request,
                                                        # Note the True here!
                                                        cookies=True,
                                                        use_basic_auth=False)

        if not is_successful_upgrade(upgrade_response):
            return False

        msg = 'Cross-Site WebSocket Hijacking has been found at "%s"'
        msg %= web_socket_url

        v = Vuln.from_fr('Websockets CSRF vulnerability', msg,
                         severity.HIGH, upgrade_response.id,
                         self.get_name(), upgrade_request)
        self.kb_append_uniq(self, 'websocket_hijacking', v)
        return True
Example #19
0
    def audit(self, freq, orig_response, debugging_id):
        """
        Verify xst vulns by sending a TRACE request and analyzing the response.

        :param freq: A FuzzableRequest
        :param orig_response: The HTTP response associated with the fuzzable request
        :param debugging_id: A unique identifier for this call to audit()
        """
        if not self._exec:
            return

        # Only run once
        self._exec = False

        uri = freq.get_url().get_domain_path()
        method = 'TRACE'
        headers = Headers()
        headers['FakeHeader'] = 'XST'
        fr = FuzzableRequest(uri,
                             method=method,
                             headers=headers
                             )

        # send the request to the server and receive the response
        response = self._uri_opener.send_mutant(fr)

        # create a regex to test the response.
        regex = re.compile("FakeHeader: *?XST", re.IGNORECASE)
        if regex.search(response.get_body()):
            # If vulnerable record it. This will now become visible on
            # the KB Browser
            desc = 'The web server at "%s" is vulnerable to Cross Site'\
                  ' Tracing.'
            desc = desc % response.get_url()

            v = Vuln.from_fr('Cross site tracing vulnerability', desc,
                             severity.LOW, response.id, self.get_name(),
                             freq)

            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            self.kb_append(self, 'xst', v)
Example #20
0
    def _report_results(self, fuzzable_request, analysis_result):
        """
        Report our findings
        """
        reported = set()
        for vhost, request_id in analysis_result:
            if vhost not in reported:
                reported.add(vhost)

                domain = fuzzable_request.get_url().get_domain()
                desc = 'Found a new virtual host at the target web server, the ' \
                       'virtual host name is: "%s". To access this site' \
                       ' you might need to change your DNS resolution settings in' \
                       ' order to point "%s" to the IP address of "%s".'
                desc = desc % (vhost, vhost, domain)

                v = Vuln.from_fr('Virtual host identified', desc, severity.LOW,
                                 request_id, self.get_name(), fuzzable_request)

                kb.kb.append(self, 'find_vhosts', v)
                om.out.information(v.get_desc())
Example #21
0
    def _interesting_word(self, comment, request, response):
        """
        Find interesting words in HTML comments
        """
        comment = comment.lower()

        for word in self._multi_in.query(comment):
            if (word, response.get_url()) in self._already_reported:
                continue

            desc = ('A comment with the string "%s" was found in: "%s".'
                    ' This could be interesting.')
            desc %= (word, response.get_url())

            v = Vuln.from_fr('Interesting HTML comment',
                             desc, severity.INFORMATION, response.id,
                             self.get_name(), request)
            v.add_to_highlight(word)

            kb.kb.append(self, 'interesting_comments', v)

            self._already_reported.add((word, response.get_url()))
Example #22
0
    def audit(self, freq, orig_response, debugging_id):
        """
        Verify xst vulns by sending a TRACE request and analyzing the response.

        :param freq: A FuzzableRequest
        :param orig_response: The HTTP response associated with the fuzzable request
        :param debugging_id: A unique identifier for this call to audit()
        """
        if not self._exec:
            return

        # Only run once
        self._exec = False

        uri = freq.get_url().get_domain_path()
        method = 'TRACE'
        headers = Headers()
        headers['FakeHeader'] = 'XST'
        fr = FuzzableRequest(uri, method=method, headers=headers)

        # send the request to the server and receive the response
        response = self._uri_opener.send_mutant(fr)

        # create a regex to test the response.
        regex = re.compile("FakeHeader: *?XST", re.IGNORECASE)
        if regex.search(response.get_body()):
            # If vulnerable record it. This will now become visible on
            # the KB Browser
            desc = 'The web server at "%s" is vulnerable to Cross Site'\
                  ' Tracing.'
            desc = desc % response.get_url()

            v = Vuln.from_fr('Cross site tracing vulnerability', desc,
                             severity.LOW, response.id, self.get_name(), freq)

            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            self.kb_append(self, 'xst', v)
Example #23
0
    def audit(self, freq, orig_response, debugging_id):
        """
        Check if the protocol specified in freq is https and fetch the same URL
        using http. ie:
            - input: https://w3af.org/
            - check: http://w3af.org/

        :param freq: A FuzzableRequest
        :param orig_response: The HTTP response associated with the fuzzable request
        :param debugging_id: A unique identifier for this call to audit()
        """
        if not self._should_run:
            return

        initial_uri = freq.get_uri()
        if initial_uri.get_port() not in {80, 443}:
            # We get here then the original URL looks like http://foo:3921/
            #
            # It's really strange (maybe not even possible?) to find a server
            # that listens for HTTP and HTTPS connections on the same port,
            # since we don't want to guess the port, nor generate errors such
            # as #8871 we just ignore this case
            self._should_run = False
            return

        # Define some variables
        insecure_uri = initial_uri.copy()
        secure_uri = initial_uri.copy()

        insecure_uri.set_protocol('http')
        insecure_fr = copy.deepcopy(freq)
        insecure_fr.set_url(insecure_uri)

        secure_uri.set_protocol('https')
        secure_fr = copy.deepcopy(freq)
        secure_fr.set_url(secure_uri)

        # Make sure that we disable error handling during these tests, we want
        # the requests to fail quickly and without affecting the library's error
        # rate
        send_mutant = self._uri_opener.send_mutant
        kwargs = {'grep': False, 'error_handling': False}

        try:
            insecure_response = send_mutant(insecure_fr, **kwargs)
            secure_response = send_mutant(secure_fr, **kwargs)
        except (HTTPRequestException, ScanMustStopException):
            # No vulnerability to report since one of these threw an error
            # (because there is nothing listening on that port). It makes
            # no sense to keep running since we already got an error
            self._should_run = False

        else:
            if insecure_response is None or secure_response is None:
                # No vulnerability to report since one of these threw an
                # error (because there is nothing listening on that port).
                # It makes no sense to keep running since we already got an
                # error
                self._should_run = False
                return

            if self._redirects_to_secure(insecure_response, secure_response):
                return

            if insecure_response.get_code() == secure_response.get_code()\
            and fuzzy_equal(insecure_response.get_body(),
                            secure_response.get_body(),
                            0.95):

                desc = ('Secure content can be accessed using the insecure'
                        ' HTTP protocol. The vulnerable URLs used to verify'
                        ' this vulnerability are:\n'
                        ' - %s\n'
                        ' - %s\n')
                desc %= (secure_uri, insecure_uri)

                response_ids = [insecure_response.id, secure_response.id]

                v = Vuln.from_fr('Secure content over insecure channel',
                                 desc, severity.MEDIUM, response_ids,
                                 self.get_name(), freq)

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

                # In most cases, when one resource is available, all are
                # so we just stop searching for this vulnerability
                self._should_run = False
Example #24
0
    def _brute_worker(self, freq, user_field, passwd_field,
                      login_failed_result_list, combination):
        """
        :param freq: A FuzzableRequest
        :param combination: A tuple with (user, pass) or a pass if this is a
                                password only form.
        """
        if freq.get_url() not in self._found or not self._stop_on_first:
            freq = freq.copy()
            data_container = freq.get_dc()
            data_container = self._true_extra_fields(
                data_container, user_field, passwd_field)

            # Handle password-only forms!
            if user_field is not None:
                user, pwd = combination
                data_container[user_field][0] = user
                data_container[passwd_field][0] = pwd
            else:
                user = '******'
                pwd = combination
                data_container[passwd_field][0] = pwd

            freq.set_dc(data_container)

            try:
                resp = self._uri_opener.send_mutant(freq, cookies=False,
                                                    grep=False)
            except ScanMustStopOnUrlError:
                return
            else:
                body = resp.get_body()
                body = body.replace(user, '').replace(pwd, '')

                if self._matches_failed_login(body, login_failed_result_list):
                    return
                
                # Ok, this might be a valid combination.
                # Now test with a new invalid password to ensure our
                # previous possible found credentials are valid
                data_container[passwd_field][0] = rand_alnum(8)
                freq.set_dc(data_container)
                verif_resp = self._uri_opener.send_mutant(freq,
                                                          cookies=False,
                                                          grep=False)
                body = verif_resp.get_body()
                body = body.replace(user, '').replace(pwd, '')

                if self._matches_failed_login(body, login_failed_result_list):
                    freq_url = freq.get_url()
                    self._found.add(freq_url)
                    
                    if user_field is not None:
                        desc = ('Found authentication credentials to: '
                                '"%s". A correct user and password combination'
                                ' is: %s/%s' % (freq_url, user, pwd))
                    else:
                        # There is no user field!
                        desc = ('Found authentication credentials to: '
                                '"%s". The correct password is: "%s".'
                                % (freq_url, pwd))
                        
                    v = Vuln.from_fr('Guessable credentials', desc,
                                     severity.HIGH, resp.id,
                                     self.get_name(), freq)
                    v['user'] = user
                    v['pass'] = pwd
                    v['response'] = resp

                    kb.kb.append(self, 'auth', v)

                    om.out.vulnerability(desc, severity=severity.HIGH)
                    return
Example #25
0
    def audit(self, freq, orig_response):
        """
        Check if the protocol specified in freq is https and fetch the same URL
        using http. ie:
            - input: https://w3af.org/
            - check: http://w3af.org/

        :param freq: A FuzzableRequest
        """
        if not self._should_run:
            return

        initial_uri = freq.get_uri()
        if initial_uri.get_port() not in {80, 443}:
            # We get here then the original URL looks like http://foo:3921/
            #
            # It's really strange (maybe not even possible?) to find a server
            # that listens for HTTP and HTTPS connections on the same port,
            # since we don't want to guess the port, nor generate errors such
            # as #8871 we just ignore this case
            self._should_run = False
            return

        # Define some variables
        insecure_uri = initial_uri.copy()
        secure_uri = initial_uri.copy()

        insecure_uri.set_protocol('http')
        insecure_fr = copy.deepcopy(freq)
        insecure_fr.set_url(insecure_uri)

        secure_uri.set_protocol('https')
        secure_fr = copy.deepcopy(freq)
        secure_fr.set_url(secure_uri)

        # Make sure that we disable error handling during these tests, we want
        # the requests to fail quickly and without affecting the library's error
        # rate
        send_mutant = self._uri_opener.send_mutant
        kwargs = {'grep': False, 'error_handling': False}

        try:
            insecure_response = send_mutant(insecure_fr, **kwargs)
            secure_response = send_mutant(secure_fr,  **kwargs)
        except (HTTPRequestException, ScanMustStopException):
            # No vulnerability to report since one of these threw an error
            # (because there is nothing listening on that port). It makes
            # no sense to keep running since we already got an error
            self._should_run = False

        else:
            if insecure_response is None or secure_response is None:
                # No vulnerability to report since one of these threw an
                # error (because there is nothing listening on that port).
                # It makes no sense to keep running since we already got an
                # error
                self._should_run = False
                return

            if self._redirects_to_secure(insecure_response, secure_response):
                return

            if insecure_response.get_code() == secure_response.get_code()\
            and relative_distance_boolean(insecure_response.get_body(),
                                          secure_response.get_body(),
                                          0.95):
                desc = 'Secure content can be accessed using the insecure'\
                       ' protocol HTTP. The vulnerable URLs are:'\
                       ' "%s" - "%s" .'
                desc = desc % (secure_uri, insecure_uri)

                response_ids = [insecure_response.id, secure_response.id]

                v = Vuln.from_fr('Secure content over insecure channel',
                                 desc, severity.MEDIUM, response_ids,
                                 self.get_name(), freq)

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

                om.out.vulnerability(v.get_desc(), severity=v.get_severity())

                # In most cases, when one resource is available, all are
                # so we just stop searching for this vulnerability
                self._should_run = False
Example #26
0
    def audit(self, freq, orig_response):
        """
        Check if the protocol specified in freq is https and fetch the same URL
        using http. ie:
            - input: https://w3af.org/
            - check: http://w3af.org/

        :param freq: A FuzzableRequest
        """
        if not self._run:
            return
        else:
            # Define some variables
            initial_uri = freq.get_uri()
            insecure_uri = initial_uri.copy()
            secure_uri = initial_uri.copy()

            insecure_uri.set_protocol('http')
            insecure_fr = freq.copy()
            insecure_fr.set_url(insecure_uri)

            secure_uri.set_protocol('https')
            secure_fr = freq.copy()
            secure_fr.set_url(secure_uri)

            # Make sure that we ignore errors during this test
            send_mutant = self._uri_opener.send_mutant
            kwargs = {'grep': False, 'ignore_errors': True}

            try:
                insecure_response = send_mutant(insecure_fr, **kwargs)
                secure_response = send_mutant(secure_fr, **kwargs)
            except (BaseFrameworkException, ScanMustStopException):
                # No vulnerability to report since one of these threw an error
                # (because there is nothing listening on that port). It makes
                # no sense to keep running since we already got an error
                self._run = False

            else:
                if insecure_response is None or secure_response is None:
                    # No vulnerability to report since one of these threw an
                    # error (because there is nothing listening on that port).
                    # It makes no sense to keep running since we already got an
                    # error
                    self._run = False
                    return

                if self._redirects_to_secure(insecure_response,
                                             secure_response):
                    return

                if insecure_response.get_code() == secure_response.get_code()\
                and relative_distance_boolean(insecure_response.get_body(),
                                              secure_response.get_body(),
                                              0.95):
                    desc = 'Secure content can be accessed using the insecure'\
                           ' protocol HTTP. The vulnerable URLs are:'\
                           ' "%s" - "%s" .'
                    desc = desc % (secure_uri, insecure_uri)

                    response_ids = [insecure_response.id, secure_response.id]

                    v = Vuln.from_fr('Secure content over insecure channel',
                                     desc, severity.MEDIUM, response_ids,
                                     self.get_name(), freq)

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

                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())

                    # In most cases, when one resource is available, all are
                    # so we just stop searching for this vulnerability
                    self._run = False
Example #27
0
    def audit(self, freq, orig_response):
        """
        Check if the protocol specified in freq is https and fetch the same URL
        using http. ie:
            - input: https://w3af.org/
            - check: http://w3af.org/

        :param freq: A FuzzableRequest
        """
        if not self._run:
            return
        else:
            # Define some variables
            initial_uri = freq.get_uri()
            insecure_uri = initial_uri.copy()
            secure_uri = initial_uri.copy()

            insecure_uri.set_protocol('http')
            insecure_fr = copy.deepcopy(freq)
            insecure_fr.set_url(insecure_uri)

            secure_uri.set_protocol('https')
            secure_fr = copy.deepcopy(freq)
            secure_fr.set_url(secure_uri)

            # Make sure that we ignore errors during this test
            send_mutant = self._uri_opener.send_mutant
            kwargs = {'grep': False, 'ignore_errors': True}

            try:
                insecure_response = send_mutant(insecure_fr, **kwargs)
                secure_response = send_mutant(secure_fr,  **kwargs)
            except (HTTPRequestException, ScanMustStopException):
                # No vulnerability to report since one of these threw an error
                # (because there is nothing listening on that port). It makes
                # no sense to keep running since we already got an error
                self._run = False

            else:
                if insecure_response is None or secure_response is None:
                    # No vulnerability to report since one of these threw an
                    # error (because there is nothing listening on that port).
                    # It makes no sense to keep running since we already got an
                    # error
                    self._run = False
                    return

                if self._redirects_to_secure(insecure_response, secure_response):
                    return

                if insecure_response.get_code() == secure_response.get_code()\
                and relative_distance_boolean(insecure_response.get_body(),
                                              secure_response.get_body(),
                                              0.95):
                    desc = 'Secure content can be accessed using the insecure'\
                           ' protocol HTTP. The vulnerable URLs are:'\
                           ' "%s" - "%s" .'
                    desc = desc % (secure_uri, insecure_uri)
                    
                    response_ids = [insecure_response.id, secure_response.id]
                    
                    v = Vuln.from_fr('Secure content over insecure channel',
                                     desc, severity.MEDIUM, response_ids,
                                     self.get_name(), freq)

                    self.kb_append(self, 'un_ssl', v)
                    
                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())
                    
                    # In most cases, when one resource is available, all are
                    # so we just stop searching for this vulnerability
                    self._run = False
Example #28
0
    def _brute_worker(self, freq, user_field, passwd_field,
                      login_failed_result_list, combination):
        """
        :param freq: A FuzzableRequest
        :param combination: A tuple with (user, pass) or a pass if this is a
                                password only form.
        """
        if freq.get_url() not in self._found or not self._stop_on_first:
            freq = freq.copy()
            data_container = freq.get_dc()
            data_container = self._true_extra_fields(data_container,
                                                     user_field, passwd_field)

            # Handle password-only forms!
            if user_field is not None:
                user, pwd = combination
                data_container[user_field][0] = user
                data_container[passwd_field][0] = pwd
            else:
                user = '******'
                pwd = combination
                data_container[passwd_field][0] = pwd

            freq.set_dc(data_container)

            try:
                resp = self._uri_opener.send_mutant(freq,
                                                    cookies=False,
                                                    grep=False)
            except ScanMustStopOnUrlError:
                return
            else:
                body = resp.get_body()
                body = body.replace(user, '').replace(pwd, '')

                if self._matches_failed_login(body, login_failed_result_list):
                    return

                # Ok, this might be a valid combination.
                # Now test with a new invalid password to ensure our
                # previous possible found credentials are valid
                data_container[passwd_field][0] = rand_alnum(8)
                freq.set_dc(data_container)
                verif_resp = self._uri_opener.send_mutant(freq,
                                                          cookies=False,
                                                          grep=False)
                body = verif_resp.get_body()
                body = body.replace(user, '').replace(pwd, '')

                if self._matches_failed_login(body, login_failed_result_list):
                    freq_url = freq.get_url()
                    self._found.add(freq_url)

                    if user_field is not None:
                        desc = ('Found authentication credentials to: '
                                '"%s". A correct user and password combination'
                                ' is: %s/%s' % (freq_url, user, pwd))
                    else:
                        # There is no user field!
                        desc = ('Found authentication credentials to: '
                                '"%s". The correct password is: "%s".' %
                                (freq_url, pwd))

                    v = Vuln.from_fr('Guessable credentials',
                                     desc, severity.HIGH, resp.id,
                                     self.get_name(), freq)
                    v['user'] = user
                    v['pass'] = pwd
                    v['response'] = resp

                    kb.kb.append(self, 'auth', v)

                    om.out.vulnerability(desc, severity=severity.HIGH)
                    return