Example #1
0
class ScanContextTest(AsyncTestCase):
    def setUp(self):
        super(ScanContextTest, self).setUp()
        self.scan = MagicMock()
        self.aucote = MagicMock()
        self.context = ScanContext(aucote=self.aucote, scanner=self.scan)

    def test_add_task(self):
        task = MagicMock()
        self.context.add_task(task)

        self.assertIn(task, self.context.tasks)
        self.aucote.add_async_task.assert_called_once_with(
            task, manager=TaskManagerType.REGULAR)

    def test_non_end_scan(self):
        self.context.tasks = [
            MagicMock(has_finished=MagicMock(return_value=False))
        ]

        result = self.context.is_scan_end()

        self.assertFalse(result)

    def test_scan_end(self):
        self.context.tasks = [
            MagicMock(has_finished=MagicMock(return_value=True))
        ]
        self.context.end = 0

        result = self.context.is_scan_end()

        self.assertTrue(result)
Example #2
0
 def setUp(self):
     super(AucoteHttpHeadersTaskTest, self).setUp()
     HTTPClient._instance = MagicMock()
     self.port = Port(node=MagicMock(),
                      transport_protocol=None,
                      number=None)
     self.port.scan = Scan()
     self.aucote = MagicMock()
     self.exploit = MagicMock()
     self.exploit.name = "test"
     self.config = {
         'headers': {
             'test': HeaderDefinition(pattern='test_nie', obligatory=True)
         }
     }
     self.custom_headers = {
         'Accept-Encoding': 'gzip, deflate',
         'User-Agent': 'test'
     }
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.task = AucoteHttpHeadersTask(port=self.port,
                                       context=self.context,
                                       exploits=[self.exploit],
                                       config=self.config)
Example #3
0
    def setUp(self):
        super(TaskMapperTest, self).setUp()
        self.executor = Mock()
        self.exploits = OrderedDict({
            'test': [
                Exploit(exploit_id=1, name='test_1'),
                Exploit(exploit_id=2, name='test_2')
            ]
        })

        self.exploits.update(test2=[Exploit(exploit_id=3)])
        self.executor.exploits.find_all_matching.return_value = self.exploits
        self.context = ScanContext(aucote=self.executor,
                                   scanner=MagicMock(scan=Scan()))

        self.task_mapper = TaskMapper(context=self.context)

        self.cfg = {
            'portdetection': {
                '_internal': {
                    'categories': ['other', 'brute']
                }
            },
            'tools': {
                'test': {
                    'enable': True
                },
                'test2': {
                    'enable': True
                }
            }
        }
Example #4
0
    def setUp(self):
        super(NmapToolTest, self).setUp()
        self.exploit = Exploit(exploit_id=1,
                               name='test_name',
                               risk_level=RiskLevel.NONE)

        self.exploit2 = Exploit(exploit_id=2,
                                name='test_name',
                                risk_level=RiskLevel.HIGH)

        self.exploit_conf_args = Exploit(exploit_id=3)
        self.exploit_conf_args.name = 'test_name2'
        self.exploit_conf_args.risk_level = RiskLevel.HIGH

        self.config = {
            'scripts': {
                'test_name': {
                    'args': 'test_args'
                },
                'test_name2': {
                    'args': MagicMock()
                }
            }
        }

        self.cfg = {
            'tools': {
                'nmap': {
                    'disable_scripts': [],
                },
                'common': {
                    'rate': 1337,
                    'http': {
                        'useragent': 'test_useragent'
                    }
                }
            },
            'config_filename': ''
        }

        self.exploits = [self.exploit, self.exploit2]
        self.port = Port(number=13,
                         transport_protocol=TransportProtocol.TCP,
                         node=Node(node_id=1,
                                   ip=ipaddress.ip_address('127.0.0.1')))

        self.port.scan = Scan(start=14, end=13)
        self.port.protocol = 'test_service'

        self.aucote = MagicMock(storage=Storage(":memory:"))
        self.context = ScanContext(aucote=self.aucote,
                                   scanner=MagicMock(scan=Scan()))
        self.nmap_tool = NmapTool(context=self.context,
                                  exploits=self.exploits,
                                  port=self.port,
                                  config=self.config)
Example #5
0
 def setUp(self):
     exploit = Exploit(exploit_id=3)
     port = Port(node=Node(node_id=2, ip=ipaddress.ip_address('127.0.0.1')),
                 transport_protocol=TransportProtocol.TCP,
                 number=16)
     self.aucote = MagicMock()
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.task = SSLScriptTask(port=port,
                               exploits=[exploit],
                               context=self.context)
Example #6
0
 def setUp(self):
     self.aucote = MagicMock()
     self.port = Port(node=MagicMock(),
                      transport_protocol=None,
                      number=MagicMock())
     self.exploit = MagicMock()
     self.scan = Scan()
     self.context = ScanContext(aucote=self.aucote, scanner=None)
     self.task = PortTask(context=self.context,
                          port=self.port,
                          exploits=[self.exploit])
Example #7
0
    def setUp(self):
        """
        Set up init variables
        """
        super().setUp()
        self.executor = MagicMock()
        self.executor.kudu_queue = MagicMock()
        self.executor.exploits = MagicMock()
        self.context = ScanContext(aucote=self.executor,
                                   scanner=MagicMock(scan=Scan()))

        self.task = Task(context=self.context)
Example #8
0
    def setUp(self):
        """
        Prepare some internal variables:
            exploit, port, exploits, script, vulnerability, scan_task

        """
        super(NmapPortScanTaskTest, self).setUp()
        self.aucote = MagicMock()

        self.exploit = Exploit(exploit_id=1, app='nmap', name='test')
        self.exploit_vuln_non_exist = Exploit(exploit_id=2,
                                              app='nmap',
                                              name='test2')
        self.exploits = Exploits()
        self.exploits.add(self.exploit)

        self.node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=None)
        self.node_ipv6 = Node(ip=ipaddress.ip_address('::1'), node_id=None)

        self.port = Port(number=22,
                         node=self.node,
                         transport_protocol=TransportProtocol.TCP)
        self.port.service_name = 'ssh'
        self.port.scan = Scan()

        self.port_ipv6 = Port(number=22,
                              node=self.node_ipv6,
                              transport_protocol=TransportProtocol.TCP)

        self.script = NmapScript(port=self.port,
                                 parser=NmapParser(),
                                 exploit=self.exploit,
                                 name='test',
                                 args='test_args')
        self.script.get_result = MagicMock(return_value='test')
        self.script2 = NmapScript(port=self.port,
                                  parser=NmapInfoParser(),
                                  exploit=self.exploit_vuln_non_exist,
                                  name='test2')
        self.context = ScanContext(aucote=self.aucote,
                                   scanner=MagicMock(scan=Scan()))
        self.scan_task = NmapPortScanTask(
            context=self.context,
            port=self.port,
            script_classes=[self.script, self.script2],
            rate=1337)
        self.scan_task.store_scan_end = MagicMock()

        future = Future()
        future.set_result(ElementTree.fromstring(self.XML))
        self.scan_task.command.async_call = MagicMock(return_value=future)

        self.cfg = {'tools': {'nmap': {'scripts_dir': '', 'timeout': 0}}}
Example #9
0
 def setUp(self):
     super(AucoteHttpHeadersToolTest, self).setUp()
     self.aucote = MagicMock()
     self.exploits = MagicMock()
     self.port = MagicMock()
     self.config = MagicMock()
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.tool = AucoteHttpHeadersTool(context=self.context,
                                       exploits=self.exploits,
                                       port=self.port,
                                       config=self.config)
Example #10
0
 def setUp(self):
     super(WhatWebTaskTest, self).setUp()
     self.node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=1)
     self.port = Port(node=self.node,
                      number=19,
                      transport_protocol=TransportProtocol.UDP)
     self.port.protocol = 'http'
     self.aucote = MagicMock()
     self.exploit = Exploit(app='whatweb', name='whatweb', exploit_id=1)
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.task = WhatWebTask(port=self.port,
                             context=self.context,
                             exploits=[self.exploit])
Example #11
0
    def setUp(self):
        super().setUp()
        self.aucote = MagicMock()
        self.aucote.storage.filename = ":memory:"
        self.exploits = MagicMock()
        self.config = MagicMock()
        self.port = MagicMock()
        self.scan = Scan()
        self.context = ScanContext(aucote=self.aucote, scanner=None)

        self.tool = Tool(context=self.context,
                         exploits=self.exploits,
                         port=self.port,
                         config=self.config)
Example #12
0
 def setUp(self):
     super(WhatWebToolTest, self).setUp()
     self.aucote = MagicMock()
     self.exploit = Exploit(exploit_id=1)
     self.node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=1)
     self.port = Port(node=self.node,
                      transport_protocol=TransportProtocol.UDP,
                      number=87)
     self.config = MagicMock()
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.tool = WhatWebTool(context=self.context,
                             exploits=[self.exploit],
                             port=self.port,
                             config=self.config)
Example #13
0
 def setUp(self):
     super(CVESearchToolTest, self).setUp()
     self.aucote = MagicMock()
     self.exploits = MagicMock()
     self.port = MagicMock()
     self.config = MagicMock()
     self.node = MagicMock()
     self.scan = Scan()
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.tool = CVESearchTool(context=self.context,
                               exploits=self.exploits,
                               port=self.port,
                               node=self.node,
                               config=self.config)
Example #14
0
 def setUp(self, cfg):
     super(ExecutorTest, self).setUp()
     cfg._cfg = {
         'portdetection': {
             '_internal': {
                 'port_period': None,
                 'broadcast': True
             }
         }
     }
     self.cfg = cfg
     self.aucote = MagicMock()
     self.aucote.storage = MagicMock()
     self.context = ScanContext(aucote=self.aucote, scanner=MagicMock())
     self.context.scanner.scan = Scan()
     self.executor = Executor(context=self.context)
Example #15
0
    def setUp(self):
        super(HydraToolTest, self).setUp()
        self.exploit = Exploit(exploit_id=1,
                               name='hydra',
                               app='hydra',
                               risk_level=RiskLevel.NONE)
        self.exploit2 = Exploit(exploit_id=2,
                                name='hydra',
                                app='hydra',
                                risk_level=RiskLevel.HIGH)

        self.config = {
            'services': ['ssh', 'vnc'],
            'mapper': {
                'test': 'ssh'
            },
            'without-login': '******'
        }

        self.exploits = [self.exploit, self.exploit2]

        self.node = Node(node_id=1, ip=ipaddress.ip_address('127.0.0.1'))

        self.port = Port(number=12,
                         transport_protocol=TransportProtocol.TCP,
                         node=self.node)
        self.port.protocol = 'test'
        self.port.scan = Scan(start=14)

        self.port_no_login = Port(number=12,
                                  transport_protocol=TransportProtocol.TCP,
                                  node=self.node)
        self.port_no_login.protocol = 'vnc'
        self.port_no_login.scan = Scan(start=14)

        self.aucote = MagicMock()
        self.context = ScanContext(aucote=self.aucote,
                                   scanner=MagicMock(scan=Scan()))
        self.hydra_tool = HydraTool(context=self.context,
                                    exploits=self.exploits,
                                    port=self.port,
                                    config=self.config)
        self.hydra_tool_without_login = HydraTool(context=self.context,
                                                  exploits=self.exploits,
                                                  port=self.port_no_login,
                                                  config=self.config)
Example #16
0
    def setUp(self):
        super(SkipfishToolTest, self).setUp()
        self.exploit = Exploit(exploit_id=1)
        self.exploit.name = 'skipfish'
        self.exploit.risk_level = RiskLevel.NONE

        self.config = {}

        self.exploits = [self.exploit]
        self.port = Port(node=Node(node_id=1, ip=ipaddress.ip_address('127.0.0.1')), number=3,
                         transport_protocol=TransportProtocol.TCP)
        self.port.scan = Scan(start=13, end=45)

        self.aucote = MagicMock()
        self.context = ScanContext(aucote=self.aucote, scanner=MagicMock(scan=Scan()))
        self.skipfish_tool = SkipfishTool(context=self.context, exploits=self.exploits, port=self.port,
                                          config=self.config)
Example #17
0
 def setUp(self):
     super(SietTaskTest, self).setUp()
     self.context = ScanContext(aucote=MagicMock(),
                                scanner=TCPScanner(MagicMock(), MagicMock(),
                                                   MagicMock(),
                                                   MagicMock()))
     self.node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=14)
     self.scan = Scan()
     self.port = Port(node=self.node,
                      number=46,
                      transport_protocol=TransportProtocol.TCP,
                      scan=self.scan)
     self.exploit = Exploit(exploit_id=15,
                            app='aucote-scripts',
                            name='siet')
     self.task = SietTask(context=self.context,
                          port=self.port,
                          exploits=[self.exploit])
     self.cfg = {'portdetection': {'expiration_period': '7d'}}
Example #18
0
    def setUp(self):
        super(HydraScriptTaskTest, self).setUp()
        self.aucote = MagicMock()
        self.port = Port(node=Node(ip='127.0.0.1', node_id=None),
                         transport_protocol=TransportProtocol.TCP,
                         number=22)
        self.port.service_name = 'ssh'
        self.port.scan = Scan()
        self.exploit = Exploit(exploit_id=1)
        self.scan = Scan()
        self.context = ScanContext(aucote=self.aucote,
                                   scanner=MagicMock(scan=Scan()))

        self.hydra_script_task = HydraScriptTask(
            exploits=[self.exploit],
            context=self.context,
            port=self.port,
            service=self.port.service_name)
        self.hydra_script_task.store_scan_end = MagicMock()
        self.hydra_script_task.aucote.exploits.find.return_value = self.exploit
Example #19
0
 def setUp(self):
     super(CommandTaskTest, self).setUp()
     self.aucote = MagicMock()
     self.port = Port(node=MagicMock(),
                      transport_protocol=None,
                      number=None)
     self.port.scan = Scan()
     self.command = MagicMock(NAME='test_name')
     future = Future()
     self.future_return = MagicMock()
     future.set_result(self.future_return)
     self.command.async_call = MagicMock(return_value=future)
     self.exploit = MagicMock()
     self.context = ScanContext(aucote=self.aucote,
                                scanner=MagicMock(scan=Scan()))
     self.task = CommandTask(context=self.context,
                             port=self.port,
                             command=self.command,
                             exploits=[self.exploit])
     self.cfg = {'tools': {'test_name': {'timeout': 0}}}
Example #20
0
    def setUp(self):
        super(NmapPortInfoTaskTest, self).setUp()
        self.aucote = MagicMock()
        self.aucote.task_mapper.assign_tasks = MagicMock(return_value=Future())
        self.aucote.task_mapper.assign_tasks.return_value.set_result(
            MagicMock())
        self.exploit = Exploit(exploit_id=4)

        self.node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=1)
        self.node.os = Service(name='os test name',
                               version='os test version',
                               cpe='cpe:2.3:o:vendor:product:-:*:*:*:*:*:*:*')
        self.node_ipv6 = Node(ip=ipaddress.ip_address('::1'), node_id=None)

        self.port = Port(number=22,
                         transport_protocol=TransportProtocol.TCP,
                         node=self.node)
        self.port.scan = Scan()
        self.port_ipv6 = Port(number=22,
                              node=self.node_ipv6,
                              transport_protocol=TransportProtocol.TCP)
        self.scanner = Scanner(aucote=self.aucote)
        self.scanner.NAME = 'tools'
        self.context = ScanContext(aucote=self.aucote, scanner=self.scanner)

        self.port_info = NmapPortInfoTask(context=self.context, port=self.port)

        self.cfg = {
            'portdetection': {
                'tools': {
                    'scan_rate': 1337
                },
                'expiration_period': '7d'
            },
            'tools': {
                'nmap': {
                    'scripts_dir': 'test'
                }
            },
        }
Example #21
0
    def setUp(self):
        self.serializer = Serializer()
        self.vuln = Vulnerability(subid=15)

        node = Node(ip=ipaddress.ip_address('127.0.0.1'), node_id=1)
        node.os = MagicMock()
        node.os.name_with_version = 'test_name_and_version'

        self.context = ScanContext(aucote=None, scanner=TCPScanner(MagicMock(), MagicMock(), MagicMock(), MagicMock()))

        self.vuln.context = self.context

        self.port = Port(node=node, number=22, transport_protocol=TransportProtocol.TCP)
        self.port.protocol = 'ssh'

        self.port.scan = Scan()
        self.port.scan.start = datetime.datetime(2016, 8, 16, 15, 23, 10, 183095, tzinfo=utc).timestamp()

        self.vuln.port = self.port
        self.vuln.output = 'Test'
        self.vuln.scan = Scan(start=datetime.datetime(2016, 8, 16, 15, 23, 10, 183095, tzinfo=utc).timestamp(),
                              scanner='tcp')

        self.exploit = Exploit(exploit_id=1)
        self.exploit.app = 'test_app'
        self.exploit.name = 'test_name'
        self.exploit.title = 'test_title'
        self.exploit.description = 'test_description'
        self.exploit.risk_level = RiskLevel.from_name('High')
        self.exploit.cve = 'CVE-2018-0001'
        self.exploit.cvss = 9.8
        self.exploit.metric = ExploitMetric.VNC_INFO
        self.exploit.category = ExploitCategory.VULN
        self.exploit.tags = {ExploitTag.HTTP, ExploitTag.SSL, ExploitTag.HTTPS}

        self.vuln.exploit = self.exploit
        self.vuln.time = datetime.datetime(2016, 8, 16, 15, 23, 10, 183095, tzinfo=utc).timestamp()
Example #22
0
    def setUp(self, cfg):
        super(CVESearchServiceTaskTest, self).setUp()
        cfg._cfg = {'tools': {'cve-search': {'api': 'localhost:200'}}}

        self.example_output = ''

        with open(
                path.join(path.dirname(path.abspath(__file__)),
                          'example_output.json'), 'rb') as f:
            self.example_output = f.read()

        self.node = Node(ip='127.0.0.1', node_id=None)

        self.port = Port(node=self.node,
                         transport_protocol=TransportProtocol.TCP,
                         number=22)
        self.port.service_name = 'ssh'
        self.port.scan = Scan()
        self.port.service = Service()
        self.app = Service()
        self.app_2 = Service()
        self.app.cpe = 'cpe:/a:microsoft:iexplorer:8.0.6001:beta'
        self.app_2.cpe = 'cpe:/a:microsoft:aexplorer:8.0.6001:beta'
        self.cpe_txt = 'cpe:/a:microsoft:internet_explorer:8.0.6001:beta'
        self.os_cpe_txt = 'cpe:/o:a:b:4'
        self.cpe_without_version = 'cpe:/o:cisco:ios'
        self.node.os.cpe = self.os_cpe_txt
        self.port.service.cpe = self.cpe_txt
        self.exploit = Exploit(exploit_id=1337,
                               name='cve-search',
                               app='cve-search')
        self.aucote = MagicMock()
        self.context = ScanContext(aucote=self.aucote,
                                   scanner=MagicMock(scan=Scan()))
        self.task = CVESearchServiceTask(context=self.context,
                                         port=self.port,
                                         exploits=[self.exploit])

        self.vuln_1 = Vulnerability(port=self.port,
                                    exploit=self.exploit,
                                    cve='CVE-2016-8612',
                                    cvss=3.3,
                                    output='test summary 1',
                                    context=self.context,
                                    subid=0)

        self.vuln_2 = Vulnerability(port=self.port,
                                    exploit=self.exploit,
                                    cve='CVE-2017-9798',
                                    cvss=5.0,
                                    output='test summary 2',
                                    context=self.context,
                                    subid=1)

        self.vuln_3 = Vulnerability(port=self.port,
                                    exploit=self.exploit,
                                    cve='CVE-2017-9788',
                                    cvss=6.4,
                                    output='test summary 3',
                                    context=self.context,
                                    subid=2)
Example #23
0
class ScanAsyncTask(object):
    """
    Parent class for all scanning tasks

    """
    LIVE_SCAN_CRON = '* * * * *'
    PROTOCOL = None
    NAME = None

    TOPDIS_MIN_TIME = 5
    TOPDIS_MAX_TIME = 30
    TOPDIS_RETRIES = 5

    def __init__(self, aucote):
        self._current_scan = []
        self._aucote = aucote
        self.context = None
        self.scan = Scan(protocol=self.PROTOCOL, scanner=self.NAME,
                         init=False)  # ToDo: move it inside
        self._shutdown_condition = Event()
        self.status = ScanStatus.IDLE
        self.run_now = False

    @property
    def aucote(self):
        return self._aucote

    def _init(self):
        if self.context is not None:
            raise Exception("Scan context already exists")
        self.context = ScanContext(aucote=self.aucote, scanner=self)

    async def __call__(self, resume=False):
        try:
            self._init()

            if not cfg['portdetection.{name}.scan_enabled'.format(
                    name=self.NAME)]:
                log.info("Scanner %s is disabled", self.NAME)
                return
            log.info("Starting %s scanner", self.NAME)

            if resume:
                self.scan.resume = True
            else:
                self.scan.resume = False

            result = await self.run(resume=resume)

            run_after = cfg['portdetection.{name}.run_after'.format(
                name=self.NAME)]
            for scan_name in run_after:

                scan_task = self.aucote.async_task_managers[
                    TaskManagerType.SCANNER].cron_task(scan_name)
                if scan_task is not None:
                    self.aucote.ioloop.add_callback(
                        partial(scan_task, skip_cron=True))

            return result
        finally:
            self.context.end = time.time()
            self.context = None
            self.expire_vulnerabilities()

    async def run(self, **kwargs):
        raise NotImplementedError()

    @property
    def shutdown_condition(self):
        """
        Event which is set when no scan in progress

        Returns:
            Event

        """
        return self._shutdown_condition

    async def _get_nodes_for_scanning(self,
                                      timestamp=None,
                                      filter_out_storage=True,
                                      scan=None):
        """
        Get nodes for scan since timestamp.
            - If timestamp is None, it is equal: current timestamp - node scan period
            - Restrict nodes to allowed networks

        Args:
            timestamp (float):

        Returns:
            list

        """
        if scan is not None:
            nodes = {
                'snmp': set(self.storage.get_non_finished_nodes(scan)),
                'hosts': set()
            }

            for node in nodes['snmp']:
                node.scan = self.scan
        else:
            nodes = {'snmp': await self.topdis.get_snmp_nodes()}
            nodes['hosts'] = await self.topdis.get_all_nodes() - nodes['snmp']

        if filter_out_storage:
            storage_nodes = set(
                self.storage.get_nodes(pasttime=self._scan_interval(),
                                       timestamp=timestamp,
                                       scan=self.scan))

            nodes['hosts'] = nodes['hosts'] - storage_nodes
            nodes['snmp'] = nodes['snmp'] - storage_nodes

        include_networks = self._get_networks_list()
        exclude_networks = self._get_excluded_networks_list()

        return_value = []

        if cfg['portdetection.{name}.scan_devices.snmp'.format(
                name=self.NAME)]:
            return_value.extend(node for node in list(nodes['snmp'])
                                if node.ip.exploded in include_networks
                                and node.ip.exploded not in exclude_networks)

        if cfg['portdetection.{name}.scan_devices.host'.format(
                name=self.NAME)]:
            return_value.extend(node for node in list(nodes['hosts'])
                                if node.ip.exploded in include_networks
                                and node.ip.exploded not in exclude_networks)

        return return_value

    def _get_networks_list(self):
        """
        Returns list of networks from configuration file

        Returns:
            IPSet: set of networks

        """
        try:
            return IPSet(cfg['portdetection.{name}.networks.include'.format(
                name=self.NAME)])
        except KeyError:
            log.error(
                "Please set portdetection.%s.networks.include in configuration file!",
                self.NAME)
            exit()

    def _get_excluded_networks_list(self):
        """
        List of excluded networks from configuration file

        Returns:
            IPSet: set of networks

        """
        try:
            return IPSet(cfg['portdetection.{name}.networks.exclude'.format(
                name=self.NAME)])
        except KeyError:
            return []

    @property
    def storage(self):
        """
        Handler to application storage

        Returns:
            Storage

        """
        return self.aucote.storage

    @property
    def current_scan(self):
        """
        List of currently scan nodes

        Returns:
            list

        """
        return self._current_scan[:]

    @current_scan.setter
    def current_scan(self, val):
        self._current_scan = val

    @property
    def previous_scan(self):
        """
        Returns previous scan timestamp

        Returns:
            float

        """

        return int(croniter(self._scan_cron(), time.time()).get_prev())

    @property
    def next_scan(self):
        """
        Time of next regular scan

        Returns:
            float

        """
        return int(croniter(self._scan_cron(), time.time()).get_next())

    def _scan_interval(self):
        """
        Get interval between particular node scan

        Returns:
            int

        """
        if cfg['portdetection.{name}.scan_type'.format(
                name=self.NAME)] == ScanType.PERIODIC.value:
            return 0

        return parse_period(
            cfg['portdetection.{name}.live_scan.min_time_gap'.format(
                name=self.NAME)])

    def _scan_cron(self):
        """
        Get scan cron

        Returns:
            str

        """
        if cfg['portdetection.{name}.scan_type'.format(
                name=self.NAME)] == ScanType.LIVE.value:
            return self.LIVE_SCAN_CRON

        return cfg['portdetection.{name}.periodic_scan.cron'.format(
            name=self.NAME)]

    def is_exploit_allowed(self, exploit):
        """
        Check if exploit can be executed by scanner

        Args:
            exploit:

        Returns:
            bool

        """
        return exploit.id in map(
            int, cfg['portdetection.{0}.scripts'.format(self.NAME)])

    async def _clean_scan(self):
        """
        Clean scan and update scan status

        Returns:
            None

        """
        await self.update_scan_status(ScanStatus.IDLE)
        self.scan.rowid = None  # ToDo: Do it more pythonic
        self._shutdown_condition.set()

    async def update_scan_status(self, status=None):
        """
        Update scan status base on status value

        Args:
            status (ScanStatus):

        Returns:
            None

        """
        self.status = status

        if not cfg.toucan or cfg['portdetection.{name}.scan_type'.format(
                name=self.NAME)] == ScanType.LIVE.value:
            return

        current_status = cfg.get('portdetection.{0}.status.*'.format(
            self.NAME),
                                 cache=False)

        data = {'portdetection': {self.NAME: {'status': {}}}}

        log.debug("Current status for %s is %s", self.NAME, current_status.cfg)
        next_scan = round(current_status['next_scan_start'])
        if next_scan != self.next_scan:
            data['portdetection'][
                self.NAME]['status']['next_scan_start'] = self.next_scan

        if self.scan.start:
            previous_scan_start = current_status['scan_start']
            if previous_scan_start != self.scan.start:
                data['portdetection'][self.NAME]['status'][
                    'previous_scan_start'] = previous_scan_start
                data['portdetection'][
                    self.NAME]['status']['scan_start'] = self.scan.start

        if status is not None:
            current_status_code = current_status['code']
            if current_status_code != status.value:
                data['portdetection'][
                    self.NAME]['status']['code'] = status.value

        if status is ScanStatus.IDLE and self.scan.start is not None:
            data['portdetection'][self.NAME]['status'][
                'previous_scan_duration'] = int(time.time() - self.scan.start)

        if data['portdetection'][self.NAME]['status']:
            log.debug("Update toucan by %s with %s", self.NAME, data)
            await cfg.toucan.async_push_config(data,
                                               overwrite=True,
                                               keep_history=False)

    @property
    def topdis(self):
        """
        Topdis API object

        Returns:
            Topdis

        """
        return self.aucote.topdis

    async def stop(self):
        """
        Stops scan by stopping/cancelling all its related tasks

        """
        log.info('Stopping scan %s', self.NAME)
        if self.context is None:
            log.warning("There is no %s scan in progress", self.NAME)
            return

        self.context.cancel()

        if not self.context.is_scan_end():
            tasks = self.context.unfinished_tasks()

            log.warning('Cancelling %s tasks for scan %s', len(tasks),
                        self.NAME)
            for task in tasks:
                task.cancel()

        await self.context.wait_on_scan_end()

        log.info('Scan %s cancelled successfully', self.NAME)

    def prepare_vulnerability_for_kudu(self, vuln: 'Vulnerability'):
        """
        Update vulnerability to meet all fields required by kudu serializer

        """
        data = self.storage.portdetection_vulns(vuln)

        os_service = Service(name=data['os_name'],
                             version=data['os_version'],
                             cpe=data['os_cpe'])
        vuln.port.node.os = os_service
        vuln.port.protocol = data['protocol']
        vuln.port.banner = data['banner']
        vuln.port.service.name = data['name']
        vuln.port.service.version = data['version']
        vuln.port.service.cpe = data['cpe']

        return vuln

    def expire_vulnerabilities(self):
        """
        Update validation time of vulnerabilites

        """
        # Do not update already deprecated vulnerabilities, so get all later than timestamp - expiration_period
        timestamp = time.time()
        expiration_period = parse_period(
            cfg['portdetection.expiration_period'])

        vulns = self.storage.expire_vulnerabilities(timestamp=timestamp -
                                                    expiration_period)
        for vuln in vulns:
            # There is some mismatch between kudu and local storage
            if vuln.exploit.id == 0 and vuln.subid > 0:
                continue
            self.prepare_vulnerability_for_kudu(vuln)
            self.store_vulnerability(vuln)

    def store_vulnerability(self, vuln):
        """
        Saves vulnerability into database: kudu and local storage
        """
        expiration_period = parse_period(
            cfg['portdetection.expiration_period'])

        log.debug('Found vulnerability %s for %s',
                  vuln.exploit.id if vuln.exploit is not None else None,
                  vuln.port)

        try:
            # Do not save vulnerability which is already saved: FixMe: better save and update vulns
            if vuln.expiration_time is None:
                self.aucote.storage.save_vulnerabilities(
                    vulnerabilities=[vuln], scan=self.scan)
        except Exception:
            log.warning(
                'Error during saving vulnerability (%s, %s) to the storage',
                vuln.exploit.id if vuln.exploit is not None else None,
                vuln.subid)

        # FixMe: A little bit hacking here: Serializer doesn't have access to Toucan,
        # so I have to set expiration time in vuln. Future solution: Incorporate serializer into Aucote instance

        if vuln.expiration_time is None:
            vuln.expiration_time = vuln.time + expiration_period

        msg = Serializer.serialize_vulnerability(vuln)
        self.aucote.kudu_queue.send_msg(msg)

    def __str__(self):
        return self.__class__.__name__

    def get_last_scan(self, resume: Optional[bool] = None) -> Optional['Scan']:
        """
        Get last scan from database
        """
        scans = self.storage.get_scans(self.PROTOCOL,
                                       self.NAME,
                                       amount=2,
                                       resume=resume)

        if not scans:
            return None

        if scans[0].rowid == self.scan.rowid:
            if len(scans) == 1:
                return None

            return scans[1]

        return scans[0]

    def get_previous_non_resumed_scan(self):
        """
        Returns scan before last scan (which is not current scan)
        Returns:

        """
        scans = self.storage.get_scans(self.PROTOCOL,
                                       self.NAME,
                                       amount=3,
                                       resume=False)

        if not scans:
            return None

        # We should have at least 2 scans
        if len(scans) == 1:
            return None

        if len(scans) == 2:
            # If last scan is current scan, the second one is truly last scan
            if scans[0].rowid == self.scan.rowid:
                return None
            return scans[1]

        return scans[2]
Example #24
0
 def _init(self):
     if self.context is not None:
         raise Exception("Scan context already exists")
     self.context = ScanContext(aucote=self.aucote, scanner=self)
Example #25
0
 def setUp(self):
     super(ScanContextTest, self).setUp()
     self.scan = MagicMock()
     self.aucote = MagicMock()
     self.context = ScanContext(aucote=self.aucote, scanner=self.scan)
Example #26
0
    def get_app(self):
        self.aucote = MagicMock(unfinished_tasks=4)
        self.context = ScanContext(aucote=self.aucote, scanner=None)
        self.tasks = AsyncTaskManager()
        self.tasks._is_running = False
        tasks = [
            {
                'port': 45,
                'id': 1,
                'ip': '127.0.0.1'
            },
            {
                'port': 56,
                'id': 2,
                'ip': '127.0.0.2'
            },
            {
                'port': 67,
                'id': 3,
                'ip': '127.0.0.3'
            },
        ]
        worker_tasks = [
            {
                'port': 78,
                'id': 4,
                'ip': '127.0.0.4'
            },
            {
                'port': 89,
                'id': 5,
                'ip': '127.0.0.5'
            },
        ]
        for task in tasks:
            self.tasks.add_task(
                PortTask(context=self.context,
                         port=Port(
                             node=Node(node_id=task['id'],
                                       ip=ipaddress.ip_address(task['ip'])),
                             number=task['port'],
                             transport_protocol=TransportProtocol.TCP,
                         ),
                         exploits=[]))

        self.tasks._task_workers = {
            number:
            PortTask(context=self.context,
                     port=Port(
                         node=Node(node_id=task['id'],
                                   ip=ipaddress.ip_address(task['ip'])),
                         number=task['port'],
                         transport_protocol=TransportProtocol.TCP,
                     ),
                     exploits=[])
            for number, task in enumerate(worker_tasks)
        }

        class test_function:
            def __str__(self):
                return 'test_function'

            def __call__(self, *args, **kwargs):
                pass

        self.tasks.add_crontab_task(test_function(), '0 0 0 0 0')
        self.tasks._task_workers.update({2: None, 3: None, 4: None})

        self.aucote.async_task_managers = {TaskManagerType.SCANNER: self.tasks}
        self.app = Application([(r"/api/v1/tasks", TasksHandler, {
            'aucote': self.aucote
        })])
        return self.app