Passed
Push — master ( bd40ef...f1f17f )
by
unknown
02:07 queued 34s
created

OSPDopenvas.get_refs_vt_as_xml_str()   A

Complexity

Conditions 4

Size

Total Lines 16
Code Lines 14

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 14
dl 16
loc 16
rs 9.7
c 0
b 0
f 0
cc 4
nop 1
1
# -*- coding: utf-8 -*-
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
# Description:
3
# Setup for the OSP OpenVAS Server
4
#
5
# Authors:
6
# Juan José Nicola <[email protected]>
7
#
8
# Copyright:
9
# Copyright (C) 2018 Greenbone Networks GmbH
10
#
11
# This program is free software; you can redistribute it and/or
12
# modify it under the terms of the GNU General Public License
13
# as published by the Free Software Foundation; either version 2
14
# of the License, or (at your option) any later version.
15
#
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
# GNU General Public License for more details.
20
#
21
# You should have received a copy of the GNU General Public License
22
# along with this program; if not, write to the Free Software
23
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25
import subprocess
26
import time
27
import signal
28
import uuid
29
import xml.etree.ElementTree as ET
30
import psutil
31
32
from ospd.ospd import OSPDaemon, logger
33
from ospd.misc import main as daemon_main
34
from ospd.misc import target_str_to_list
35
from ospd_openvas import __version__
36
37
import ospd_openvas.nvticache as nvti
38
import ospd_openvas.openvas_db as openvas_db
39
40
OSPD_DESC = """
41
This scanner runs 'OpenVAS Scanner' to scan the target hosts.
42
43
OpenVAS (Open Vulnerability Assessment System) is a powerful scanner
44
for vulnerabilities in IT infrastrucutres. The capabilities include
45
unauthzenticated scanning as well as authneticated scanning for
46
various types of systems and services.
47
48
For more details about OpenVAS see the OpenVAS homepage:
49
http://www.openvas.org/
50
51
The current version of ospd-openvas is a simple frame, which sends
52
the server parameters to the Greenbone Vulnerability Manager (GVM) and checks
53
the existence of OpenVAS Scanner binary. But it can not run scans yet.
54
"""
55
56
MAIN_KBINDEX = None
57
58
OSPD_PARAMS = {
59
    'auto_enable_dependencies': {
60
        'type': 'boolean',
61
        'name': 'auto_enable_dependencies',
62
        'default': 1,
63
        'mandatory': 1,
64
        'description': 'Automatically enable the plugins that are depended on',
65
    },
66
    'cgi_path': {
67
        'type': 'string',
68
        'name': 'cgi_path',
69
        'default': '/cgi-bin:/scripts',
70
        'mandatory': 1,
71
        'description': 'Look for default CGIs in /cgi-bin and /scripts',
72
    },
73
    'checks_read_timeout': {
74
        'type': 'integer',
75
        'name': 'checks_read_timeout',
76
        'default': 5,
77
        'mandatory': 1,
78
        'description': ('Number  of seconds that the security checks will ' +
79
                        'wait for when doing a recv()'),
80
    },
81
    'drop_privileges': {
82
        'type': 'boolean',
83
        'name': 'drop_privileges',
84
        'default': 0,
85
        'mandatory': 1,
86
        'description': '',
87
    },
88
    'network_scan': {
89
        'type': 'boolean',
90
        'name': 'network_scan',
91
        'default': 0,
92
        'mandatory': 1,
93
        'description': '',
94
    },
95
    'non_simult_ports': {
96
        'type': 'string',
97
        'name': 'non_simult_ports',
98
        'default': '139, 445, 3389, Services/irc',
99
        'mandatory': 1,
100
        'description': ('Prevent to make two connections on the same given ' +
101
                        'ports at the same time.'),
102
    },
103
    'open_sock_max_attempts': {
104
        'type': 'integer',
105
        'name': 'open_sock_max_attempts',
106
        'default': 5,
107
        'mandatory': 0,
108
        'description': ('Number of unsuccessful retries to open the socket ' +
109
                        'before to set the port as closed.'),
110
    },
111
    'timeout_retry': {
112
        'type': 'integer',
113
        'name': 'timeout_retry',
114
        'default': 5,
115
        'mandatory': 0,
116
        'description': ('Number of retries when a socket connection attempt ' +
117
                        'timesout.'),
118
    },
119
    'optimize_test': {
120
        'type': 'integer',
121
        'name': 'optimize_test',
122
        'default': 5,
123
        'mandatory': 0,
124
        'description': ('By default, openvassd does not trust the remote ' +
125
                        'host banners.'),
126
    },
127
    'plugins_timeout': {
128
        'type': 'integer',
129
        'name': 'plugins_timeout',
130
        'default': 5,
131
        'mandatory': 0,
132
        'description': 'This is the maximum lifetime, in seconds of a plugin.',
133
    },
134
    'report_host_details': {
135
        'type': 'boolean',
136
        'name': 'report_host_details',
137
        'default': 1,
138
        'mandatory': 1,
139
        'description': '',
140
    },
141
    'safe_checks': {
142
        'type': 'boolean',
143
        'name': 'safe_checks',
144
        'default': 1,
145
        'mandatory': 1,
146
        'description': ('Disable the plugins with potential to crash ' +
147
                        'the remote services'),
148
    },
149
    'scanner_plugins_timeout': {
150
        'type': 'integer',
151
        'name': 'scanner_plugins_timeout',
152
        'default': 36000,
153
        'mandatory': 1,
154
        'description': 'Like plugins_timeout, but for ACT_SCANNER plugins.',
155
    },
156
    'time_between_request': {
157
        'type': 'integer',
158
        'name': 'time_between_request',
159
        'default': 0,
160
        'mandatory': 0,
161
        'description': ('Allow to set a wait time between two actions ' +
162
                        '(open, send, close).'),
163
    },
164
    'unscanned_closed': {
165
        'type': 'boolean',
166
        'name': 'unscanned_closed',
167
        'default': 1,
168
        'mandatory': 1,
169
        'description': '',
170
    },
171
    'unscanned_closed_udp': {
172
        'type': 'boolean',
173
        'name': 'unscanned_closed_udp',
174
        'default': 1,
175
        'mandatory': 1,
176
        'description': '',
177
    },
178
    'use_mac_addr': {
179
        'type': 'boolean',
180
        'name': 'use_mac_addr',
181
        'default': 0,
182
        'mandatory': 0,
183
        'description': 'To test the local network. ' +
184
                       'Hosts will be referred to by their MAC address.',
185
    },
186
    'vhosts': {
187
        'type': 'string',
188
        'name': 'vhosts',
189
        'default': '',
190
        'mandatory': 0,
191
        'description': '',
192
    },
193
    'vhosts_ip': {
194
        'type': 'string',
195
        'name': 'vhosts_ip',
196
        'default': '',
197
        'mandatory': 0,
198
        'description': '',
199
    },
200
}
201
202
203 View Code Duplication
class OSPDopenvas(OSPDaemon):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
204
205
    """ Class for ospd-openvas daemon. """
206
207
    def __init__(self, certfile, keyfile, cafile):
208
        """ Initializes the ospd-openvas daemon's internal data. """
209
210
        super(OSPDopenvas, self).__init__(certfile=certfile, keyfile=keyfile,
211
                                          cafile=cafile)
212
        self.server_version = __version__
213
        self.scanner_info['name'] = 'openvassd'
214
        self.scanner_info['version'] = ''  # achieved during self.check()
215
        self.scanner_info['description'] = OSPD_DESC
216
        for name, param in OSPD_PARAMS.items():
217
            self.add_scanner_param(name, param)
218
219
        if openvas_db.db_init() is False:
220
            logger.error('OpenVAS Redis Error: Not possible '
221
                         'to find db_connection.')
222
            raise Exception
223
224
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
225
        if not ctx:
226
            self.redis_nvticache_init()
227
            ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
228
        openvas_db.set_global_redisctx(ctx)
229
        self.load_vts()
230
231
    def parse_param(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
232
        """ Set OSPD_PARAMS with the params taken from the openvas_scanner. """
233
        global OSPD_PARAMS
0 ignored issues
show
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
234
        bool_dict = {'no': 0, 'yes': 1}
235
236
        result = subprocess.check_output(['openvassd', '-s'],
237
                                         stderr=subprocess.STDOUT)
238
        result = result.decode('ascii')
239
        param_list = dict()
240
        for conf in result.split('\n'):
241
            elem = conf.split('=')
242
            if len(elem) == 2:
243
                value = str.strip(elem[1])
244
                if str.strip(elem[1]) in bool_dict:
245
                    value = bool_dict[value]
246
                param_list[str.strip(elem[0])] = value
247
        for elem in OSPD_PARAMS:
248
            if elem in param_list:
249
                OSPD_PARAMS[elem]['default'] = param_list[elem]
250
251
    def redis_nvticache_init(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
252
        """ Loads NVT's metadata into Redis DB. """
253
        try:
254
            logger.debug('Loading NVTs in Redis DB')
255
            subprocess.check_call(['openvassd', '-C'])
256
        except subprocess.CalledProcessError as err:
257
            logger.error('OpenVAS Scanner failed to load NVTs.')
258
            raise err
259
260
    def load_vts(self):
261
        """ Load the NVT's OIDs and their filename into the vts
262
        global  dictionary. """
263
        oids = nvti.get_oids()
264
        str_out = True
0 ignored issues
show
Unused Code introduced by
The variable str_out seems to be unused.
Loading history...
265
        for oid in oids:
266
            vt_id = oid[1]
267
            filename = oid[0].split(':')
268
            ret = self.add_vt(vt_id,
269
                              name=filename[1],
270
                              vt_params=nvti.get_nvt_params(vt_id),
271
                              vt_refs=nvti.get_nvt_refs(vt_id),
272
                              custom=nvti.get_nvt_metadata(vt_id))
273
            if ret == -1:
274
                logger.info("Dupplicated VT with OID: {0}".format(vt_id))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
275
            if ret == -2:
276
                logger.info("{0}: Invalid OID.".format(vt_id))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
277
278
    @staticmethod
279
    def get_custom_vt_as_xml_str(custom):
280
        """ Return custom since it is already formated as string. """
281
282
        nvt = ET.Element('vt')
283
        for key, val in custom.items():
284
            xml_key = ET.SubElement(nvt, key)
285
            xml_key.text = val
286
287
        itera = nvt.iter()
288
        metadata = ''
289
        for elem in itera:
290
            if elem.tag != 'vt' and elem.tag != 'file_name':
291
                metadata += (ET.tostring(elem).decode('utf-8'))
292
        return metadata
293
294
    @staticmethod
295
    def get_params_vt_as_xml_str(vt_params):
296
        """ Return custom since it is already formated as string. """
297
        vt_params_xml = ET.Element('vt_params')
298
        for prefs in vt_params.items():
299
            vt_param = ET.Element('vt_param')
300
            vt_param.set('id', prefs[0])
301
            vt_param.set('type', prefs[1]['type'])
302
            xml_name = ET.SubElement(vt_param, 'name')
303
            xml_name.text = prefs[1]['name']
304
            if prefs[1]['default']:
305
                xml_def = ET.SubElement(vt_param, 'default')
306
                xml_def.text = prefs[1]['default']
307
            vt_params_xml.append(vt_param)
308
309
        params_list = vt_params_xml.findall("vt_param")
310
        params = ''
311
        for param in params_list:
312
            params += (ET.tostring(param).decode('utf-8'))
313
        return params
314
315
    @staticmethod
316
    def get_refs_vt_as_xml_str(vt_refs):
317
        """ Return custom since it is already formated as string. """
318
        vt_refs_xml = ET.Element('vt_prefs')
319
        for ref_type, ref_values in vt_refs.items():
320
            for value in ref_values:
321
                vt_ref = ET.Element('ref')
322
                vt_ref.set('type', ref_type)
323
                vt_ref.set('id', value)
324
                vt_refs_xml.append(vt_ref)
325
326
        refs_list = vt_refs_xml.findall("ref")
327
        refs = ''
328
        for ref in refs_list:
329
            refs += (ET.tostring(ref).decode('utf-8'))
330
        return refs
331
332
    def check(self):
333
        """ Checks that openvassd command line tool is found and
334
        is executable. """
335
        try:
336
            result = subprocess.check_output(['openvassd', '-V'],
337
                                             stderr=subprocess.STDOUT)
338
            result = result.decode('ascii')
339
        except OSError:
340
            # The command is not available
341
            return False
342
343
        if result is None:
344
            return False
345
346
        version = result.split('\n')
347
        if version[0].find('OpenVAS') < 0:
348
            return False
349
350
        self.parse_param()
351
        self.scanner_info['version'] = version[0]
352
353
        return True
354
355
    def update_progress(self, scan_id, target, msg):
356
        """ Calculate porcentage and update the scan status
357
        for the progress bar. """
358
        host_progress_dict = dict()
359
        prog = str.split(msg, '/')
360
        if float(prog[1]) == 0:
361
            return
362
        host_prog = (float(prog[0]) / float(prog[1])) * 100
363
        host_progress_dict[target] = host_prog
364
        total_host = len(target_str_to_list(target))
365
        self.set_scan_target_progress(scan_id, target,
366
                                      sum(host_progress_dict.values()) / total_host)
367
368
    def get_openvas_status(self, scan_id, target):
369
        """ Get all status entries from redis kb. """
370
        res = openvas_db.get_status()
371
        while res:
372
            self.update_progress(scan_id, target, res)
373
            res = openvas_db.get_status()
374
375
    def get_openvas_result(self, scan_id):
376
        """ Get all result entries from redis kb. """
377
        res = openvas_db.get_result()
378
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
379
        while res:
380
            msg = res.split('|||')
381
            host_aux = openvas_db.item_get_single('internal/ip')
382
            roid = msg[3]
383
            tag = nvti.get_nvt_tag(ctx, roid)
384
            rqod = nvti.get_nvt_qod(ctx, tag)
385
            rseverity = nvti.get_nvt_severity(ctx, tag)
386
            rname = nvti.get_nvt_name(ctx, roid)
387
388
            if msg[0] == 'ERRMSG':
389
                self.add_scan_error(scan_id, host=host_aux,
390
                                    name=rname, value=msg[4], port=msg[2])
391
            if msg[0] == 'LOG':
392
                self.add_scan_log(scan_id, host=host_aux, name=rname,
393
                                  value=msg[4], port=msg[2], qod=rqod,
394
                                  test_id=roid)
395
            if msg[0] == 'HOST_DETAIL':
396
                self.add_scan_log(scan_id, host=host_aux, name=rname,
397
                                  value=msg[4])
398
            if msg[0] == 'ALARM':
399
                self.add_scan_alarm(scan_id, host=host_aux, name=rname,
400
                                    value=msg[4], port=msg[2],
401
                                    test_id=roid, severity=rseverity,
402
                                    qod=rqod)
403
            res = openvas_db.get_result()
404
405
    def get_openvas_timestamp_scan_host(self, scan_id, target):
406
        """ Get start and end timestamp of a host scan from redis kb. """
407
        timestamp = openvas_db.get_host_scan_scan_end_time()
408
        if timestamp:
409
            self.add_scan_log(scan_id, host=target, name='HOST_END',
410
                              value=timestamp)
411
            return
412
        timestamp = openvas_db.get_host_scan_scan_start_time()
413
        if timestamp:
414
            self.add_scan_log(scan_id, host=target, name='HOST_START',
415
                              value=timestamp)
416
            return
417
418
    def scan_is_finished(self, scan_id):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
419
        """ Check if the scan has finished. """
420
        status = openvas_db.item_get_single(('internal/%s' % scan_id))
421
        return status == 'finished'
422
423
    def scan_is_stopped(self, scan_id):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
424
        """ Check if the parent process has recieved the stop_scan order.
425
        @in scan_id: ID to identify the scan to be stopped.
426
        @return 1 if yes, None in oder case.
427
        """
428
        ctx = openvas_db.kb_connect(dbnum=MAIN_KBINDEX)
429
        openvas_db.set_global_redisctx(ctx)
430
        status = openvas_db.item_get_single(('internal/%s' % scan_id))
431
        return status == 'stop_all'
432
433
    @staticmethod
434
    def stop_scan(global_scan_id):
0 ignored issues
show
Bug introduced by
Parameters differ from overridden 'stop_scan' method
Loading history...
435
        """ Set a key in redis to indicate the wrapper is stopped.
436
        It is done through redis because it is a new multiprocess
437
        instance and it is not possible to reach the variables
438
        of the grandchild process. Send SIGUSR2 to openvas to stop
439
        each running scan."""
440
        ctx = openvas_db.kb_connect()
441
        for current_kbi in range(0, openvas_db.MAX_DBINDEX):
442
            ctx.execute_command('SELECT '+ str(current_kbi))
443
            openvas_db.set_global_redisctx(ctx)
444
            scan_id = openvas_db.item_get_single(
445
                ('internal/%s/globalscanid' % global_scan_id))
446
            if scan_id:
447
                openvas_db.item_set_single(('internal/%s' % scan_id),
448
                                           ['stop_all', ])
449
                ovas_pid = openvas_db.item_get_single('internal/ovas_pid')
450
                parent = psutil.Process(int(ovas_pid))
451
                openvas_db.release_db(current_kbi)
452
                parent.send_signal(signal.SIGUSR2)
453
                logger.debug('Stopping process: {0}'.format(parent))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
454
455
    @staticmethod
456
    def get_vts_in_groups(ctx, filters):
457
        """ Return a list of vts which match with the given filter.
458
459
        @input filters A list of filters. Each filter has key, operator and
460
                       a value. They are separated by a space.
461
                       Supported keys: family
462
        @return Return a list of vts which match with the given filter.
463
        """
464
        vts_list = list()
465
        families = dict()
466
        oids = nvti.get_oids()
467
        for oid in oids:
468
            family = nvti.get_nvt_family(ctx, oid[1])
469
            if family not in families:
470
                families[family] = list()
471
            families[family].append(oid[1])
472
473
        for elem in filters:
474
            key, value = elem.split('=')
475
            if key == 'family' and value in families:
476
                vts_list.extend(families[value])
477
        return vts_list
478
479
    def get_vt_param_type(self, vtid, vt_param_id):
480
        """ Return the type of the vt paramater from the vts dictionary. """
481
        vt_params_list = self.vts[vtid].get("vt_params")
482
        return vt_params_list[vt_param_id]["type"]
483
484
    @staticmethod
485
    def check_param_type(vt_param_value, param_type):
486
        """ Check if the value of a vt parameter matches with
487
        the type founded.
488
        """
489
        if (param_type in ['entry',
490
                           'file',
491
                           'password',
492
                           'radio',
493
                           'sshlogin', ] and isinstance(vt_param_value, str)):
494
            return None
495
        elif (param_type == 'checkbox' and
496
              (vt_param_value == 'yes' or vt_param_value == 'no')):
497
            return None
498
        elif param_type == 'integer':
499
            try:
500
                int(vt_param_value)
501
            except ValueError:
502
                return 1
503
            return None
504
505
        return 1
506
507
    def process_vts(self, vts):
508
        """ Add single VTs and their parameters. """
509
        vts_list = []
510
        vts_params = []
511
        vtgroups = vts.pop('vt_groups')
512
513
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
514
        openvas_db.set_global_redisctx(ctx)
515
        if vtgroups:
516
            vts_list = self.get_vts_in_groups(ctx, vtgroups)
517
518
        for vtid, vt_params in vts.items():
519
            vts_list.append(vtid)
520
            nvt_name = nvti.get_nvt_name(ctx, vtid)
521
            for vt_param_id, vt_param_value in vt_params.items():
522
                param_type = self.get_vt_param_type(vtid, vt_param_id)
523
                if vt_param_id == 'timeout':
524
                    type_aux = 'integer'
525
                else:
526
                    type_aux = param_type
527
                if self.check_param_type(vt_param_value, type_aux):
528
                    logger.debug('Expected {} type for parameter value {}'
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
529
                                 .format(type_aux, str(vt_param_value)))
530
                param = ["{0}[{1}]:{2}".format(nvt_name, param_type,
531
                                               vt_param_id),
532
                         str(vt_param_value)]
533
                vts_params.append(param)
534
        return vts_list, vts_params
535
536
    @staticmethod
537
    def build_credentials_as_prefs(credentials):
538
        """ Parse the credential dictionary.
539
        @param credentials: Dictionary with the credentials.
540
541
        @return A list with the credentials in string format to be
542
                added to the redis KB.
543
        """
544
        cred_prefs_list = []
545
        for credential in credentials.items():
546
            service = credential[0]
547
            cred_params = credentials.get(service)
548
            cred_type = cred_params.get('type', '')
549
            username = cred_params.get('username', '')
550
            password = cred_params.get('password', '')
551
552
            if service == 'ssh':
553
                port = cred_params.get('port', '')
554
                cred_prefs_list.append('auth_port_ssh|||' +
555
                                       '{0}'.format(port))
556
                cred_prefs_list.append('SSH Authorization[entry]:SSH login ' +
557
                                       'name:|||{0}'.format(username))
558
                if cred_type == 'up':
559
                    cred_prefs_list.append('SSH Authorization[password]:' +
560
                                           'SSH password (unsafe!):|||' +
561
                                           '{0}'.format(password))
562
                else:
563
                    private = cred_params.get('private', '')
564
                    cred_prefs_list.append('SSH Authorization[password]:' +
565
                                           'SSH key passphrase:|||' +
566
                                           '{0}'.format(password))
567
                    cred_prefs_list.append('SSH Authorization[file]:' +
568
                                           'SSH private key:|||' +
569
                                           '{0}'.format(private))
570
            if service == 'smb':
571
                cred_prefs_list.append('SMB Authorization[entry]:SMB login:' +
572
                                       '|||{0}'.format(username))
573
                cred_prefs_list.append('SMB Authorization[password]:' +
574
                                       'SMB password :|||' +
575
                                       '{0}'.format(password))
576
            if service == 'esxi':
577
                cred_prefs_list.append('ESXi Authorization[entry]:ESXi login ' +
578
                                       'name:|||{0}'.format(username))
579
                cred_prefs_list.append('ESXi Authorization[password]:' +
580
                                       'ESXi login password:|||' +
581
                                       '{0}'.format(password))
582
583
            if service == 'snmp':
584
                community = cred_params.get('community', '')
585
                auth_algorithm = cred_params.get('auth_algorithm', '')
586
                privacy_password = cred_params.get('privacy_password', '')
587
                privacy_algorithm = cred_params.get('privacy_algorithm', '')
588
589
                cred_prefs_list.append('SNMP Authorization[password]:' +
590
                                       'SNMP Community:' +
591
                                       '{0}'.format(community))
592
                cred_prefs_list.append('SNMP Authorization[entry]:' +
593
                                       'SNMPv3 Username:' +
594
                                       '{0}'.format(username))
595
                cred_prefs_list.append('SNMP Authorization[password]:' +
596
                                       'SNMPv3 Password:' +
597
                                       '{0}'.format(password))
598
                cred_prefs_list.append('SNMP Authorization[radio]:' +
599
                                       'SNMPv3 Authentication Algorithm:' +
600
                                       '{0}'.format(auth_algorithm))
601
                cred_prefs_list.append('SNMP Authorization[password]:' +
602
                                       'SNMPv3 Privacy Password:' +
603
                                       '{0}'.format(privacy_password))
604
                cred_prefs_list.append('SNMP Authorization[radio]:' +
605
                                       'SNMPv3 Privacy Algorithm:' +
606
                                       '{0}'.format(privacy_algorithm))
607
608
        return cred_prefs_list
609
610
    def exec_scan(self, scan_id, target):
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (30/15).
Loading history...
611
        """ Starts the OpenVAS scanner for scan_id scan. """
612
        global MAIN_KBINDEX
0 ignored issues
show
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
613
        ports = self.get_scan_ports(scan_id, target)
614
        if not ports:
615
            self.add_scan_error(scan_id, name='', host=target,
616
                                value='No port list defined.')
617
            return 2
618
619
        # Get scan options
620
        options = self.get_scan_options(scan_id)
621
        prefs_val = []
622
        ctx = openvas_db.kb_new()
623
        openvas_db.set_global_redisctx(ctx)
624
        MAIN_KBINDEX = openvas_db.DB_INDEX
625
626
        # To avoid interference between scan process during a parallel scanning
627
        # new uuid is used internaly for each scan.
628
        openvas_scan_id = str(uuid.uuid4())
629
        openvas_db.item_add_single(('internal/%s' % openvas_scan_id), ['new', ])
630
        openvas_db.item_add_single(('internal/%s/globalscanid' % scan_id), [openvas_scan_id, ])
631
632
        # Set scan preferences
633
        for item in options.items():
634
            item_type = ''
635
            if item[0] in OSPD_PARAMS:
636
                item_type = OSPD_PARAMS[item[0]].get('type')
637
            if item_type == 'boolean' and item[1] == 1:
638
                val = 'yes'
639
            else:
640
                val = str(item[1])
641
            prefs_val.append(item[0] + "|||" + val)
642
        openvas_db.item_add_single(str('internal/%s/scanprefs' % (openvas_scan_id)),
643
                                   prefs_val)
644
645
        # Store MAIN_KBINDEX as global preference
646
        ov_maindbid = ('ov_maindbid|||%d' % MAIN_KBINDEX)
647
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
648
                                   [ov_maindbid, ])
649
650
        # Set target
651
        target_aux = ('TARGET|||%s' % target)
652
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
653
                                   [target_aux, ])
654
        # Set port range
655
        port_range = ('port_range|||%s' % ports)
656
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
657
                                   [port_range, ])
658
659
        # Set credentials
660
        credentials = self.get_scan_credentials(scan_id, target)
661
        if credentials:
662
            cred_prefs = self.build_credentials_as_prefs(credentials)
663
            openvas_db.item_add_single(str('internal/%s/scanprefs' % openvas_scan_id),
664
                                       cred_prefs)
665
666
        # Set plugins to run
667
        nvts = self.get_scan_vts(scan_id)
668
        if nvts != '':
669
            nvts_list, nvts_params = self.process_vts(nvts)
670
            # Select the scan KB again.
671
            ctx.execute_command('SELECT '+ str(MAIN_KBINDEX))
672
            openvas_db.set_global_redisctx(ctx)
673
            # Add nvts list
674
            separ = ';'
675
            plugin_list = ('plugin_set|||%s' % separ.join(nvts_list))
676
            openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
677
                                       [plugin_list, ])
678
            # Add nvts parameters
679
            for elem in nvts_params:
680
                item = ('%s|||%s' % (elem[0], elem[1]))
681
                openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
682
                                           [item, ])
683
        else:
684
            openvas_db.release_db(MAIN_KBINDEX)
685
            self.add_scan_error(scan_id, name='', host=target,
686
                                value='No VTS to run.')
687
            return 2
688
689
        # Create a general log entry about executing OpenVAS
690
        # It is important to send at least one result, otherwise
691
        # the host details won't be stored.
692
        self.add_scan_log(scan_id, host=target, name='OpenVAS summary',
693
                          value='An OpenVAS Scanner was started for %s.'
694
                          % target)
695
696
        self.add_scan_log(scan_id, host=target, name='KB location Found',
697
                          value='KB location path was found: %s.'
698
                          % openvas_db.DB_ADDRESS)
699
700
        self.add_scan_log(scan_id, host=target, name='Feed Update',
701
                          value='Feed version: %s.'
702
                          % nvti.get_feed_version())
703
704
        cmd = ['openvassd', '--scan-start', openvas_scan_id]
705
        try:
706
            result = subprocess.Popen(cmd, shell=False)
707
        except OSError:
708
            # the command is not available
709
            return False
710
711
        ovas_pid = result.pid
712
        logger.debug('pid = {0}'.format(ovas_pid))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
713
        openvas_db.item_add_single(('internal/ovas_pid'), [ovas_pid, ])
714
715
        # Wait until the scanner starts and loads all the preferences.
716
        while openvas_db.item_get_single('internal/'+ openvas_scan_id) == 'new':
717
            time.sleep(1)
718
719
        no_id_found = False
720
        while True:
721
            time.sleep(3)
722
723
            # Check if the client stopped the whole scan
724
            if self.scan_is_stopped(openvas_scan_id):
725
                return 1
726
727
            ctx = openvas_db.kb_connect(MAIN_KBINDEX)
728
            openvas_db.set_global_redisctx(ctx)
729
            dbs = openvas_db.item_get_set('internal/dbindex')
730
            for i in list(dbs):
731
                if i == MAIN_KBINDEX:
732
                    continue
733
                ctx.execute_command('SELECT '+ str(i))
734
                openvas_db.set_global_redisctx(ctx)
735
                id_aux = ctx.execute_command('srandmember internal/scan_id')
736
                if not id_aux:
737
                    continue
738
                if id_aux == openvas_scan_id:
739
                    no_id_found = False
740
                    self.get_openvas_timestamp_scan_host(scan_id, target)
741
                    self.get_openvas_result(scan_id)
742
                    self.get_openvas_status(scan_id, target)
743
                    if self.scan_is_finished(openvas_scan_id):
744
                        ctx.execute_command('SELECT '+ str(MAIN_KBINDEX))
745
                        openvas_db.remove_set_member('internal/dbindex', i)
746
                        openvas_db.release_db(i)
747
748
            # Scan end. No kb in use for this scan id
749
            if no_id_found:
750
                break
751
            no_id_found = True
752
753
        # Delete keys from KB related to this scan task.
754
        openvas_db.release_db(MAIN_KBINDEX)
755
        return 1
756
757
758
def main():
759
    """ OSP openvas main function. """
760
    daemon_main('OSPD - openvas wrapper', OSPDopenvas)
761