Example #1
0
    def __init__(self, ip, port, urlOpener=ExtendedUrllib(),
                 proxy_cert=Proxy.SSL_CERT):
        """
        :param ip: IP address to bind
        :param port: Port to bind
        :param urlOpener: The urlOpener that will be used to open the requests
                          that arrive from the browser
        :param proxyHandler: A class that will know how to handle requests
                             from the browser
        :param proxy_cert: Proxy certificate to use, this is needed for
                           proxying SSL connections.
        """
        Proxy.__init__(self, ip, port, urlOpener, w3afLocalProxyHandler,
                       proxy_cert)

        self.daemon = True
        self.name = 'LocalProxyThread'

        # Internal vars
        self._request_queue = Queue.Queue()
        self._edited_requests = {}
        self._edited_responses = {}

        # User configured parameters
        self._methods_to_trap = set()
        self._what_to_trap = re.compile('.*')
        self._what_not_to_trap = re.compile('.*\.(gif|jpg|png|css|js|ico|swf|axd|tif)$')
        self._trap = False
        self._fix_content_length = True
Example #2
0
    def __init__(self,
                 ip,
                 port,
                 urlOpener=ExtendedUrllib(),
                 proxy_cert=Proxy.SSL_CERT):
        """
        :param ip: IP address to bind
        :param port: Port to bind
        :param urlOpener: The urlOpener that will be used to open the requests
                          that arrive from the browser
        :param proxyHandler: A class that will know how to handle requests
                             from the browser
        :param proxy_cert: Proxy certificate to use, this is needed for
                           proxying SSL connections.
        """
        Proxy.__init__(self, ip, port, urlOpener, w3afLocalProxyHandler,
                       proxy_cert)

        self.daemon = True
        self.name = 'LocalProxyThread'

        # Internal vars
        self._request_queue = Queue.Queue()
        self._edited_requests = {}
        self._edited_responses = {}

        # User configured parameters
        self._methods_to_trap = set()
        self._what_to_trap = re.compile('.*')
        self._what_not_to_trap = re.compile(
            '.*\.(gif|jpg|png|css|js|ico|swf|axd|tif)$')
        self._trap = False
        self._fix_content_length = True
Example #3
0
    def __init__(self, ip, port, url_opener):
        """
        :param ip: IP address to bind
        :param port: Port to bind
        :param url_opener: The urlOpener that will be used to open the requests
                          that arrive from the browser
        """
        Proxy.__init__(self,
                       ip,
                       port,
                       url_opener,
                       handler_klass=InterceptProxyHandler,
                       name='LocalProxyThread')

        # Internal vars
        self.requests_pending_modification = Queue.Queue()
        self.requests_already_modified = Queue.Queue()

        # User configured parameters
        self.methods_to_trap = set()
        self.what_to_trap = re.compile(self.DEFAULT_TRAP)
        self.what_not_to_trap = re.compile(self.DEFAULT_NO_TRAP)
        self.trap = False

        # Forward to handler
        # pylint: disable=E1103
        self.on_request_edit_finished = self._master.on_request_edit_finished
Example #4
0
class TestExtendedUrllibProxy(unittest.TestCase):

    MOTH_MESSAGE = '<title>moth: vulnerable web application</title>'

    def setUp(self):
        self.uri_opener = ExtendedUrllib()

        # Start the proxy daemon
        self._proxy = Proxy('127.0.0.1', 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()

        port = self._proxy.get_port()

        # Configure the proxy
        settings = OpenerSettings()
        options = settings.get_options()
        proxy_address_opt = options['proxy_address']
        proxy_port_opt = options['proxy_port']

        proxy_address_opt.set_value('127.0.0.1')
        proxy_port_opt.set_value(port)

        settings.set_options(options)
        self.uri_opener.settings = settings

    def tearDown(self):
        self.uri_opener.end()

    def test_http_default_port_via_proxy(self):
        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_http_port_specification_via_proxy(self):
        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_https_via_proxy(self):
        TODO = 'Skip this test because of a strange bug with the extended'\
               ' url library and w3af\'s local proxy daemon. More info here:'\
               ' https://github.com/andresriancho/w3af/issues/183'
        raise SkipTest(TODO)

        url = URL(get_moth_https())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_offline_port_via_proxy(self):
        url = URL('http://127.0.0.1:8181/')
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertEqual(http_response.get_code(), 400)

    def test_POST_via_proxy(self):
        url = URL(get_moth_http('/audit/xss/simple_xss_form.py'))
        http_response = self.uri_opener.POST(url,
                                             data='text=123456abc',
                                             cache=False)
        self.assertIn('123456abc', http_response.body)
Example #5
0
class TestExtendedUrllibProxy(unittest.TestCase):

    MOTH_MESSAGE = '<title>moth: vulnerable web application</title>'

    def setUp(self):
        self.uri_opener = ExtendedUrllib()
        
        # Start the proxy daemon
        self._proxy = Proxy('127.0.0.1', 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()
        
        port = self._proxy.get_port()
        
        # Configure the proxy
        settings = OpenerSettings()
        options = settings.get_options()
        proxy_address_opt = options['proxy_address']
        proxy_port_opt = options['proxy_port']
        
        proxy_address_opt.set_value('127.0.0.1') 
        proxy_port_opt.set_value(port)
        
        settings.set_options(options)
        self.uri_opener.settings = settings
    
    def tearDown(self):
        self.uri_opener.end()
        
    def test_http_default_port_via_proxy(self):
        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_http_port_specification_via_proxy(self):
        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_https_via_proxy(self):
        TODO = 'Skip this test because of a strange bug with the extended'\
               ' url library and w3af\'s local proxy daemon. More info here:'\
               ' https://github.com/andresriancho/w3af/issues/183'
        raise SkipTest(TODO)
    
        url = URL(get_moth_https())
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertIn(self.MOTH_MESSAGE, http_response.body)

    def test_offline_port_via_proxy(self):
        url = URL('http://127.0.0.1:8181/')
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertEqual(http_response.get_code(), 400)
    
    def test_POST_via_proxy(self):
        url = URL(get_moth_http('/audit/xss/simple_xss_form.py'))
        http_response = self.uri_opener.POST(url, data='text=123456abc', cache=False)
        self.assertIn('123456abc', http_response.body)
Example #6
0
 def _start_proxy(self, uri_opener):
     """
     Saves the proxy configuration to self.local_proxy_url in order for the
     wrapper to use it in the calls to sqlmap.py and have the traffic go
     through our proxy (which has the user configuration, logging, etc).
     
     :return: None, an exception is raised if something fails.
     """
     host = '127.0.0.1'
     
     self.proxy = Proxy(host, 0, uri_opener)
     self.proxy.start()
     self.local_proxy_url = 'http://%s:%s/' % (host, self.proxy.get_bind_port())
Example #7
0
    def setUp(self):
        # Start the proxy server
        create_temp_dir()

        self._proxy = Proxy(self.IP, 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()

        port = self._proxy.get_port()

        # Build the proxy opener
        proxy_handler = urllib2.ProxyHandler(
            {"http": "http://%s:%s" % (self.IP, port)})
        self.proxy_opener = urllib2.build_opener(proxy_handler,
                                                 urllib2.HTTPHandler)
Example #8
0
    def crawl(self, freq):

        # Create the proxy server
        try:
            self._proxy = Proxy(self._listen_address, self._listen_port,
                                self._uri_opener, self.create_p_h())
        except ProxyException, proxy_exc:
            om.out.error('%s' % proxy_exc)
Example #9
0
    def setUp(self):
        self.uri_opener = ExtendedUrllib()

        # Start the proxy daemon
        self._proxy = Proxy('127.0.0.2', 0, ExtendedUrllib(), ProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()

        port = self._proxy.get_port()

        # Configure the proxy
        settings = OpenerSettings()
        options = settings.get_options()
        proxy_address_opt = options['proxy_address']
        proxy_port_opt = options['proxy_port']

        proxy_address_opt.set_value('127.0.0.2')
        proxy_port_opt.set_value(port)

        settings.set_options(options)
        self.uri_opener.settings = settings
Example #10
0
 def _start_proxy(self, uri_opener):
     """
     Saves the proxy configuration to self.local_proxy_url in order for the
     wrapper to use it in the calls to sqlmap.py and have the traffic go
     through our proxy (which has the user configuration, logging, etc).
     
     :return: None, an exception is raised if something fails.
     """
     host = '127.0.0.1'
     
     self.proxy = Proxy(host, 0, uri_opener)
     self.proxy.start()
     self.local_proxy_url = 'http://%s:%s/' % (host, self.proxy.get_bind_port())
Example #11
0
    def setUp(self):
        # Start the proxy server
        create_temp_dir()

        self._proxy = Proxy(self.IP, 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()
        
        port = self._proxy.get_port()
        
        # Build the proxy opener
        proxy_handler = urllib2.ProxyHandler({"http": "http://%s:%s"
                                              % (self.IP, port)})
        self.proxy_opener = urllib2.build_opener(proxy_handler,
                                                 urllib2.HTTPHandler)
Example #12
0
    def __init__(self, ip, port, url_opener):
        """
        :param ip: IP address to bind
        :param port: Port to bind
        :param url_opener: The urlOpener that will be used to open the requests
                          that arrive from the browser
        """
        Proxy.__init__(self, ip, port, url_opener,
                       handler_klass=InterceptProxyHandler,
                       name='LocalProxyThread')

        # Internal vars
        self.requests_pending_modification = Queue.Queue()
        self.requests_already_modified = Queue.Queue()

        # User configured parameters
        self.methods_to_trap = set()
        self.what_to_trap = re.compile(self.DEFAULT_TRAP)
        self.what_not_to_trap = re.compile(self.DEFAULT_NO_TRAP)
        self.trap = False

        # Forward to handler
        # pylint: disable=E1103
        self.on_request_edit_finished = self._master.on_request_edit_finished
Example #13
0
 def setUp(self):
     self.uri_opener = ExtendedUrllib()
     
     # Start the proxy daemon
     self._proxy = Proxy('127.0.0.2', 0, ExtendedUrllib(), ProxyHandler)
     self._proxy.start()
     self._proxy.wait_for_start()
     
     port = self._proxy.get_port()
     
     # Configure the proxy
     settings = OpenerSettings()
     options = settings.get_options()
     proxy_address_opt = options['proxy_address']
     proxy_port_opt = options['proxy_port']
     
     proxy_address_opt.set_value('127.0.0.2')
     proxy_port_opt.set_value(port)
     
     settings.set_options(options)
     self.uri_opener.settings = settings
Example #14
0
class SQLMapWrapper(object):

    DEBUG_ARGS = ['-v6']
    DEFAULT_ARGS = [sys.executable, 'sqlmap.py',
                    '--output-dir=%s' % tempfile.gettempdir()]

    SQLMAP_LOCATION = os.path.join(ROOT_PATH, 'plugins', 'attack', 'db', 'sqlmap') 
    VULN_STR = 'sqlmap identified the following injection points'
    NOT_VULN_STR = 'all tested parameters appear to be not injectable'

    SQLMAP_ERRORS = ('connection timed out to the target',
                     'infinite redirect loop detected',
                     'it is not recommended to continue in this kind of cases',
                     'unable to connect to the target url or proxy',
                     "[INFO] skipping '",
                     '[CRITICAL] unable to retrieve page content')
    
    def __init__(self, target, uri_opener, coloring=False, debug=False):
        if not isinstance(target, Target):
            fmt = 'Invalid type %s for target parameter in SQLMapWrapper ctor.'
            raise TypeError(fmt % type(target))

        self._start_proxy(uri_opener)

        self.debug = debug
        self.target = target
        self.coloring = coloring
        self.last_command = None
        self.verified_vulnerable = False
    
    def _start_proxy(self, uri_opener):
        """
        Saves the proxy configuration to self.local_proxy_url in order for the
        wrapper to use it in the calls to sqlmap.py and have the traffic go
        through our proxy (which has the user configuration, logging, etc).
        
        :return: None, an exception is raised if something fails.
        """
        host = '127.0.0.1'
        
        self.proxy = Proxy(host, 0, uri_opener)
        self.proxy.start()
        self.local_proxy_url = 'http://%s:%s/' % (host, self.proxy.get_bind_port())
    
    def cleanup(self):
        self.proxy.stop()
    
    def is_vulnerable(self):
        """
        :return: True if the URL is vulnerable to SQL injection.
        """
        if self.verified_vulnerable:
            return self.verified_vulnerable
        
        params = ['--batch']
        
        full_command, stdout, stderr = self.run_sqlmap(params)
                
        if self.VULN_STR in stdout and self.NOT_VULN_STR not in stdout:
            self.verified_vulnerable = True
            return True
        
        if self.NOT_VULN_STR in stdout and self.VULN_STR not in stdout:
            return False 

        for error_string in self.SQLMAP_ERRORS:
            if error_string in stdout:
                # We found an unknown sqlmap error, such as a timeout
                return False
        
        fmt = 'Unexpected answer found in sqlmap output for command "%s": "%s"'
        raise NotImplementedError(fmt % (full_command, stdout))
    
    def _run(self, custom_params):
        """
        Internal function used by run_sqlmap and run_sqlmap_with_pipes to
        call subprocess.
        
        :return: A Popen object.
        """
        final_params = self.get_wrapper_params(custom_params)
        target_params = self.target.to_params()
        all_params = self.DEFAULT_ARGS + final_params + target_params
        
        if self.debug:
            all_params += self.DEBUG_ARGS

        process = subprocess.Popen(args=all_params,
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   shell=False,
                                   universal_newlines=True,
                                   cwd=self.SQLMAP_LOCATION)
        
        full_command = ' '.join(all_params)
        self.last_command = full_command

        return process
    
    def run_sqlmap(self, custom_params):
        """
        Run sqlmap and wait for it to finish before getting its output.
        
        :param custom_params: A list with the extra parameters that we want to
                              send to sqlmap.
                              
        :return: Runs sqlmap and returns a tuple containing:
                    (last command run,
                     stdout, sterr)
        """
        process = self._run(custom_params)
        self.last_stdout, self.last_stderr = process.communicate()

        om.out.debug('[sqlmap_wrapper] %s' % self.last_command)
        for line in self.last_stdout.split('\n'):
            om.out.debug('[sqlmap_wrapper] %s' % line)

        return self.last_command, self.last_stdout, self.last_stderr
        
    def run_sqlmap_with_pipes(self, custom_params):
        """
        Run sqlmap and immediately return handlers to stdout, stderr and stdin
        so the code using this can interact directly with the process.
        
        :param custom_params: A list with the extra parameters that we want to
                              send to sqlmap.
                              
        :return: Runs sqlmap and returns a tuple with:
                    (last command run,
                     Popen object so that everyone can read .stdout)
                 
                 This is very useful for using with w3af's output manager.
        """
        process = self._run(custom_params)
        return self.last_command, process
    
    def direct(self, params):
        
        if isinstance(params, basestring):
            extra_params = shlex.split(params)
            
        return self.run_sqlmap_with_pipes(extra_params)
    
    def get_wrapper_params(self, extra_params=[]):
        params = []
        
        # TODO: This one will dissapear the day I add stdin handling support
        #       for the wrapper. Please remember that this support will have to
        #       take care of stdin and all other inputs from other UIs
        params.append('--batch')
        
        if not self.coloring:
            params.append('--disable-coloring')
        
        if self.local_proxy_url is not None:
            params.append('--proxy=%s' % self.local_proxy_url)
        
        params.extend(extra_params)
        
        return params
    
    def _wrap_param(self, custom_params):
        """
        Utility function to allow me to easily wrap params.
        
        :return: Runs sqlmap with --dbs and returns a tuple with:
                    (last command run,
                     Popen object so that everyone can read .stdout,
                     .stderr, .stdin attributes)
        """
        process = self._run(custom_params)
        return self.last_command, process
        
    def dbs(self):
        return self._wrap_param(['--dbs',])

    def tables(self):
        return self._wrap_param(['--tables',])

    def users(self):
        return self._wrap_param(['--users',])

    def dump(self):
        return self._wrap_param(['--dump',])

    def read(self, filename):
        """
        :param filename: The file to be read
        :return: The contents of the file that was passed as parameter
        """
        cmd, process = self._wrap_param(['--file-read=%s' % filename,])
        local_file_re = re.compile("the local file (.*?) and")
        # pylint: disable=E1101
        stdout = process.stdout.read()
        
        try:
            local_file = local_file_re.search(stdout).group(1)
        except:
            # FIXME: I'll have to fix this at some point... files that do not
            # exist should raise an exception (or something similar), instead
            # of just returning an empty string. This is a big FAIL from my
            # initial design of the payloads/shell API.
            return ''
        else:
            if os.path.exists(local_file):
                return file(local_file).read()
        
        return 
Example #15
0
class SQLMapWrapper(object):

    OUTPUT_DIR = '%s/%s' % (tempfile.gettempdir(), os.getpid())
    DEBUG_ARGS = ['-v6']
    DEFAULT_ARGS = [
        sys.executable, 'sqlmap.py',
        '--output-dir=%s' % OUTPUT_DIR
    ]

    SQLMAP_LOCATION = os.path.join(ROOT_PATH, 'plugins', 'attack', 'db',
                                   'sqlmap')
    VULN_STR = 'sqlmap identified the following injection points'
    NOT_VULN_STR = 'all tested parameters appear to be not injectable'

    SQLMAP_ERRORS = ('connection timed out to the target',
                     'infinite redirect loop detected',
                     'it is not recommended to continue in this kind of cases',
                     'unable to connect to the target url or proxy',
                     "[INFO] skipping '",
                     '[CRITICAL] unable to retrieve page content')

    def __init__(self, target, uri_opener, coloring=False, debug=False):
        if not isinstance(target, Target):
            fmt = 'Invalid type %s for target parameter in SQLMapWrapper ctor.'
            raise TypeError(fmt % type(target))

        self.debug = debug
        self.target = target
        self.coloring = coloring
        self.last_command = None
        self.verified_vulnerable = False
        self.proxy = None
        self.local_proxy_url = None
        self.last_stdout = None
        self.last_stderr = None

        if uri_opener is not None:
            self.start_proxy(uri_opener)

    def start_proxy(self, uri_opener):
        """
        Saves the proxy configuration to self.local_proxy_url in order for the
        wrapper to use it in the calls to sqlmap.py and have the traffic go
        through our proxy (which has the user configuration, logging, etc).
        
        :return: None, an exception is raised if something fails.
        """
        host = '127.0.0.1'

        self.proxy = Proxy(host, 0, uri_opener, name='SQLMapWrapperProxy')
        self.proxy.start()
        self.local_proxy_url = 'http://%s:%s/' % (host,
                                                  self.proxy.get_bind_port())

    def __reduce__(self):
        """
        Need to define this method in order to remove the uri_opener from the
        pickled string. This will make sure that when the object is un-pickled
        we get the real uri_opener from w3af's core.

        The object being un-pickled is the SQLMapShell, which when un-pickled
        from the kb we call "shell.set_url_opener(w3af_core.uri_opener)",
        which then calls start_proxy(uri_opener) in order to restore the opener
        """
        return self.__class__, (self.target, None, self.coloring, self.debug)

    def cleanup(self):
        self.proxy.stop()

    def is_vulnerable(self):
        """
        :return: True if the URL is vulnerable to SQL injection.
        """
        if self.verified_vulnerable:
            return self.verified_vulnerable

        params = ['--batch']

        full_command, stdout, stderr = self.run_sqlmap(params)

        if self.VULN_STR in stdout and self.NOT_VULN_STR not in stdout:
            self.verified_vulnerable = True
            return True

        if self.NOT_VULN_STR in stdout and self.VULN_STR not in stdout:
            return False

        for error_string in self.SQLMAP_ERRORS:
            if error_string in stdout:
                # We found an unknown sqlmap error, such as a timeout
                return False

        fmt = 'Unexpected answer found in sqlmap output for command "%s": "%s"'
        raise NotImplementedError(fmt % (full_command, stdout))

    def _run(self, custom_params):
        """
        Internal function used by run_sqlmap and run_sqlmap_with_pipes to
        call subprocess.
        
        :return: A Popen object.
        """
        if not os.path.exists(self.OUTPUT_DIR):
            os.mkdir(self.OUTPUT_DIR)

        final_params = self.get_wrapper_params(custom_params)
        target_params = self.target.to_params()
        all_params = self.DEFAULT_ARGS + final_params + target_params

        if self.debug:
            all_params += self.DEBUG_ARGS

        process = subprocess.Popen(args=all_params,
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   shell=False,
                                   universal_newlines=True,
                                   cwd=self.SQLMAP_LOCATION)

        full_command = ' '.join(all_params)
        self.last_command = full_command

        return process

    def run_sqlmap(self, custom_params):
        """
        Run sqlmap and wait for it to finish before getting its output.
        
        :param custom_params: A list with the extra parameters that we want to
                              send to sqlmap.
                              
        :return: Runs sqlmap and returns a tuple containing:
                    (last command run,
                     stdout, sterr)
        """
        process = self._run(custom_params)
        self.last_stdout, self.last_stderr = process.communicate()

        om.out.debug('[sqlmap_wrapper] %s' % self.last_command)
        for line in self.last_stdout.split('\n'):
            om.out.debug('[sqlmap_wrapper] %s' % line)

        return self.last_command, self.last_stdout, self.last_stderr

    def run_sqlmap_with_pipes(self, custom_params):
        """
        Run sqlmap and immediately return handlers to stdout, stderr and stdin
        so the code using this can interact directly with the process.
        
        :param custom_params: A list with the extra parameters that we want to
                              send to sqlmap.
                              
        :return: Runs sqlmap and returns a tuple with:
                    (last command run,
                     Popen object so that everyone can read .stdout)
                 
                 This is very useful for using with w3af's output manager.
        """
        process = self._run(custom_params)
        return self.last_command, process

    def direct(self, params):

        if isinstance(params, basestring):
            extra_params = shlex.split(params)

        return self.run_sqlmap_with_pipes(extra_params)

    def get_wrapper_params(self, extra_params=[]):
        # TODO: This one will disappear the day I add stdin handling support
        #       for the wrapper. Please remember that this support will have to
        #       take care of stdin and all other inputs from other UIs
        params = ['--batch']

        if not self.coloring:
            params.append('--disable-coloring')

        if self.local_proxy_url is not None:
            params.append('--proxy=%s' % self.local_proxy_url)

        params.extend(extra_params)

        return params

    def _wrap_param(self, custom_params):
        """
        Utility function to allow me to easily wrap params.
        
        :return: Runs sqlmap with --dbs and returns a tuple with:
                    (last command run,
                     Popen object so that everyone can read .stdout,
                     .stderr, .stdin attributes)
        """
        process = self._run(custom_params)
        return self.last_command, process

    def dbs(self):
        return self._wrap_param(['--dbs'])

    def tables(self):
        return self._wrap_param(['--tables'])

    def users(self):
        return self._wrap_param(['--users'])

    def dump(self):
        return self._wrap_param(['--dump'])

    def read(self, filename):
        """
        :param filename: The file to be read
        :return: The contents of the file that was passed as parameter
        """
        cmd, process = self._wrap_param(['--file-read=%s' % filename])
        local_file_re = re.compile("the local file (.*?) and")
        # pylint: disable=E1101
        stdout = process.stdout.read()

        try:
            local_file = local_file_re.search(stdout).group(1)
        except:
            # FIXME: I'll have to fix this at some point... files that do not
            # exist should raise an exception (or something similar), instead
            # of just returning an empty string. This is a big FAIL from my
            # initial design of the payloads/shell API.
            return ''
        else:
            if os.path.exists(local_file):
                return file(local_file).read()

        return
Example #16
0
class TestExtendedUrllibProxy(unittest.TestCase):

    MOTH_MESSAGE = '<title>moth: vulnerable web application</title>'

    def setUp(self):
        self.uri_opener = ExtendedUrllib()

        # Start the proxy daemon
        self._proxy = Proxy('127.0.0.2', 0, ExtendedUrllib(), ProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()

        port = self._proxy.get_port()

        # Configure the proxy
        settings = OpenerSettings()
        options = settings.get_options()
        proxy_address_opt = options['proxy_address']
        proxy_port_opt = options['proxy_port']

        proxy_address_opt.set_value('127.0.0.2')
        proxy_port_opt.set_value(port)

        settings.set_options(options)
        self.uri_opener.settings = settings

    def tearDown(self):
        self.uri_opener.end()

    def test_http_default_port_via_proxy(self):
        # TODO: Write this test
        pass

    def test_http_port_specification_via_proxy(self):
        self.assertEqual(self._proxy.total_handled_requests, 0)

        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)

        self.assertIn(self.MOTH_MESSAGE, http_response.body)
        self.assertEqual(self._proxy.total_handled_requests, 1)

    def test_https_via_proxy(self):
        self.assertEqual(self._proxy.total_handled_requests, 0)

        url = URL(get_moth_https())
        http_response = self.uri_opener.GET(url, cache=False)

        self.assertIn(self.MOTH_MESSAGE, http_response.body)
        self.assertEqual(self._proxy.total_handled_requests, 1)

    def test_offline_port_via_proxy(self):
        url = URL('http://127.0.0.1:8181/')
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertEqual(http_response.get_code(), 500)
        self.assertIn('Connection refused', http_response.body)

    def test_POST_via_proxy(self):
        url = URL(get_moth_http('/audit/xss/simple_xss_form.py'))
        http_response = self.uri_opener.POST(url,
                                             data='text=123456abc',
                                             cache=False)
        self.assertIn('123456abc', http_response.body)
Example #17
0
class SQLMapWrapper(object):
    OUTPUT_DIR = '%s/%s' % (tempfile.gettempdir(), os.getpid())
    DEBUG_ARGS = ['-v6']

    # This was added for Debian (and most likely useful for other distributions)
    # because we don't want to have a sqlmap.deb and duplicate the same files
    # in w3af.deb
    #
    # https://github.com/andresriancho/w3af/issues/10538
    #
    INSTALLED_DEFAULT_ARGS = ['sqlmap', '--output-dir=%s' % OUTPUT_DIR]

    # The embedded sqlmap (the whole directory) is removed in Debian
    EMBEDDED_DEFAULT_ARGS = [
        sys.executable, 'sqlmap.py',
        '--output-dir=%s' % OUTPUT_DIR
    ]

    SQLMAP_LOCATION = os.path.join(ROOT_PATH, 'plugins', 'attack', 'db',
                                   'sqlmap')
    VULN_STR = '[INFO] the back-end DBMS is'
    NOT_VULN_STR = 'all tested parameters appear to be not injectable'

    SQLMAP_ERRORS = ('connection timed out to the target',
                     'infinite redirect loop detected',
                     'it is not recommended to continue in this kind of cases',
                     'unable to connect to the target url or proxy',
                     "[INFO] skipping '",
                     '[CRITICAL] unable to retrieve page content',
                     'establish SSL connection')

    def __init__(self, target, uri_opener, coloring=False, debug=False):
        if not isinstance(target, Target):
            fmt = 'Invalid type %s for target parameter in SQLMapWrapper ctor.'
            raise TypeError(fmt % type(target))

        self.debug = debug
        self.target = target
        self.coloring = coloring
        self.last_command = None
        self.verified_vulnerable = False
        self.proxy = None
        self.local_proxy_url = None
        self.last_stdout = None
        self.last_stderr = None

        if uri_opener is not None:
            self.start_proxy(uri_opener)

    def start_proxy(self, uri_opener):
        """
        Saves the proxy configuration to self.local_proxy_url in order for the
        wrapper to use it in the calls to sqlmap.py and have the traffic go
        through our proxy (which has the user configuration, logging, etc).
        
        :return: None, an exception is raised if something fails.
        """
        host = '127.0.0.1'

        self.proxy = Proxy(host, 0, uri_opener, name='SQLMapWrapperProxy')
        self.proxy.start()
        self.proxy.wait_for_start()

        self.local_proxy_url = 'http://%s:%s/' % (host,
                                                  self.proxy.get_bind_port())

    def __reduce__(self):
        """
        Need to define this method in order to remove the uri_opener from the
        pickled string. This will make sure that when the object is un-pickled
        we get the real uri_opener from w3af's core.

        The object being un-pickled is the SQLMapShell, which when un-pickled
        from the kb we call "shell.set_url_opener(w3af_core.uri_opener)",
        which then calls start_proxy(uri_opener) in order to restore the opener
        """
        return self.__class__, (self.target, None, self.coloring, self.debug)

    def cleanup(self):
        self.proxy.stop()

    def is_vulnerable(self):
        """
        :return: True if the URL is vulnerable to SQL injection.
        """
        if self.verified_vulnerable:
            return self.verified_vulnerable

        params = ['--batch']

        full_command, stdout, stderr = self.run_sqlmap(params)

        if full_command is None:
            # Something really bad happen with sqlmap
            return False

        if self.VULN_STR in stdout and self.NOT_VULN_STR not in stdout:
            self.verified_vulnerable = True
            return True

        if self.NOT_VULN_STR in stdout and self.VULN_STR not in stdout:
            return False

        for error_string in self.SQLMAP_ERRORS:
            if error_string in stdout:
                # We found an unknown sqlmap error, such as a timeout
                return False

        fmt = 'Unexpected answer found in sqlmap output for command "%s": "%s"'
        raise NotImplementedError(fmt % (full_command, stdout))

    def _get_base_args(self):
        """
        Simple logic to get the base args in different environments where:
            * sqlmap is in PATH
            * The embedded sqlmap is not available

        :see: https://github.com/andresriancho/w3af/issues/10538

        :return: The base args to execute sqlmap in this environment, or raise
                 an exception if something is wrong.
        """
        if os.path.exists(self.SQLMAP_LOCATION):
            # This is the most common scenario where the user installs w3af
            # from source and wants to use the embedded sqlmap
            return self.SQLMAP_LOCATION, self.EMBEDDED_DEFAULT_ARGS

        # sqlmap is not embedded, most likely because the packager removed
        # it and sqlmap executable is in path, make sure it's there before
        # we return the base args
        if not which('sqlmap'):
            raise RuntimeError('The "sqlmap" command is not in PATH')

        return os.getcwd(), self.INSTALLED_DEFAULT_ARGS

    def _run(self, custom_params):
        """
        Internal function used by run_sqlmap and run_sqlmap_with_pipes to
        call subprocess.
        
        :return: A Popen object.
        """
        if not os.path.exists(self.OUTPUT_DIR):
            os.mkdir(self.OUTPUT_DIR)

        cwd, base_args = self._get_base_args()
        final_params = self.get_wrapper_params(custom_params)
        target_params = self.target.to_params()

        all_params = base_args + final_params + target_params

        if self.debug:
            all_params += self.DEBUG_ARGS

        try:
            process = subprocess.Popen(args=all_params,
                                       stdin=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       shell=False,
                                       universal_newlines=True,
                                       cwd=cwd)
        except OSError, os_err:
            # https://github.com/andresriancho/w3af/issues/10186
            # OSError: [Errno 12] Cannot allocate memory
            if os_err.errno == errno.ENOMEM:
                msg = ('The operating system is running low on memory and'
                       ' failed to start the sqlmap process.')
                om.out.error(msg)

                # This tells the rest of the world that the command failed
                self.last_command = None
                return None
            else:
                # Let me discover/handle other errors
                raise

        else:
Example #18
0
class SQLMapWrapper(object):

    OUTPUT_DIR = '%s/%s' % (tempfile.gettempdir(), os.getpid())
    DEBUG_ARGS = ['-v6']

    # This was added for Debian (and most likely useful for other distributions)
    # because we don't want to have a sqlmap.deb and duplicate the same files
    # in w3af.deb
    #
    # https://github.com/andresriancho/w3af/issues/10538
    #
    INSTALLED_DEFAULT_ARGS = ['sqlmap',
                              '--output-dir=%s' % OUTPUT_DIR]

    # The embedded sqlmap (the whole directory) is removed in Debian
    EMBEDDED_DEFAULT_ARGS = [sys.executable,
                             'sqlmap.py',
                             '--output-dir=%s' % OUTPUT_DIR]

    SQLMAP_LOCATION = os.path.join(ROOT_PATH,
                                   'plugins', 'attack', 'db', 'sqlmap')
    VULN_STR = '[INFO] the back-end DBMS is'
    NOT_VULN_STR = 'all tested parameters do not appear to be injectable'

    SQLMAP_ERRORS = ('connection timed out to the target',
                     'infinite redirect loop detected',
                     'it is not recommended to continue in this kind of cases',
                     'unable to connect to the target url or proxy',
                     "[INFO] skipping '",
                     '[CRITICAL] unable to retrieve page content',
                     'establish SSL connection')
    
    def __init__(self, target, uri_opener, coloring=False, debug=False):
        if not isinstance(target, Target):
            fmt = 'Invalid type %s for target parameter in SQLMapWrapper ctor.'
            raise TypeError(fmt % type(target))

        self.debug = debug
        self.target = target
        self.coloring = coloring
        self.last_command = None
        self.verified_vulnerable = False
        self.proxy = None
        self.local_proxy_url = None
        self.last_stdout = None
        self.last_stderr = None

        if uri_opener is not None:
            self.start_proxy(uri_opener)

    def start_proxy(self, uri_opener):
        """
        Saves the proxy configuration to self.local_proxy_url in order for the
        wrapper to use it in the calls to sqlmap.py and have the traffic go
        through our proxy (which has the user configuration, logging, etc).
        
        :return: None, an exception is raised if something fails.
        """
        host = '127.0.0.1'
        
        self.proxy = Proxy(host, 0, uri_opener, name='SQLMapWrapperProxy')
        self.proxy.start()
        self.proxy.wait_for_start()

        self.local_proxy_url = 'http://%s:%s/' % (host,
                                                  self.proxy.get_bind_port())

    def __reduce__(self):
        """
        Need to define this method in order to remove the uri_opener from the
        pickled string. This will make sure that when the object is un-pickled
        we get the real uri_opener from w3af's core.

        The object being un-pickled is the SQLMapShell, which when un-pickled
        from the kb we call "shell.set_url_opener(w3af_core.uri_opener)",
        which then calls start_proxy(uri_opener) in order to restore the opener
        """
        return self.__class__, (self.target, None, self.coloring, self.debug)

    def cleanup(self):
        self.proxy.stop()
    
    def is_vulnerable(self):
        """
        :return: True if the URL is vulnerable to SQL injection.
        """
        if self.verified_vulnerable:
            return self.verified_vulnerable
        
        params = ['--batch']
        
        full_command, stdout, stderr = self.run_sqlmap(params)

        if full_command is None:
            # Something really bad happen with sqlmap
            return False
                
        if self.VULN_STR in stdout and self.NOT_VULN_STR not in stdout:
            self.verified_vulnerable = True
            return True
        
        if self.NOT_VULN_STR in stdout and self.VULN_STR not in stdout:
            return False 

        for error_string in self.SQLMAP_ERRORS:
            if error_string in stdout:
                # We found an unknown sqlmap error, such as a timeout
                return False
        
        fmt = 'Unexpected answer found in sqlmap output for command "%s": "%s"'
        raise NotImplementedError(fmt % (full_command, stdout))

    def _get_base_args(self):
        """
        Simple logic to get the base args in different environments where:
            * sqlmap is in PATH
            * The embedded sqlmap is not available

        :see: https://github.com/andresriancho/w3af/issues/10538

        :return: The base args to execute sqlmap in this environment, or raise
                 an exception if something is wrong.
        """
        if os.path.exists(self.SQLMAP_LOCATION):
            # This is the most common scenario where the user installs w3af
            # from source and wants to use the embedded sqlmap
            return self.SQLMAP_LOCATION, self.EMBEDDED_DEFAULT_ARGS

        # sqlmap is not embedded, most likely because the packager removed
        # it and sqlmap executable is in path, make sure it's there before
        # we return the base args
        if not which('sqlmap'):
            raise RuntimeError('The "sqlmap" command is not in PATH')

        return os.getcwd(), self.INSTALLED_DEFAULT_ARGS

    def _run(self, custom_params):
        """
        Internal function used by run_sqlmap and run_sqlmap_with_pipes to
        call subprocess.
        
        :return: A Popen object.
        """
        if not os.path.exists(self.OUTPUT_DIR):
            os.mkdir(self.OUTPUT_DIR)

        cwd, base_args = self._get_base_args()
        final_params = self.get_wrapper_params(custom_params)
        target_params = self.target.to_params()

        all_params = base_args + final_params + target_params
        
        if self.debug:
            all_params += self.DEBUG_ARGS

        try:
            process = subprocess.Popen(args=all_params,
                                       stdin=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       shell=False,
                                       universal_newlines=True,
                                       cwd=cwd)
        except OSError, os_err:
            # https://github.com/andresriancho/w3af/issues/10186
            # OSError: [Errno 12] Cannot allocate memory
            if os_err.errno == errno.ENOMEM:
                msg = ('The operating system is running low on memory and'
                       ' failed to start the sqlmap process.')
                om.out.error(msg)

                # This tells the rest of the world that the command failed
                self.last_command = None
                return None
            else:
                # Let me discover/handle other errors
                raise

        else:
Example #19
0
class TestProxy(unittest.TestCase):

    IP = '127.0.0.1'

    def setUp(self):
        # Start the proxy server
        create_temp_dir()

        self._proxy = Proxy(self.IP, 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()
        
        port = self._proxy.get_port()
        
        # Build the proxy opener
        proxy_handler = urllib2.ProxyHandler({"http": "http://%s:%s"
                                              % (self.IP, port)})
        self.proxy_opener = urllib2.build_opener(proxy_handler,
                                                 urllib2.HTTPHandler)

    def test_do_req_through_proxy(self):
        resp_body = self.proxy_opener.open(get_moth_http()).read()

        # Basic check
        self.assertTrue(len(resp_body) > 0)

        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_http())
        # Get it without any proxy
        direct_resp = urllib2.urlopen(get_moth_http())

        # Must be equal
        self.assertEqual(direct_resp.read(), proxy_resp.read())

        # Have to remove the Date header because in some cases they differ
        # because one request was sent in second X and the other in X+1, which
        # makes the test fail
        direct_resp_headers = dict(direct_resp.info())
        proxy_resp_headers = dict(proxy_resp.info())

        # Make sure that a change in the seconds returned in date doesn't break
        # the test
        del direct_resp_headers['date']
        del proxy_resp_headers['date']

        del direct_resp_headers['transfer-encoding']
        del proxy_resp_headers['content-length']

        self.assertEqual(direct_resp_headers, proxy_resp_headers)

    def test_do_ssl_req_through_proxy(self):
        resp_body = self.proxy_opener.open(get_moth_https()).read()

        # Basic check
        self.assertTrue(len(resp_body) > 0)

        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_https())
        # Get it without any proxy
        direct_resp = urllib2.urlopen(get_moth_https())

        # Must be equal
        self.assertEqual(direct_resp.read(), proxy_resp.read())

        # Have to remove the Date header because in some cases they differ
        # because one request was sent in second X and the other in X+1, which
        # makes the test fail
        direct_resp_headers = dict(direct_resp.info())
        proxy_resp_headers = dict(proxy_resp.info())
        del direct_resp_headers['date']
        del proxy_resp_headers['date']
        self.assertEqual(direct_resp_headers, proxy_resp_headers)

    def test_proxy_req_ok(self):
        """Test if self._proxy.stop() works as expected. Note that the check
        content is the same as the previous check, but it might be that this
        check fails because of some error in start() or stop() which is run
        during setUp and tearDown."""
        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_http()).read()
        # Get it the other way
        resp = urllib2.urlopen(get_moth_http()).read()
        # They must be very similar
        self.assertEqual(resp, proxy_resp)
    
    def test_stop_no_requests(self):
        """Test what happens if I stop the proxy without sending any requests
        through it"""
        # Note that the test is completed by self._proxy.stop() in tearDown
        pass

    def test_stop_stop(self):
        """Test what happens if I stop the proxy twice."""
        # Note that the test is completed by self._proxy.stop() in tearDown
        self._proxy.stop()
    
    def tearDown(self):
        # Shutdown the proxy server
        self._proxy.stop()
Example #20
0
class TestProxy(unittest.TestCase):

    IP = '127.0.0.1'

    def setUp(self):
        # Start the proxy server
        create_temp_dir()

        self._proxy = Proxy(self.IP, 0, ExtendedUrllib(), w3afProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()

        port = self._proxy.get_port()

        # Build the proxy opener
        proxy_handler = urllib2.ProxyHandler(
            {"http": "http://%s:%s" % (self.IP, port)})
        self.proxy_opener = urllib2.build_opener(proxy_handler,
                                                 urllib2.HTTPHandler)

    def test_do_req_through_proxy(self):
        resp_body = self.proxy_opener.open(get_moth_http()).read()

        # Basic check
        self.assertTrue(len(resp_body) > 0)

        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_http())
        # Get it without any proxy
        direct_resp = urllib2.urlopen(get_moth_http())

        # Must be equal
        self.assertEqual(direct_resp.read(), proxy_resp.read())

        # Have to remove the Date header because in some cases they differ
        # because one request was sent in second X and the other in X+1, which
        # makes the test fail
        direct_resp_headers = dict(direct_resp.info())
        proxy_resp_headers = dict(proxy_resp.info())

        # Make sure that a change in the seconds returned in date doesn't break
        # the test
        del direct_resp_headers['date']
        del proxy_resp_headers['date']

        del direct_resp_headers['transfer-encoding']
        del proxy_resp_headers['content-length']

        self.assertEqual(direct_resp_headers, proxy_resp_headers)

    def test_do_ssl_req_through_proxy(self):
        resp_body = self.proxy_opener.open(get_moth_https()).read()

        # Basic check
        self.assertTrue(len(resp_body) > 0)

        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_https())
        # Get it without any proxy
        direct_resp = urllib2.urlopen(get_moth_https())

        # Must be equal
        self.assertEqual(direct_resp.read(), proxy_resp.read())

        # Have to remove the Date header because in some cases they differ
        # because one request was sent in second X and the other in X+1, which
        # makes the test fail
        direct_resp_headers = dict(direct_resp.info())
        proxy_resp_headers = dict(proxy_resp.info())
        del direct_resp_headers['date']
        del proxy_resp_headers['date']
        self.assertEqual(direct_resp_headers, proxy_resp_headers)

    def test_proxy_req_ok(self):
        """Test if self._proxy.stop() works as expected. Note that the check
        content is the same as the previous check, but it might be that this
        check fails because of some error in start() or stop() which is run
        during setUp and tearDown."""
        # Get response using the proxy
        proxy_resp = self.proxy_opener.open(get_moth_http()).read()
        # Get it the other way
        resp = urllib2.urlopen(get_moth_http()).read()
        # They must be very similar
        self.assertEqual(resp, proxy_resp)

    def test_stop_no_requests(self):
        """Test what happens if I stop the proxy without sending any requests
        through it"""
        # Note that the test is completed by self._proxy.stop() in tearDown
        pass

    def test_stop_stop(self):
        """Test what happens if I stop the proxy twice."""
        # Note that the test is completed by self._proxy.stop() in tearDown
        self._proxy.stop()

    def tearDown(self):
        # Shutdown the proxy server
        self._proxy.stop()
Example #21
0
class TestExtendedUrllibProxy(unittest.TestCase):

    MOTH_MESSAGE = '<title>moth: vulnerable web application</title>'

    def setUp(self):
        self.uri_opener = ExtendedUrllib()
        
        # Start the proxy daemon
        self._proxy = Proxy('127.0.0.2', 0, ExtendedUrllib(), ProxyHandler)
        self._proxy.start()
        self._proxy.wait_for_start()
        
        port = self._proxy.get_port()
        
        # Configure the proxy
        settings = OpenerSettings()
        options = settings.get_options()
        proxy_address_opt = options['proxy_address']
        proxy_port_opt = options['proxy_port']
        
        proxy_address_opt.set_value('127.0.0.2')
        proxy_port_opt.set_value(port)
        
        settings.set_options(options)
        self.uri_opener.settings = settings
    
    def tearDown(self):
        self.uri_opener.end()
        
    def test_http_default_port_via_proxy(self):
        # TODO: Write this test
        pass

    def test_http_port_specification_via_proxy(self):
        self.assertEqual(self._proxy.total_handled_requests, 0)

        url = URL(get_moth_http())
        http_response = self.uri_opener.GET(url, cache=False)

        self.assertIn(self.MOTH_MESSAGE, http_response.body)
        self.assertEqual(self._proxy.total_handled_requests, 1)

    def test_https_via_proxy(self):
        self.assertEqual(self._proxy.total_handled_requests, 0)

        url = URL(get_moth_https())
        http_response = self.uri_opener.GET(url, cache=False)

        self.assertIn(self.MOTH_MESSAGE, http_response.body)
        self.assertEqual(self._proxy.total_handled_requests, 1)

    def test_offline_port_via_proxy(self):
        url = URL('http://127.0.0.1:8181/')
        http_response = self.uri_opener.GET(url, cache=False)
        self.assertEqual(http_response.get_code(), 500)
        self.assertIn('Connection refused', http_response.body)
    
    def test_POST_via_proxy(self):
        url = URL(get_moth_http('/audit/xss/simple_xss_form.py'))
        http_response = self.uri_opener.POST(url, data='text=123456abc', cache=False)
        self.assertIn('123456abc', http_response.body)