Skip to content

Commit 8a359e5

Browse files
authored
Merge pull request #416 from Kraemii/better-credential-validation
Added validation, error handling and some debug messages for credentials
2 parents 6147d71 + ae4ae2d commit 8a359e5

File tree

4 files changed

+388
-33
lines changed

4 files changed

+388
-33
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

99
### Added
1010
- Validate port list to be sent to openvas. [#411](https://github.com/greenbone/ospd-openvas/pull/411)
11+
- Validate credentials to be sent to openvas. [#416](https://github.com/greenbone/ospd-openvas/pull/416)
1112

1213
### Changed
1314
### Removed

ospd_openvas/daemon.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1264,10 +1264,27 @@ def exec_scan(self, scan_id: str):
12641264

12651265
# Set credentials
12661266
if not scan_prefs.prepare_credentials_for_openvas():
1267+
error = (
1268+
'All authentifications contain errors.'
1269+
+ 'Starting unauthenticated scan instead.'
1270+
)
12671271
self.add_scan_error(
1268-
scan_id, name='', host='', value='Malformed credential.'
1272+
scan_id,
1273+
name='',
1274+
host='',
1275+
value=error,
12691276
)
1270-
do_not_launch = True
1277+
logger.error(error)
1278+
errors = scan_prefs.get_error_messages()
1279+
for e in errors:
1280+
error = 'Malformed credential. ' + e
1281+
self.add_scan_error(
1282+
scan_id,
1283+
name='',
1284+
host='',
1285+
value=error,
1286+
)
1287+
logger.error(error)
12711288

12721289
if not scan_prefs.prepare_plugins_for_openvas():
12731290
self.add_scan_error(

ospd_openvas/preferencehandler.py

+103-16
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,20 @@ def __init__(
107107

108108
self.nvti = nvticache
109109

110+
self.errors = []
111+
110112
def prepare_scan_id_for_openvas(self):
111113
"""Create the openvas scan id and store it in the redis kb.
112114
Return the openvas scan_id.
113115
"""
114116
self.kbdb.add_scan_id(self.scan_id)
115117

118+
def get_error_messages(self) -> List:
119+
"""Returns the Error List and reset it"""
120+
ret = self.errors
121+
self.errors = []
122+
return ret
123+
116124
@property
117125
def target_options(self) -> Dict:
118126
"""Return target options from Scan collection"""
@@ -571,8 +579,7 @@ def prepare_scan_params_for_openvas(self, ospd_params: Dict[str, Dict]):
571579
if prefs_val:
572580
self.kbdb.add_scan_preferences(self.scan_id, prefs_val)
573581

574-
@staticmethod
575-
def build_credentials_as_prefs(credentials: Dict) -> List[str]:
582+
def build_credentials_as_prefs(self, credentials: Dict) -> List[str]:
576583
"""Parse the credential dictionary.
577584
Arguments:
578585
credentials: Dictionary with the credentials.
@@ -589,23 +596,36 @@ def build_credentials_as_prefs(credentials: Dict) -> List[str]:
589596
username = cred_params.get('username', '')
590597
password = cred_params.get('password', '')
591598

599+
# Check service ssh
592600
if service == 'ssh':
593-
port = cred_params.get('port', '')
594-
cred_prefs_list.append('auth_port_ssh|||' + '{0}'.format(port))
595-
cred_prefs_list.append(
596-
OID_SSH_AUTH
597-
+ ':1:'
598-
+ 'entry:SSH login '
599-
+ 'name:|||{0}'.format(username)
600-
)
601+
# For ssh check the Port
602+
port = cred_params.get('port', '22')
603+
if not port:
604+
port = '22'
605+
warning = (
606+
"Missing port number for ssh credentials."
607+
+ " Using default port 22."
608+
)
609+
logger.warning(warning)
610+
elif not port.isnumeric():
611+
self.errors.append(
612+
"Port for SSH '" + port + "' is not a valid number."
613+
)
614+
continue
615+
elif int(port) > 65535 or int(port) < 1:
616+
self.errors.append(
617+
"Port for SSH is out of range (1-65535): " + port
618+
)
619+
continue
620+
# For ssh check the credential type
601621
if cred_type == 'up':
602622
cred_prefs_list.append(
603623
OID_SSH_AUTH
604624
+ ':3:'
605625
+ 'password:SSH password '
606626
+ '(unsafe!):|||{0}'.format(password)
607627
)
608-
else:
628+
elif cred_type == 'usk':
609629
private = cred_params.get('private', '')
610630
cred_prefs_list.append(
611631
OID_SSH_AUTH
@@ -619,7 +639,30 @@ def build_credentials_as_prefs(credentials: Dict) -> List[str]:
619639
+ 'file:SSH private key:|||'
620640
+ '{0}'.format(private)
621641
)
622-
if service == 'smb':
642+
elif cred_type:
643+
self.errors.append(
644+
"Unknown Credential Type for SSH: "
645+
+ cred_type
646+
+ ". Use 'up' for Username + Password"
647+
+ " or 'usk' for Username + SSH Key."
648+
)
649+
continue
650+
else:
651+
self.errors.append(
652+
"Missing Credential Type for SSH."
653+
+ " Use 'up' for Username + Password"
654+
+ " or 'usk' for Username + SSH Key."
655+
)
656+
continue
657+
cred_prefs_list.append('auth_port_ssh|||' + '{0}'.format(port))
658+
cred_prefs_list.append(
659+
OID_SSH_AUTH
660+
+ ':1:'
661+
+ 'entry:SSH login '
662+
+ 'name:|||{0}'.format(username)
663+
)
664+
# Check servic smb
665+
elif service == 'smb':
623666
cred_prefs_list.append(
624667
OID_SMB_AUTH
625668
+ ':1:entry'
@@ -631,7 +674,8 @@ def build_credentials_as_prefs(credentials: Dict) -> List[str]:
631674
+ 'password:SMB password:|||'
632675
+ '{0}'.format(password)
633676
)
634-
if service == 'esxi':
677+
# Check service esxi
678+
elif service == 'esxi':
635679
cred_prefs_list.append(
636680
OID_ESXI_AUTH
637681
+ ':1:entry:'
@@ -644,13 +688,47 @@ def build_credentials_as_prefs(credentials: Dict) -> List[str]:
644688
+ 'password:ESXi login password:|||'
645689
+ '{0}'.format(password)
646690
)
647-
648-
if service == 'snmp':
691+
# Check service snmp
692+
elif service == 'snmp':
649693
community = cred_params.get('community', '')
650694
auth_algorithm = cred_params.get('auth_algorithm', '')
651695
privacy_password = cred_params.get('privacy_password', '')
652696
privacy_algorithm = cred_params.get('privacy_algorithm', '')
653697

698+
if not privacy_algorithm:
699+
if privacy_password:
700+
self.errors.append(
701+
"When no privacy algorithm is used, the privacy"
702+
+ " password also has to be empty."
703+
)
704+
continue
705+
elif (
706+
not privacy_algorithm == "aes"
707+
and not privacy_algorithm == "des"
708+
):
709+
self.errors.append(
710+
"Unknows privacy algorithm used: "
711+
+ privacy_algorithm
712+
+ ". Use 'aes', 'des' or '' (none)."
713+
)
714+
continue
715+
716+
if not auth_algorithm:
717+
self.errors.append(
718+
"Missing authentification algorithm for SNMP."
719+
+ " Use 'md5' or 'sha1'."
720+
)
721+
continue
722+
elif (
723+
not auth_algorithm == "md5" and not auth_algorithm == "sha1"
724+
):
725+
self.errors.append(
726+
"Unknown authentification algorithm: "
727+
+ auth_algorithm
728+
+ ". Use 'md5' or 'sha1'."
729+
)
730+
continue
731+
654732
cred_prefs_list.append(
655733
OID_SNMP_AUTH
656734
+ ':1:'
@@ -685,20 +763,29 @@ def build_credentials_as_prefs(credentials: Dict) -> List[str]:
685763
+ 'radio:SNMPv3 Privacy Algorithm:|||'
686764
+ '{0}'.format(privacy_algorithm)
687765
)
766+
elif service:
767+
self.errors.append(
768+
"Unknown service type for credential: " + service
769+
)
770+
else:
771+
self.errors.append("Missing service type for credential.")
688772

689773
return cred_prefs_list
690774

691775
def prepare_credentials_for_openvas(self) -> bool:
692776
"""Get the credentials from the scan collection and store them
693777
in the kb."""
778+
logger.debug("Looking for given Credentials...")
694779
credentials = self.scan_collection.get_credentials(self.scan_id)
695780
if credentials:
696781
cred_prefs = self.build_credentials_as_prefs(credentials)
697782
if cred_prefs:
698783
self.kbdb.add_credentials_to_scan_preferences(
699784
self.scan_id, cred_prefs
700785
)
701-
786+
logger.debug("Credentials added to the kb.")
787+
else:
788+
logger.debug("No credentials found.")
702789
if credentials and not cred_prefs:
703790
return False
704791

0 commit comments

Comments
 (0)