コード例 #1
0
 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)
コード例 #2
0
    def test_fix_dereference_bug(self):
        '''
            test for dereference that made the app fail even though
            all tests were passing.
        '''

        plugins_base_url = 'plugins_base_url'
        themes_base_url = 'themes_base_url'
        opts_p = {
            'url': self.base_url,
            'plugins_base_url': plugins_base_url,
            'themes_base_url': themes_base_url,
            'scanning_method': 'a',
            'number': 'a',
            'threads': 'a',
            'threads_enumerate': None,
            'threads_identify': None,
            'threads_scan': None,
            'verb': 'a',
            'enumerate': 'p',
            'timeout': 15,
            'headers': {}
        }
        opts_t = dict(opts_p)
        opts_t['enumerate'] = 't'

        drupal = Drupal()
        kwargs_p = drupal._functionality(opts_p)['plugins']['kwargs']
        kwargs_t = drupal._functionality(opts_t)['themes']['kwargs']

        # these should not be equal
        assert not kwargs_p == kwargs_t
コード例 #3
0
ファイル: base_tests.py プロジェクト: 3-bits/droopescan
    def test_fix_dereference_bug(self):
        '''
            test for dereference that made the app fail even though
            all tests were passing.
        '''

        plugins_base_url = 'plugins_base_url'
        themes_base_url = 'themes_base_url'
        opts_p = {
            'url': self.base_url,
            'plugins_base_url': plugins_base_url,
            'themes_base_url': themes_base_url,
            'scanning_method': 'a',
            'number': 'a',
            'threads': 'a',
            'threads_enumerate': None,
            'threads_identify': None,
            'threads_scan': None,
            'verb': 'a',
            'enumerate': 'p',
            'timeout': 15,
            'headers': {}
        }
        opts_t = dict(opts_p)
        opts_t['enumerate'] = 't'

        drupal = Drupal()
        kwargs_p = drupal._functionality(opts_p)['plugins']['kwargs']
        kwargs_t = drupal._functionality(opts_t)['themes']['kwargs']

        # these should not be equal
        assert not kwargs_p == kwargs_t
コード例 #4
0
ファイル: base_http_tests.py プロジェクト: droope/droopescan
    def test_module_fake_200(self, warn, mock):
        """
        The workaround implemented to find some modules that return 200 when
        they are present causes other sites to report many false positives. This
        is due to the fact that all modules respond with 200 for unknown
        reasons. In these cases 200 should be ignored as they are fake.
        """

        scanner = Drupal()
        scanner._general_init(self.test_opts)

        r_404 = ['supermodule/']
        r_403 = ['yep/', 'thisisthere/', 'thisisalsothere/']
        r_500 = ['iamtherebuti500/']
        r_200 = ['iamtherebuti200/', scanner.not_found_module + "/"]
        self.respond_several(self.base_url + 'sites/all/modules/%s', {404:
            r_404, 403: r_403, 500: r_500, 200: r_200})

        scanner.plugins_base_url = '%ssites/all/modules/%s/'
        self.mock_controller('drupal', 'enumerate_interesting')

        result, empty = scanner.enumerate_plugins(self.base_url,
                scanner.plugins_base_url, ScanningMethod.forbidden)

        assert len(result) == 4
        found_500 = False
        found_200 = False
        for res in result:
            if res['name'] == 'iamtherebuti500':
                found_500 = True

            if res['name'] == 'iamtherebuti200':
                found_200 = True

        assert found_500
        assert not found_200 # 200 should not count as false positive
        assert warn.called
コード例 #5
0
    def test_plugins_update_check(self):
        drupal = Drupal()
        drupal.update_plugins = up = Mock(spec=self.scanner.update_plugins,
                                          return_value=([], []))

        today = datetime.today()
        yesterday = datetime.today() - timedelta(days=1)
        too_long_ago = today - timedelta(days=400)

        o = mock_open()
        with patch('dscan.plugins.update.open', o, create=True):
            with patch('dscan.common.update_api.file_mtime',
                       return_value=yesterday,
                       autospec=True):
                self.updater.update_plugins(
                    self.controller_get('drupal')(), 'Drupal')
                assert not up.called

            with patch('dscan.common.update_api.file_mtime',
                       return_value=too_long_ago):
                self.updater.update_plugins(drupal, 'Drupal')
                assert up.called
コード例 #6
0
    def test_module_fake_200(self, warn, mock):
        """
        The workaround implemented to find some modules that return 200 when
        they are present causes other sites to report many false positives. This
        is due to the fact that all modules respond with 200 for unknown
        reasons. In these cases 200 should be ignored as they are fake.
        """

        scanner = Drupal()
        scanner._general_init(self.test_opts)

        r_404 = ['supermodule/']
        r_403 = ['yep/', 'thisisthere/', 'thisisalsothere/']
        r_500 = ['iamtherebuti500/']
        r_200 = ['iamtherebuti200/', scanner.not_found_module + "/"]
        self.respond_several(self.base_url + 'sites/all/modules/%s', {
            404: r_404,
            403: r_403,
            500: r_500,
            200: r_200
        })

        scanner.plugins_base_url = '%ssites/all/modules/%s/'
        self.mock_controller('drupal', 'enumerate_interesting')

        result, empty = scanner.enumerate_plugins(self.base_url,
                                                  scanner.plugins_base_url,
                                                  ScanningMethod.forbidden)

        assert len(result) == 4
        found_500 = False
        found_200 = False
        for res in result:
            if res['name'] == 'iamtherebuti500':
                found_500 = True

            if res['name'] == 'iamtherebuti200':
                found_200 = True

        assert found_500
        assert not found_200  # 200 should not count as false positive
        assert warn.called
コード例 #7
0
ファイル: __init__.py プロジェクト: vielsoft/droopescan
 def _init_scanner(self):
     self.scanner = Drupal()
     self.scanner._general_init(self.test_opts)
コード例 #8
0
ファイル: __init__.py プロジェクト: vielsoft/droopescan
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']
コード例 #9
0
    def test_kali_old_requests_bug(self, warn):
        drupal = Drupal()
        with patch('requests.adapters', spec_set=["force_attr_error"]):
            drupal._general_init(self.test_opts)

            assert warn.called
コード例 #10
0
ファイル: __init__.py プロジェクト: droope/droopescan
 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)
コード例 #11
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']
コード例 #12
0
ファイル: __init__.py プロジェクト: zenzue/droopescan
 def _init_scanner(self):
     self.scanner = Drupal()
     self.scanner._general_init(self.test_opts)
コード例 #13
0
ファイル: base_tests.py プロジェクト: 3-bits/droopescan
    def test_kali_old_requests_bug(self, warn):
        drupal = Drupal()
        with patch('requests.adapters', spec_set=["force_attr_error"]):
            drupal._general_init(self.test_opts)

            assert warn.called