Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: krb5 to openvasd. #1856

Merged
merged 3 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions rust/doc/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,16 @@ components:
- smb
- esxi
- snmp
- krb5
port:
description: "The port the authentication service is running."
type: "integer"
format: "int32"
up:
$ref: "#/components/schemas/UP"
krb5:
$ref: "#/components/schemas/KRB5"

usk:
$ref: "#/components/schemas/USK"
snmp:
Expand All @@ -634,6 +638,29 @@ components:
required:
- username


KRB5:
description: "Authentication via Kerberos GSA."
type: "object"
properties:
username:
description: "Username for authentication."
type: "string"
password:
description: "Password for authentication."
type: "string"
realm:
description: "Realm to be used by KRB5"
type: "string"
kdc:
description: "KDC to be defined within the realm."
type: "string"
required:
- username
- password
- realm
- kdc

USK:
description: "Authentication via Username and Security Key."
type: "object"
Expand Down
32 changes: 23 additions & 9 deletions rust/src/models/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@ impl Credential {
credential_type: self.credential_type.map_password(f)?,
})
}

/// Gets the password of the credential.
pub fn password(&self) -> &str {
match &self.credential_type {
CredentialType::UP { password, .. } => password,
CredentialType::USK { password, .. } => password,
CredentialType::SNMP { password, .. } => password,
}
}
}

impl Default for Credential {
Expand Down Expand Up @@ -86,6 +77,9 @@ pub enum Service {
#[cfg_attr(feature = "serde_support", serde(rename = "snmp"))]
/// SNMP, supports [SNMP](CredentialType::SNMP)
SNMP,
#[cfg_attr(feature = "serde_support", serde(rename = "krb5"))]
/// SNMP, supports [SNMP](CredentialType::SNMP)
KRB5,
}

impl AsRef<str> for Service {
Expand All @@ -95,6 +89,7 @@ impl AsRef<str> for Service {
Service::SMB => "smb",
Service::ESXi => "esxi",
Service::SNMP => "snmp",
Service::KRB5 => "krb5",
}
}
}
Expand All @@ -108,6 +103,7 @@ impl TryFrom<&str> for Service {
"smb" => Service::SMB,
"esxi" => Service::ESXi,
"snmp" => Service::SNMP,
"krb5" => Service::KRB5,
value => return Err(value.to_string()),
})
}
Expand Down Expand Up @@ -167,6 +163,12 @@ pub enum CredentialType {
/// The SNMP privacy algorithm.
privacy_algorithm: String,
},
KRB5 {
username: String,
password: String,
realm: String,
kdc: String,
},
}

impl CredentialType {
Expand Down Expand Up @@ -223,6 +225,17 @@ impl CredentialType {
privacy_password: f(privacy_password)?,
privacy_algorithm,
},
CredentialType::KRB5 {
username,
password,
realm,
kdc,
} => CredentialType::KRB5 {
username,
password: f(password)?,
realm,
kdc,
},
})
}
}
Expand All @@ -233,6 +246,7 @@ impl AsRef<str> for CredentialType {
CredentialType::UP { .. } => "up",
CredentialType::USK { .. } => "usk",
CredentialType::SNMP { .. } => "snmp",
CredentialType::KRB5 { .. } => "krb5",
}
}
}
69 changes: 61 additions & 8 deletions rust/src/openvas/pref_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::cmd;
use super::openvas_redis::{KbAccess, VtHelper};

const OID_SSH_AUTH: &str = "1.3.6.1.4.1.25623.1.0.103591";
const OID_KRB5_AUTH: &str = "1.3.6.1.4.1.25623.1.0.102114";
const OID_SMB_AUTH: &str = "1.3.6.1.4.1.25623.1.0.90023";
const OID_ESXI_AUTH: &str = "1.3.6.1.4.1.25623.1.0.105058";
const OID_SNMP_AUTH: &str = "1.3.6.1.4.1.25623.1.0.105076";
Expand Down Expand Up @@ -373,7 +374,30 @@ where

let mut credential_preferences: Vec<String> = vec![];
for credential in credentials {
// TODO: refactor that
match credential.service {
Service::KRB5 => {
if let Some(port) = credential.port {
credential_preferences.push(format!("auth_port_krb5|||{}", port));
} else {
credential_preferences.push("auth_port_krb5|||445".to_string());
};
if let CredentialType::KRB5 {
username,
password,
realm,
kdc,
} = credential.credential_type
{
credential_preferences
.push(format!("{OID_KRB5_AUTH}:1:entry::|||{}", username));
credential_preferences
.push(format!("{OID_KRB5_AUTH}:2:password::|||{}", password));
credential_preferences
.push(format!("{OID_KRB5_AUTH}:3:entry::|||{}", realm));
credential_preferences.push(format!("{OID_KRB5_AUTH}:4:entry::|||{}", kdc));
}
}
Service::SSH => {
if let Some(port) = credential.port {
credential_preferences.push(format!("auth_port_ssh|||{}", port));
Expand Down Expand Up @@ -550,15 +574,27 @@ mod tests {
};
scan.target.hosts = vec!["127.0.0.1".to_string(), "10.0.0.1".to_string()];
scan.target.alive_test_methods = vec![AliveTestMethods::Icmp, AliveTestMethods::TcpSyn];
scan.target.credentials = vec![Credential {
service: Service::SSH,
port: Some(22),
credential_type: CredentialType::UP {
username: "user".to_string(),
password: "pass".to_string(),
privilege: None,
scan.target.credentials = vec![
Credential {
service: Service::SSH,
port: Some(22),
credential_type: CredentialType::UP {
username: "user".to_string(),
password: "pass".to_string(),
privilege: None,
},
},
}];
Credential {
service: Service::KRB5,
port: None,
credential_type: CredentialType::KRB5 {
username: "user".to_string(),
password: "pass".to_string(),
realm: "realm".to_string(),
kdc: "kdc".to_string(),
},
},
];
scan.target.excluded_hosts = vec!["127.0.0.1".to_string()];
scan.target.ports = vec![Port {
protocol: Some(Protocol::TCP),
Expand Down Expand Up @@ -634,6 +670,23 @@ mod tests {
"1.3.6.1.4.1.25623.1.0.103591:1:entry:SSH login name:|||user"
));

assert!(prefh.redis_connector.item_exists(
"internal/123-456/scanprefs",
"1.3.6.1.4.1.25623.1.0.102114:1:entry::|||user"
));
assert!(prefh.redis_connector.item_exists(
"internal/123-456/scanprefs",
"1.3.6.1.4.1.25623.1.0.102114:2:password::|||pass"
));
assert!(prefh.redis_connector.item_exists(
"internal/123-456/scanprefs",
"1.3.6.1.4.1.25623.1.0.102114:3:entry::|||realm"
));
assert!(prefh.redis_connector.item_exists(
"internal/123-456/scanprefs",
"1.3.6.1.4.1.25623.1.0.102114:4:entry::|||kdc"
));

// Prepare and test Plugins
assert!(prefh.prepare_plugins_for_openvas().await.is_ok());
assert!(prefh
Expand Down
17 changes: 13 additions & 4 deletions rust/src/openvasd/storage/inmemory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ where

#[cfg(test)]
mod tests {
use models::Scan;
use models::{Credential, CredentialType, Scan};
use scannerlib::storage::ContextKey;

use super::*;
Expand Down Expand Up @@ -481,6 +481,15 @@ mod tests {
);
}

fn password(c: &Credential) -> &str {
match &c.credential_type {
CredentialType::UP { password, .. }
| CredentialType::USK { password, .. }
| CredentialType::SNMP { password, .. }
| CredentialType::KRB5 { password, .. } => password,
}
}

#[tokio::test]
async fn store_delete_scan() {
let storage = Storage::default();
Expand All @@ -499,7 +508,7 @@ mod tests {
let pw = models::Credential {
credential_type: models::CredentialType::UP {
username: "test".to_string(),
password: "test".to_string(),
password: "pass".to_string(),
privilege: None,
},
..Default::default()
Expand All @@ -511,11 +520,11 @@ mod tests {
storage.insert_scan(scan).await.unwrap();
let (retrieved, _) = storage.get_scan(&id).await.unwrap();
assert_eq!(retrieved.scan_id, id);
assert_ne!(retrieved.target.credentials[0].password(), "test");
assert_ne!(password(&retrieved.target.credentials[0]), "pass");

let (retrieved, _) = storage.get_decrypted_scan(&id).await.unwrap();
assert_eq!(retrieved.scan_id, id);
assert_eq!(retrieved.target.credentials[0].password(), "test");
assert_eq!(password(&retrieved.target.credentials[0]), "pass");
}

async fn store_scan(storage: &Storage<crypt::ChaCha20Crypt>) -> String {
Expand Down
11 changes: 11 additions & 0 deletions rust/src/osp/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,17 @@ fn write_credentials(scan: &Scan, writer: &mut Writer) -> Result<()> {
write_str_element(writer, "privacy_password", privacy_password)?;
write_str_element(writer, "privacy_algorithm", privacy_algorithm)?;
}
CredentialType::KRB5 {
username,
password,
realm,
kdc,
} => {
write_str_element(writer, "username", username)?;
write_str_element(writer, "password", password)?;
write_str_element(writer, "realm", realm)?;
write_str_element(writer, "kdc", kdc)?;
}
}

Ok(())
Expand Down
11 changes: 11 additions & 0 deletions rust/src/scannerctl/osp/start_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,17 @@ impl From<models::Credential> for Credential {
let kind = value.credential_type.as_ref().to_string();
let mut credentials = Vec::new();
match value.credential_type {
models::CredentialType::KRB5 {
username,
password,
realm,
kdc,
} => {
credentials.push(("username".to_string(), username));
credentials.push(("password".to_string(), password));
credentials.push(("realm".to_string(), realm));
credentials.push(("kdc".to_string(), kdc));
}
models::CredentialType::UP {
username,
password,
Expand Down
Loading