예제 #1
0
    def test_delay_controlled_random(self):
        for expected_result, delays in self.TEST_SUITE:
            print delays
            mock_uri_opener = Mock()
            side_effect = generate_delays(delays, rand_range=(0, 2))
            mock_uri_opener.send_mutant = MagicMock(side_effect=side_effect)
            delay_obj = ExactDelay('sleep(%s)')

            url = URL('http://moth/?id=1')
            req = FuzzableRequest(url)
            mutant = QSMutant(req)
            mutant.set_dc(url.querystring)
            mutant.set_var('id', 0)

            ed = ExactDelayController(mutant, delay_obj, mock_uri_opener)
            controlled, responses = ed.delay_is_controlled()

            # This is where we change from test_delay_controlled, the basic
            # idea is that we'll allow false negatives but no false positives
            if expected_result == True:
                expected_result = [True, False]
            else:
                expected_result = [
                    False,
                ]

            self.assertIn(controlled, expected_result, delays)
예제 #2
0
    def _with_time_delay(self, freq):
        """
        Tests an URL for OS Commanding vulnerabilities using time delays.

        :param freq: A FuzzableRequest
        """
        fake_mutants = create_mutants(freq, [
            '',
        ])

        for mutant in fake_mutants:

            if self._has_bug(mutant):
                continue

            for delay_obj in self._get_wait_commands():

                ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
                success, responses = ed.delay_is_controlled()

                if success:
                    desc = 'OS Commanding was found at: %s' % mutant.found_at()

                    v = Vuln.from_mutant('OS commanding vulnerability', desc,
                                         severity.HIGH,
                                         [r.id for r in responses],
                                         self.get_name(), mutant)

                    v['os'] = delay_obj.get_OS()
                    v['separator'] = delay_obj.get_separator()

                    self.kb_append_uniq(self, 'os_commanding', v)
                    break
예제 #3
0
    def is_injectable(self, mutant):
        """
        Check if this mutant is delay injectable or not.

        @mutant: The mutant object that I have to inject to
        :return: A vulnerability object or None if nothing is found
        """
        for delay_obj in self._get_delays():

            ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
            success, responses = ed.delay_is_controlled()

            if success:
                # Now I can be sure that I found a vuln, we control the response
                # time with the delay
                desc = 'Blind SQL injection using time delays was found at: %s'
                desc = desc % mutant.found_at()

                response_ids = [r.id for r in responses]

                v = Vuln.from_mutant('Blind SQL injection vulnerability', desc,
                                     severity.HIGH, response_ids, 'blind_sqli',
                                     mutant)

                om.out.debug(v.get_desc())

                return v

        return None
예제 #4
0
    def test_delay_controlled(self):

        for expected_result, delays in self.TEST_SUITE:
            mock_uri_opener = Mock()
            side_effect = generate_delays(delays)
            mock_uri_opener.send_mutant = MagicMock(side_effect=side_effect)
            delay_obj = ExactDelay('sleep(%s)')

            url = URL('http://moth/?id=1')
            req = FuzzableRequest(url)
            mutant = QSMutant(req)
            mutant.set_dc(url.querystring)
            mutant.set_token(('id', 0))

            ed = ExactDelayController(mutant, delay_obj, mock_uri_opener)
            controlled, responses = ed.delay_is_controlled()
            self.assertEqual(expected_result, controlled, delays)
예제 #5
0
    def _with_time_delay(self, freq):
        """
        Tests an URLs for shell shock vulnerabilities using time delays.

        :param freq: A FuzzableRequest
        :return: True if a vulnerability was found
        """
        mutant = self.create_mutant(freq, TEST_HEADER)

        for delay_obj in self.DELAY_TESTS:
            ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
            success, responses = ed.delay_is_controlled()

            if success:
                mutant.set_token_value(delay_obj.get_string_for_delay(3))
                desc = u'Shell shock was found at: %s' % mutant.found_at()

                v = Vuln.from_mutant(u'Shell shock vulnerability', desc,
                                     severity.HIGH, [r.id for r in responses],
                                     self.get_name(), mutant)

                self.kb_append_uniq(self, 'shell_shock', v)
                return True
예제 #6
0
    def _test_delay(self, mutant):
        """
        Try to delay the response and save a vulnerability if successful
        """
        if self._has_bug(mutant):
            return

        for delay_obj in self.WAIT_OBJ:

            ed_inst = ExactDelayController(mutant, delay_obj, self._uri_opener)
            success, responses = ed_inst.delay_is_controlled()

            if success:
                desc = 'eval() input injection was found at: %s'
                desc = desc % mutant.found_at()

                response_ids = [r.id for r in responses]

                v = Vuln.from_mutant('eval() input injection vulnerability',
                                     desc, severity.HIGH, response_ids,
                                     self.get_name(), mutant)

                self.kb_append_uniq(self, 'eval', v)
                break
예제 #7
0
파일: eval.py 프로젝트: zsdlove/w3af
class eval(AuditPlugin):
    """
    Find insecure eval() usage.

    :author: Viktor Gazdag ( [email protected] )
    :author: Andres Riancho ([email protected])
    """
    PRINT_REPEATS = 5

    PRINT_STRINGS = (
        # PHP http://php.net/eval
        "echo str_repeat('%%s',%s);" % PRINT_REPEATS,
        # Perl http://perldoc.perl.org/functions/eval.html
        "print '%%s'x%s" % PRINT_REPEATS,
        # Python
        # http://docs.python.org/reference/simple_stmts.html#the-exec-statement
        "print('%%s'*%s)" % PRINT_REPEATS,
        # ASP
        "Response.Write(new String(\"%%s\",%s))" % PRINT_REPEATS,
    )

    WAIT_OBJ = (
        # PHP http://php.net/sleep
        # Perl http://perldoc.perl.org/functions/sleep.html
        ExactDelay("sleep(%s);"),
        # Python http://docs.python.org/library/time.html#time.sleep
        ExactDelay("__import__('time').sleep(%s)"),
        # It seems that ASP doesn't support sleep! A language without sleep...
        # is not a language!
        # http://classicasp.aspfaq.com/general/how-do-i-make-my-asp-page-pause-or-sleep.html
        # JSP takes the amount in miliseconds
        # http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html#sleep(long)
        ExactDelay("Thread.sleep(%s);", mult=1000),
        # ASP.NET also uses miliseconds
        # http://msdn.microsoft.com/en-us/library/d00bd51t.aspx
        # Note: The Sleep in ASP.NET is uppercase
        ExactDelay("Thread.Sleep(%s);", mult=1000),
        # NodeJS eval
        ExactDelay("var cd;var d=new Date();do{cd=new Date();}while(cd-d<%s)", mult=1000)
    )

    def __init__(self):
        AuditPlugin.__init__(self)

        # Create some random strings, which the plugin will use.
        # for the fuzz_with_echo
        self._rnd = rand_alpha(5)
        self._rnd = self._rnd.lower()
        self._expected_result = self._rnd * self.PRINT_REPEATS

        # User configured parameters
        self._use_time_delay = True
        self._use_echo = True

    def audit(self, freq, orig_response, debugging_id):
        """
        Tests an URL for eval() user input injection vulnerabilities.

        :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 self._use_echo:
            self._fuzz_with_echo(freq, orig_response, debugging_id)

        if self._use_time_delay:
            self._fuzz_with_time_delay(freq, debugging_id)

    def _fuzz_with_echo(self, freq, orig_response, debugging_id):
        """
        Tests an URL for eval() usage vulnerabilities using echo strings.
        :param freq: A FuzzableRequest
        """
        print_strings = [pstr % (self._rnd,) for pstr in self.PRINT_STRINGS]

        mutants = create_mutants(freq, print_strings, orig_resp=orig_response)

        self._send_mutants_in_threads(self._uri_opener.send_mutant,
                                      mutants,
                                      self._analyze_echo,
                                      debugging_id=debugging_id)

    def _fuzz_with_time_delay(self, freq, debugging_id):
        """
        Tests an URL for eval() usage vulnerabilities using time delays.
        :param freq: A FuzzableRequest
        """
        self._send_mutants_in_threads(func=self._find_delay_in_mutant,
                                      iterable=self._generate_delay_tests(freq, debugging_id),
                                      callback=lambda x, y: None)

    def _generate_delay_tests(self, freq, debugging_id):
        for mutant in create_mutants(freq, ['', ]):
            #
            # Don't try to find an eval() using a time delay method if we already found
            # it via echo
            #
            if self._has_bug(mutant):
                return

            for delay_obj in self.WAIT_OBJ:
                yield mutant, delay_obj, debugging_id

    def _find_delay_in_mutant(self, (mutant, delay_obj, debugging_id)):
        """
        Try to delay the response and save a vulnerability if successful

        :param mutant: The mutant to modify and test
        :param delay_obj: The delay to use
        :param debugging_id: The debugging ID for logging
        """
        if self._has_bug(mutant):
            return

        ed_inst = ExactDelayController(mutant, delay_obj, self._uri_opener)
        ed_inst.set_debugging_id(debugging_id)
        success, responses = ed_inst.delay_is_controlled()

        if success:
            desc = 'eval() input injection was found at: %s'
            desc %= mutant.found_at()

            response_ids = [r.id for r in responses]

            v = Vuln.from_mutant('eval() input injection vulnerability',
                                 desc, severity.HIGH, response_ids,
                                 self.get_name(), mutant)

            self.kb_append_uniq(self, 'eval', v)
예제 #8
0
class shell_shock(AuditPlugin):
    """
    Find shell shock vulnerabilities.
    :author: Andres Riancho ([email protected])
    """
    DELAY_TESTS = [PingDelay('() { test; }; ping -c %s 127.0.0.1'),
                   ExactDelay('() { test; }; sleep %s')]

    def __init__(self):
        super(shell_shock, self).__init__()
        self.already_tested_urls = ScalableBloomFilter()

    def audit(self, freq, orig_response, debugging_id):
        """
        Tests an URL for shell shock vulnerabilities.

        :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()
        """
        url = freq.get_url()

        # Here the script is vulnerable, not a specific parameter, so we
        # run unique tests per URL
        if url not in self.already_tested_urls:
            self.already_tested_urls.add(url)

            # We are implementing these methods for detecting shell-shock vulns
            # if you know about other methods, or have improvements on these
            # please let us know. Pull-requests are also welcome.
            for detection_method in [self._with_header_echo_injection,
                                     #self._with_body_echo_injection,
                                     self._with_time_delay]:
                if detection_method(freq, debugging_id):
                    break

    def _with_header_echo_injection(self, freq, debugging_id):
        """
        We're sending a payload that will trigger the injection of various
        headers in the HTTP response body.

        :param freq: A FuzzableRequest
        :return: True if a vulnerability was found
        """
        injected_header = 'shellshock'
        injected_value = 'check'
        payload = '() { :;}; echo "%s: %s"' % (injected_header, injected_value)

        mutant = self.create_mutant(freq, TEST_HEADER)
        mutant.set_token_value(payload)

        response = self._uri_opener.send_mutant(mutant, debugging_id=debugging_id)
        header_value, header_name = response.get_headers().iget(injected_header)

        if header_value is not None and injected_value in header_value.lower():
            desc = u'Shell shock was found at: %s' % mutant.found_at()

            v = Vuln.from_mutant(u'Shell shock vulnerability', desc,
                                 severity.HIGH, [response.id],
                                 self.get_name(), mutant)

            self.kb_append_uniq(self, 'shell_shock', v)
            return True

    def _with_body_echo_injection(self, freq, debugging_id):
        """
        We're sending a payload that will trigger the injection of new lines
        that will make the response transition from "headers" to "body".

        :param freq: A FuzzableRequest
        :return: True if a vulnerability was found
        """
        raise NotImplementedError

    def create_mutant(self, freq, header_name):
        headers = freq.get_headers()
        headers[header_name] = ''
        freq.set_headers(headers)

        fuzzer_config = {'fuzzable_headers': [TEST_HEADER]}

        mutant = HeadersMutant.create_mutants(freq, [''], [TEST_HEADER],
                                              False, fuzzer_config)[0]

        return mutant

    def _with_time_delay(self, freq, debugging_id):
        """
        Tests an URLs for shell shock vulnerabilities using time delays.

        :param freq: A FuzzableRequest
        :return: True if a vulnerability was found
        """
        self._send_mutants_in_threads(func=self._find_delay_in_mutant,
                                      iterable=self._generate_delay_tests(freq, debugging_id),
                                      callback=lambda x, y: None)

    def _generate_delay_tests(self, freq, debugging_id):
        for delay_obj in self.DELAY_TESTS:
            mutant = self.create_mutant(freq, TEST_HEADER)
            yield mutant, delay_obj, debugging_id

    def _find_delay_in_mutant(self, (mutant, delay_obj, debugging_id)):
        """
        Try to delay the response and save a vulnerability if successful

        :param mutant: The mutant to modify and test
        :param delay_obj: The delay to use
        :param debugging_id: The debugging ID for logging
        """
        ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
        ed.set_debugging_id(debugging_id)
        success, responses = ed.delay_is_controlled()

        if not success:
            return False

        mutant.set_token_value(delay_obj.get_string_for_delay(3))
        desc = u'Shell shock was found at: %s' % mutant.found_at()

        v = Vuln.from_mutant(u'Shell shock vulnerability', desc,
                             severity.HIGH, [r.id for r in responses],
                             self.get_name(), mutant)

        self.kb_append_uniq(self, 'shell_shock', v)
        return True
예제 #9
0
                if file_name.endswith(self.PAYLOAD_EXTENSION):
                    json_str = file(os.path.join(root, file_name)).read()
                    yield language, json.loads(json_str)

    def _find_delay_in_mutant(self, (mutant, delay_obj), debugging_id=None):
        """
        Try to delay the response and save a vulnerability if successful

        :param mutant: The mutant to modify and test
        :param delay_obj: The delay to use
        :param debugging_id: The debugging ID for logging
        """
        if self._has_bug(mutant):
            return

        ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
        ed.set_debugging_id(debugging_id)
        success, responses = ed.delay_is_controlled()

        if not success:
            return

        desc = 'Insecure deserialization vulnerability was found at: %s'
        desc %= mutant.found_at()

        v = Vuln.from_mutant('Insecure deserialization', desc,
                             severity.HIGH, [r.id for r in responses],
                             self.get_name(), mutant)

        self.kb_append_uniq(self, 'deserialization', v)
예제 #10
0
class os_commanding(AuditPlugin):
    """
    Find OS Commanding vulnerabilities.
    :author: Andres Riancho ([email protected])
    """

    FILE_PATTERNS = FILE_PATTERNS
    _multi_in = MultiIn(FILE_PATTERNS)

    def __init__(self):
        AuditPlugin.__init__(self)

        #
        #   Some internal variables
        #
        self._special_chars = ['', '&&', '|', ';', '\n', '\r\n']
        self._file_compiled_regex = []

    def audit(self, freq, orig_response, debugging_id):
        """
        Tests an URL for OS Commanding vulnerabilities.

        :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()
        """
        # We are implementing two different ways of detecting OS Commanding
        # vulnerabilities:
        #       - Time delays
        #       - Writing a known file to the HTML output
        # The basic idea is to be able to detect ANY vulnerability, so we use
        # ALL of the known techniques
        #
        # Please note that I'm running the echo ones first in order to get them
        # into the KB before the ones with time delays so that the os_commanding
        # exploit can (with a higher degree of confidence) exploit the
        # vulnerability
        #
        # This also speeds-up the detection process a little bit in the cases
        # where there IS a vulnerability present and can be found with both
        # methods.
        self._with_echo(freq, orig_response, debugging_id)
        self._with_time_delay(freq, debugging_id)

    def _with_echo(self, freq, orig_response, debugging_id):
        """
        Tests an URL for OS Commanding vulnerabilities using cat/type to write
        the content of a known file (i.e. /etc/passwd) to the HTML.

        :param freq: A FuzzableRequest
        """
        # Prepare the strings to create the mutants
        command_list = self._get_echo_commands()
        only_command_strings = [v.get_command() for v in command_list]

        # Create the mutants, notice that we use append=False (default) and
        # True to have better coverage.
        mutants = create_mutants(freq,
                                 only_command_strings,
                                 orig_resp=orig_response)
        mutants.extend(
            create_mutants(freq,
                           only_command_strings,
                           orig_resp=orig_response,
                           append=True))

        self._send_mutants_in_threads(self._uri_opener.send_mutant,
                                      mutants,
                                      self._analyze_echo,
                                      debugging_id=debugging_id)

    def _analyze_echo(self, mutant, response):
        """
        Analyze results of the _send_mutant method that was sent in the
        _with_echo method.
        """
        #
        #   I will only report the vulnerability once.
        #
        if self._has_bug(mutant):
            return

        for file_pattern_match in self._multi_in.query(response.get_body()):

            if file_pattern_match in mutant.get_original_response_body():
                continue

            # Search for the correct command and separator
            sent_os, sent_separator = self._get_os_separator(mutant)

            desc = 'OS Commanding was found at: %s' % mutant.found_at()
            # Create the vuln obj
            v = Vuln.from_mutant('OS commanding vulnerability',
                                 desc, severity.HIGH, response.id,
                                 self.get_name(), mutant)

            v['os'] = sent_os
            v['separator'] = sent_separator
            v.add_to_highlight(file_pattern_match)

            self.kb_append_uniq(self, 'os_commanding', v)
            break

    def _get_os_separator(self, mutant):
        """
        :param mutant: The mutant that is being analyzed.
        :return: A tuple with the OS and the command separator
        that was used to generate the mutant.
        """
        os = separator = None

        # Retrieve the data I need to create the vuln and the info objects
        command_list = self._get_echo_commands()

        # TODO: Are you sure that this works as expected ?!
        for comm in command_list:
            if comm.get_command() in mutant.get_token_value():
                os = comm.get_OS()
                separator = comm.get_separator()

        return os, separator

    def _with_time_delay(self, freq, debugging_id):
        """
        Tests an URL for OS Commanding vulnerabilities using time delays.

        :param freq: A FuzzableRequest
        """
        self._send_mutants_in_threads(func=self._find_delay_in_mutant,
                                      iterable=self._generate_delay_tests(
                                          freq, debugging_id),
                                      callback=lambda x, y: None)

    def _generate_delay_tests(self, freq, debugging_id):
        fake_mutants = create_mutants(freq, [
            '',
        ])
        fake_mutants.extend(create_mutants(freq, [
            '',
        ], append=True))

        for mutant in fake_mutants:
            #
            # Don't try to find an OS commanding using a time delay method
            # if we already found it via echo
            #
            if self._has_bug(mutant):
                return

            for delay_obj in self._get_wait_commands():
                yield mutant, delay_obj, debugging_id

    def _find_delay_in_mutant(self, (mutant, delay_obj, debugging_id)):
        """
        Try to delay the response and save a vulnerability if successful

        :param mutant: The mutant to modify and test
        :param delay_obj: The delay to use
        :param debugging_id: The debugging ID for logging
        """
        if self._has_bug(mutant):
            return

        ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
        ed.set_debugging_id(debugging_id)
        success, responses = ed.delay_is_controlled()

        if not success:
            return

        desc = 'OS Commanding was found at: %s' % mutant.found_at()

        v = Vuln.from_mutant('OS commanding vulnerability', desc,
                             severity.HIGH, [r.id for r in responses],
                             self.get_name(), mutant)

        v['os'] = delay_obj.get_OS()
        v['separator'] = delay_obj.get_separator()

        self.kb_append_uniq(self, 'os_commanding', v)