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: nasl-cli notus update subcommand #1558

Merged
merged 7 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions rust/feed/src/update/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use nasl_interpreter::{
};
use storage::{nvt::NVTField, Dispatcher, NoOpRetriever};

use crate::verify::{self, SignatureChecker, HashSumFileItem};
use crate::verify::{self, HashSumFileItem, SignatureChecker};

pub use self::error::ErrorKind;

Expand Down Expand Up @@ -69,16 +69,16 @@ pub fn feed_version<K: Default + AsRef<str>>(
Ok(feed_version)
}


impl<'a, R, S, L, V, K> SignatureChecker for Update<S, L, V, K>
where
S: Sync + Send + Dispatcher<K>,
K: AsRef<str> + Display + Default + From<String>,
L: Sync + Send + Loader + AsBufReader<File>,
V: Iterator<Item = Result<HashSumFileItem<'a, R>, verify::Error>>,
R: Read + 'a,
{}

{
}

impl<'a, S, L, V, K, R> Update<S, L, V, K>
where
S: Sync + Send + Dispatcher<K>,
Expand Down
240 changes: 240 additions & 0 deletions rust/models/src/advisories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// SPDX-FileCopyrightText: 2023 Greenbone AG
//
// SPDX-License-Identifier: GPL-2.0-or-later

use std::collections::HashMap;

/// Represents an advisory json file for notus product.
#[cfg_attr(feature = "serde_support", derive(serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct ProductsAdivisories {
/// Version of the advisory file
pub version: String,
/// SPDX license identifier
#[cfg_attr(feature = "serde_support", serde(rename = "spdx-license-identifier"))]
pub license_identifier: String,
/// Copyright
pub copyright: String,
/// Vulnerability Family
pub family: String,
/// List of Advisories
#[cfg_attr(feature = "serde_support", serde(default))]
pub advisories: Vec<Advisories>,
}

/// Represents an advisory json file for notus product.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct Advisories {
/// The advisory's title.
pub title: String,
/// The advisory's ID.
pub oid: String,
/// Creation Date
pub creation_date: u64,
/// Last modification date
pub last_modification: u64,
/// Advisory ID
pub advisory_id: String,
/// Advisory xref
pub advisory_xref: String,
/// List of cves
#[cfg_attr(feature = "serde_support", serde(default))]
pub cves: Vec<String>,
/// Summary
pub summary: String,
/// Insight
#[cfg_attr(feature = "serde_support", serde(default))]
pub insight: String,
/// Affected
pub affected: String,
/// Listo of xrefs
#[cfg_attr(feature = "serde_support", serde(default))]
pub xrefs: Vec<String>,
/// Quality of detection
pub qod_type: String,
/// Severity
pub severity: Severity,
}

/// A single vulnerability from an advisory file to be stored
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize)
)]
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Vulnerability {
/// VT Parameters
pub vt_params: Vec<String>,
/// Creation Date
pub creation_date: u64,
/// Last modification date
pub last_modification: u64,
/// Summary
pub summary: String,
/// Impact
pub impact: String,
/// Affected
pub affected: String,
/// Insight
pub insight: String,
/// Solution
pub solution: String,
/// Solution Type
pub solution_type: String,
/// Vuldetect
pub vuldeterct: String,
/// Quality of detection
pub qod_type: String,
/// Severity vector
pub severity_vector: String,
/// File name
pub filename: String,
/// All references: xrefs, cves, xrefs, advisory xrefs and advisory id.
pub refs: HashMap<String, Vec<String>>,
/// Vulnerability Family
pub family: String,
/// Title
pub name: String,
/// Category
pub category: String,
}

/// Severity
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize)
)]
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Severity {
/// Origin of the severity
pub origin: String,
/// severity date
pub date: u64,
/// Cvss version v2
#[cfg_attr(
feature = "serde_support",
serde(skip_serializing_if = "Option::is_none")
)]
pub cvss_v2: Option<String>,
/// cvss vector v3
#[cfg_attr(
feature = "serde_support",
serde(skip_serializing_if = "Option::is_none")
)]
pub cvss_v3: Option<String>,
}

pub struct ProductsAdivisoriesIterator<'a> {
products_advisories: &'a ProductsAdivisories,
index: usize,
}

impl<'a> Iterator for ProductsAdivisoriesIterator<'a> {
type Item = &'a Advisories;

fn next(&mut self) -> Option<&'a Advisories> {
if self.index < self.products_advisories.advisories.len() {
let result = Some(&self.products_advisories.advisories[self.index]);
self.index += 1;
result
} else {
None
}
}
}

impl ProductsAdivisories {
pub fn iter(&self) -> ProductsAdivisoriesIterator {
ProductsAdivisoriesIterator {
products_advisories: self,
index: 0,
}
}
}

pub struct VulnerabilityData<'a> {
pub adv: &'a Advisories,
pub product_data: &'a ProductsAdivisories,
pub filename: &'a String,
}

impl<'a> From<&VulnerabilityData<'a>> for Vulnerability {
fn from(data: &VulnerabilityData<'a>) -> Self {
let sv = match &data.adv.severity.cvss_v2 {
Some(cvss) => cvss,
None => match &data.adv.severity.cvss_v3 {
Some(cvss) => cvss,
None => "",
},
};

let refs = HashMap::new();
Self {
vt_params: Vec::new(),
creation_date: data.adv.creation_date,
last_modification: data.adv.last_modification,
summary: data.adv.summary.to_owned(),
impact: "".to_string(),
affected: data.adv.affected.to_owned(),
insight: data.adv.insight.to_owned(),
solution: "Please install the updated package(s).".to_string(),
solution_type: "VendorFix".to_string(),
vuldeterct: "Checks if a vulnerable package version is present on the target host."
.to_string(),
qod_type: data.adv.qod_type.to_owned(),
severity_vector: sv.to_string(),
filename: data.filename.to_string(),
refs,
family: data.product_data.family.to_owned(),
name: data.adv.title.to_owned(),
category: "3".to_string(),
}
}
}

//impl Vulnerability {
nichtsfrei marked this conversation as resolved.
Show resolved Hide resolved
//
// fn serialize<S> (&self, serializer: S) -> std::result::Result<Vec<<S as Serializer>::SerializeStruct>, S::Error>
// where
// S: Serializer,
// {
// let mut advisories: Vec<<S as Serializer>::SerializeStruct> = Vec::new();
// for advisory in self.advisories.iter() {
//
// let mut adv = serializer.serialize_struct("ProductAdvisories", 5)?;
//
// adv.serialize_field("vt_params", "[]")?;
// adv.serialize_field("creation_date", &advisory.creation_date)?;
// adv.serialize_field("last_modification", &advisory.last_modification)?;
// adv.serialize_field("summary", &advisory.summary)?;
// adv.serialize_field("impact", "")?;
// adv.serialize_field("affected", &advisory.affected)?;
// adv.serialize_field("insight", &advisory.insight)?;
// adv.serialize_field("solution", "Please install the updated package(s).")?;
// adv.serialize_field("solution_type", "VendorFix")?;
// adv.serialize_field("vuldetect", "Checks if a vulnerable package version is present on the target host.")?;
// adv.serialize_field("qod_type", &advisory.qod_type)?;
// match &advisory.severity.cvss_v2 {
// Some (cvss) => adv.serialize_field("severity_vector", cvss)?,
// None => match &advisory.severity.cvss_v3
// {
// Some (cvss) => adv.serialize_field("severity_vector", cvss)?,
// None => adv.serialize_field("severity_vector", "")?,
// }
// };
// adv.serialize_field("severity_vector", &advisory.severity)?;
// adv.serialize_field("filename", &self.filename)?;
// adv.serialize_field("family", &self.family)?;
//
//
// }
//
// Ok(advisories)
//
//
// }
//}
2 changes: 2 additions & 0 deletions rust/models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: GPL-2.0-or-later

mod advisories;
mod credential;
mod host_info;
mod parameter;
Expand All @@ -15,6 +16,7 @@ mod status;
mod target;
mod vt;

pub use advisories::*;
pub use credential::*;
pub use host_info::*;
pub use parameter::*;
Expand Down
1 change: 1 addition & 0 deletions rust/nasl-builtin-knowledge-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ fn get_kb_item<K>(register: &Register, c: &Context<K>) -> Result<NaslValue, Func
.map(|r| {
r.into_iter().find_map(|x| match x {
Field::NVT(_) => None,
Field::NOTUS(_) => None,
Field::KB(kb) => kb.value.into(),
})
})
Expand Down
1 change: 1 addition & 0 deletions rust/nasl-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ tracing-subscriber = { version = "0.3.17" }
serde_json = "1.0.96"
toml = "0.8.6"
serde = "1.0.190"
notus = { version = "0.1.0", path = "../notus" }


[features]
Expand Down
18 changes: 18 additions & 0 deletions rust/nasl-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ Hello, world!

Usage: `nasl-cli execute [OPTIONS] [-t HOST] <script>`

### notus
Load up Notus Advisories into redis.
It performs the signature check, the hashsum check and the upload.

Signature check is optional. It must be enabled with the command line option but also the environment variable `GPGHOME` to the gnupg keyring must be set.

Usage:
`GPGHOME=/path/to/.gnupg nasl-cli notus update --path <path-to-the-advisories> --signature-check`
#### update
Updates notus data into redis

Usage: nasl-cli notus update [OPTIONS] --path <FILE>

Options:
-p, --path <directory> Path to the notus advisories.
-x, --signature-check Enable NASL signature check.
-r, --redis <VALUE> Redis url. Must either start `unix://` or `redis://`.
-h, --help Print help

### feed

Expand Down
16 changes: 10 additions & 6 deletions rust/nasl-cli/src/feed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use std::{io, path::PathBuf};
use clap::{arg, value_parser, ArgAction, Command};
// re-export to work around name conflict


use redis_storage::FEEDUPDATE_SELECTOR;

use storage::StorageError;

use crate::{get_path_from_openvas, read_openvas_config, CliError, CliErrorKind};
Expand Down Expand Up @@ -72,12 +75,13 @@ pub fn run(root: &clap::ArgMatches) -> Option<Result<(), CliError>> {
.cloned()
.unwrap_or(false);

let dispatcher = redis_storage::NvtDispatcher::as_dispatcher(&redis)
.map_err(StorageError::from)
.map_err(|e| CliError {
kind: e.into(),
filename: format!("{path:?}"),
});
let dispatcher =
redis_storage::NvtDispatcher::as_dispatcher(&redis, FEEDUPDATE_SELECTOR)
.map_err(StorageError::from)
.map_err(|e| CliError {
kind: e.into(),
filename: format!("{path:?}"),
});
Some(dispatcher.and_then(|dispatcher| update::run(dispatcher, path, signature_check)))
}
Some(("transform", args)) => {
Expand Down
5 changes: 4 additions & 1 deletion rust/nasl-cli/src/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use nasl_interpreter::{
load_non_utf8_path, logger::DefaultLogger, logger::NaslLogger, ContextBuilder, FSPluginLoader,
Interpreter, KeyDispatcherSet, LoadError, Loader, NaslValue, NoOpLoader, RegisterBuilder,
};
use redis_storage::FEEDUPDATE_SELECTOR;
use storage::{DefaultDispatcher, Dispatcher, Retriever};

use crate::{CliError, CliErrorKind, Db};
Expand All @@ -26,7 +27,9 @@ impl Run<String> {
Db::InMemory => ContextBuilder::new(key, Box::<DefaultDispatcher<String>>::default()),
Db::Redis(url) => ContextBuilder::new(
key,
Box::new(redis_storage::NvtDispatcher::as_dispatcher(url).unwrap()),
Box::new(
redis_storage::NvtDispatcher::as_dispatcher(url, FEEDUPDATE_SELECTOR).unwrap(),
),
),
};

Expand Down
Loading
Loading