예제 #1
0
    def setUp(self):
        super(BaseTest, self).setUp()
        self.reset_backend()

        defaults = init_defaults('DroopeScan', 'general')
        defaults['general']['pwd'] = os.getcwd()
        self.app = DroopeScan(argv=[],
                              plugin_config_dir=dscan.PWD + "./plugins.d",
                              plugin_dir=dscan.PWD + "./plugins",
                              config_defaults=defaults)

        handler.register(Scan)
        self.app.testing = True
        self.app.setup()
        responses.add(responses.HEAD, self.base_url, status=200)
예제 #2
0
    def setUp(self):
        super(BaseTest, self).setUp()
        self.reset_backend()

        defaults = init_defaults('DroopeScan', 'general')
        defaults['general']['pwd'] = os.getcwd()
        self.app = DroopeScan(argv=[],
            plugin_config_dir=dscan.PWD + "./plugins.d",
            plugin_dir=dscan.PWD + "./plugins",
            config_defaults=defaults)

        handler.register(Scan)
        self.app.testing = True
        self.app.setup()
        responses.add(responses.HEAD, self.base_url, status=200)
예제 #3
0
class BaseTest(test.CementTestCase):
    app_class = DroopeScan
    scanner = None

    base_url = BASE_URL
    base_url_https = BASE_URL_HTTPS
    valid_file = VALID_FILE
    valid_file_ip = VALID_FILE_IP
    empty_file = EMPTY_FILE

    param_base = ["--url", base_url, '-n', '10']
    param_plugins = param_base + ["-e", 'p']
    param_interesting = param_base + ["-e", 'i']
    param_themes = param_base + ["-e", 't']
    param_version = param_base + ["-e", 'v']
    param_all = param_base + ["-e", 'a']

    versions_xsd = 'dscan/common/versions.xsd'
    xml_file = 'dscan/tests/resources/versions.xml'

    test_opts = {
        'output': 'standard',
        'debug_requests': False,
        'error_log': '-',
        'threads': 1,
        'threads_enumerate': None,
        'threads_identify': None,
        'threads_scan': None,
        'verb': 'head',
        'timeout': 300,
        'plugins_base_url': None,
        'themes_base_url': None,
        'number': 10,
        'debug': False,
        'enumerate': 'a',
        'headers': {}
    }

    host_header = {'Host': 'example.com'}

    def setUp(self):
        super(BaseTest, self).setUp()
        self.reset_backend()

        defaults = init_defaults('DroopeScan', 'general')
        defaults['general']['pwd'] = os.getcwd()
        self.app = DroopeScan(argv=[],
            plugin_config_dir=dscan.PWD + "./plugins.d",
            plugin_dir=dscan.PWD + "./plugins",
            config_defaults=defaults)

        handler.register(Scan)
        self.app.testing = True
        self.app.setup()
        responses.add(responses.HEAD, self.base_url, status=200)

    def _init_scanner(self):
        self.scanner = Drupal()
        self.scanner._general_init(self.test_opts)

    def tearDown(self):
        self.app.close()

    def mock_controller(self, plugin_label, method, return_value = None,
            side_effect = None, mock = None):
        """
        Mocks controller by label. Can only be used to test controllers
        that get instantiated automatically by cement.
        @param plugin_label: e.g. 'drupal'
        @param method: e.g. 'enumerate_plugins'
        @param return_value: what to return. Default is None, unless the
            method starts with enumerate_*, in which case the result is a
            tuple as expected by BasePlugin.
        @param mock: the MagicMock to place. If None, a blank MagicMock is
            created.
        @param side_effect: if set to an exception, it will raise an
            exception.
        """
        if mock:
            m = mock
        else:
            m = MagicMock()

        if return_value != None:
            m.return_value = return_value
        else:
            if method.startswith("enumerate_"):
                m.return_value = ({"a":[]}, True)

        if side_effect:
            m.side_effect = side_effect

        setattr(self.controller_get(plugin_label), method, m)
        return m

    def controller_get(self, plugin_label):
        return backend.__handlers__['controller'][plugin_label]

    def add_argv(self, argv):
        """
            Concatenates list with self.app.argv.
        """
        self.app._meta.argv += argv

    def clear_argv(self):
        self.app._meta.argv = []

    def assert_called_contains(self, mocked_method, kwarg_name, kwarg_value):
        """
        Assert kwarg_name: equals kwarg name in call to mocked_method.
        @param mocked_method: mock to check the call to.
        @param kwarg_name: name of the param. E.g. 'url'
        @param kwarg_value: expected value. E.g. 'https://www.drupal.org/'
        """
        args, kwargs = mocked_method.call_args
        assert kwargs[kwarg_name] == kwarg_value, "Parameter is not as expected."

    def assert_called_contains_all(self, mocked_method, kwarg_name, kwarg_value):
        call_list = mocked_method.call_args_list
        if len(mocked_method.call_args_list) == 0:
            assert False, "No calls to mocked method"

        for args, kwargs in call_list:
            assert kwargs[kwarg_name] == kwarg_value

    def assert_args_contains(self, mocked_method, position, expected_value):
        """
        Assert that the call contains this argument in the args at position position.
        """
        args, kwargs = mocked_method.call_args
        assert args[position] == expected_value

    def respond_several(self, base_url, data_obj, verb=responses.HEAD, headers=[]):
        for status_code in data_obj:
            for item in data_obj[status_code]:
                url = base_url % item
                responses.add(verb, url,
                        body=str(status_code), status=status_code,
                        adding_headers=headers)

    def mock_all_enumerate(self, plugin_name):
        all = []
        all.append(self.mock_controller(plugin_name, 'enumerate_plugins'))
        all.append(self.mock_controller(plugin_name, 'enumerate_themes'))
        all.append(self.mock_controller(plugin_name, 'enumerate_interesting'))
        all.append(self.mock_controller(plugin_name, 'enumerate_version'))

        for a in all:
            all[a].return_value = ([], True)

        return all

    def mock_all_url_file(self, url_file):
        with open(url_file) as f:
            for url in f:
                url_tpl = url.strip('\n') + '%s'

                self.respond_several(url_tpl, {
                    403: [Drupal.forbidden_url],
                    200: ['', 'misc/drupal.js'],
                    404: [self.scanner.not_found_url]
                })

    def mock_xml(self, xml_file, version_to_mock):
        '''
        Generates all mock data, and returns a MagicMock which can be used
        to replace self.scanner.enumerate_file_hash.

        self.scanner.enumerate_file_hash = self.mock_xml(self.xml_file, "7.27")

        @param xml_file: a file, which contains the XML to mock.
        @param version_to_mock: the version which we will pretend to be.
        @return: a function which can be used to mock
            BasePlugin.enumerate_file_hash
        '''
        with open(xml_file) as f:
            doc = etree.fromstring(f.read())
            files_xml = doc.xpath('//cms/files/file')

            files = {}
            for file in files_xml:
                url = file.get('url')
                versions = file.xpath('version')
                for file_version in versions:
                    version_number = file_version.get('nb')
                    md5 = file_version.get('md5')

                    if version_number == version_to_mock:
                        files[url] = md5

                if not url in files:
                    files[url] = '5d41402abc4b2a76b9719d911017c592'

            ch_xml_all = doc.findall('./files/changelog')
            if len(ch_xml_all) > 0:
                for ch_xml in ch_xml_all:
                    ch_url = ch_xml.get('url')
                    ch_versions = ch_xml.findall('./version')
                    found = False
                    for ch_version in ch_versions:
                        ch_nb = ch_version.get('nb')
                        if ch_nb == version_to_mock:
                            files[ch_url] = ch_version.get('md5')
                            found = True

        mock_hash = MockHash()
        mock_hash.files = files
        mock = MagicMock(side_effect=mock_hash.mock_func)

        return mock

    def get_dispatched_controller(self, app):
        """
            This might be considered a hack. I should eventually get in touch
            with the cement devs and ask for a better alternative :P.
        """
        return app.controller._dispatch_command['controller']\
                ._dispatch_command['controller']
예제 #4
0
class BaseTest(test.CementTestCase):
    app_class = DroopeScan
    scanner = None

    base_url = BASE_URL
    base_url_https = BASE_URL_HTTPS
    valid_file = VALID_FILE
    valid_file_ip = VALID_FILE_IP
    empty_file = EMPTY_FILE

    param_base = ["--url", base_url, '-n', '10']
    param_plugins = param_base + ["-e", 'p']
    param_interesting = param_base + ["-e", 'i']
    param_themes = param_base + ["-e", 't']
    param_version = param_base + ["-e", 'v']
    param_all = param_base + ["-e", 'a']

    versions_xsd = 'dscan/common/versions.xsd'
    xml_file = 'dscan/tests/resources/versions.xml'

    test_opts = {
        'output':
        'standard',
        'debug_requests':
        False,
        'error_log':
        '-',
        'threads':
        1,
        'threads_enumerate':
        None,
        'threads_identify':
        None,
        'threads_scan':
        None,
        'verb':
        'head',
        'timeout':
        300,
        'plugins_base_url':
        None,
        'themes_base_url':
        None,
        'number':
        10,
        'debug':
        False,
        'enumerate':
        'a',
        'headers': {},
        'hide_progressbar':
        False,
        'user_agent':
        'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0'
    }

    host_header = {'Host': 'example.com'}

    def setUp(self):
        super(BaseTest, self).setUp()
        self.reset_backend()

        defaults = init_defaults('DroopeScan', 'general')
        defaults['general']['pwd'] = os.getcwd()
        self.app = DroopeScan(argv=[],
                              plugin_config_dir=dscan.PWD + "./plugins.d",
                              plugin_dir=dscan.PWD + "./plugins",
                              config_defaults=defaults)

        handler.register(Scan)
        self.app.testing = True
        self.app.setup()
        responses.add(responses.HEAD, self.base_url, status=200)

    def _init_scanner(self):
        self.scanner = Drupal()
        self.scanner._general_init(self.test_opts)
        self.scanner._determine_fake_200_module = self._fake_200_check
        m = self.mock_controller('drupal',
                                 '_determine_fake_200_module',
                                 return_value=False)

    def _fake_200_check(self, param1, param2, param3):
        return False

    def tearDown(self):
        self.app.close()

    def mock_controller(self,
                        plugin_label,
                        method,
                        return_value=None,
                        side_effect=None,
                        mock=None):
        """
        Mocks controller by label. Can only be used to test controllers
        that get instantiated automatically by cement.
        @param plugin_label: e.g. 'drupal'
        @param method: e.g. 'enumerate_plugins'
        @param return_value: what to return. Default is None, unless the
            method starts with enumerate_*, in which case the result is a
            tuple as expected by BasePlugin.
        @param mock: the MagicMock to place. If None, a blank MagicMock is
            created.
        @param side_effect: if set to an exception, it will raise an
            exception.
        """
        if mock:
            m = mock
        else:
            m = MagicMock()

        if return_value != None:
            m.return_value = return_value
        else:
            if method.startswith("enumerate_"):
                m.return_value = ({"a": []}, True)

        if side_effect:
            m.side_effect = side_effect

        setattr(self.controller_get(plugin_label), method, m)
        return m

    def controller_get(self, plugin_label):
        return backend.__handlers__['controller'][plugin_label]

    def add_argv(self, argv):
        """
            Concatenates list with self.app.argv.
        """
        self.app._meta.argv += argv

    def clear_argv(self):
        self.app._meta.argv = []

    def assert_called_contains(self, mocked_method, kwarg_name, kwarg_value):
        """
        Assert kwarg_name: equals kwarg name in call to mocked_method.
        @param mocked_method: mock to check the call to.
        @param kwarg_name: name of the param. E.g. 'url'
        @param kwarg_value: expected value. E.g. 'https://www.drupal.org/'
        """
        args, kwargs = mocked_method.call_args
        assert kwargs[
            kwarg_name] == kwarg_value, "Parameter is not as expected."

    def assert_called_contains_all(self, mocked_method, kwarg_name,
                                   kwarg_value):
        call_list = mocked_method.call_args_list
        if len(mocked_method.call_args_list) == 0:
            assert False, "No calls to mocked method"

        for args, kwargs in call_list:
            assert kwargs[kwarg_name] == kwarg_value

    def assert_args_contains(self, mocked_method, position, expected_value):
        """
        Assert that the call contains this argument in the args at position position.
        """
        args, kwargs = mocked_method.call_args
        assert args[position] == expected_value

    def respond_several(self,
                        base_url,
                        data_obj,
                        verb=responses.HEAD,
                        headers=[]):
        for status_code in data_obj:
            for item in data_obj[status_code]:
                url = base_url % item
                responses.add(verb,
                              url,
                              body=str(status_code),
                              status=status_code,
                              adding_headers=headers)

    def mock_all_enumerate(self, plugin_name):
        all = []
        all.append(self.mock_controller(plugin_name, 'enumerate_plugins'))
        all.append(self.mock_controller(plugin_name, 'enumerate_themes'))
        all.append(self.mock_controller(plugin_name, 'enumerate_interesting'))

        for a in all:
            all[a].return_value = ([], True)

        mock_version = self.mock_controller(plugin_name, 'enumerate_version')
        mock_version.return_value = (['7.32'], False)
        all.append(mock_version)

        return all

    def mock_all_url_file(self, url_file):
        with open(url_file) as f:
            for url in f:
                url_tpl = url.strip('\n') + '%s'

                self.respond_several(
                    url_tpl, {
                        403: [Drupal.forbidden_url],
                        200: ['', 'misc/drupal.js'],
                        404: [
                            self.scanner.not_found_url,
                            '/sites/all/modules/a12abb4d5bead1220174a6b39a2546db/',
                        ]
                    })

    def mock_xml(self, xml_file, version_to_mock):
        '''
        Generates all mock data, and returns a MagicMock which can be used
        to replace self.scanner.enumerate_file_hash.

        self.scanner.enumerate_file_hash = self.mock_xml(self.xml_file, "7.27")

        @param xml_file: a file, which contains the XML to mock.
        @param version_to_mock: the version which we will pretend to be.
        @return: a function which can be used to mock
            BasePlugin.enumerate_file_hash
        '''
        with open(xml_file) as f:
            doc = etree.fromstring(f.read())
            files_xml = doc.xpath('//cms/files/file')

            files = {}
            for file in files_xml:
                url = file.get('url')
                versions = file.xpath('version')
                for file_version in versions:
                    version_number = file_version.get('nb')
                    md5 = file_version.get('md5')

                    if version_number == version_to_mock:
                        files[url] = md5

                if not url in files:
                    files[url] = '5d41402abc4b2a76b9719d911017c592'

            ch_xml_all = doc.findall('./files/changelog')
            if len(ch_xml_all) > 0:
                for ch_xml in ch_xml_all:
                    ch_url = ch_xml.get('url')
                    ch_versions = ch_xml.findall('./version')
                    found = False
                    for ch_version in ch_versions:
                        ch_nb = ch_version.get('nb')
                        if ch_nb == version_to_mock:
                            files[ch_url] = ch_version.get('md5')
                            found = True

        mock_hash = MockHash()
        mock_hash.files = files
        mock = MagicMock(side_effect=mock_hash.mock_func)

        return mock

    def get_dispatched_controller(self, app):
        """
        This might be considered a hack. I should eventually get in touch
        with the cement devs and ask for a better alternative :P.
        """
        return app.controller._dispatch_command['controller']\
                ._dispatch_command['controller']