Skip to content

Commit

Permalink
Add: nasl-cli notus update subcommand (#1558)
Browse files Browse the repository at this point in the history
* Add: nasl-cli notus update subcommand

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 to the gnupg keyring must be set.

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

* remove swap files and unnecessary commented code

* Change: Rename NvtDispatcher by CacheDispatcher

Since it is no not only for Nvts but also for Notus advisories.

* Change: Load both notus and vts caches with `nasl-cli feed update`

instead of having two subcommands.

* Change: run feed-verifier with --nvt-only option

* Fix: CI. Update zlib version to 1.3.1
  • Loading branch information
jjnicola authored Jan 25, 2024
1 parent 476cc3f commit d399537
Show file tree
Hide file tree
Showing 23 changed files with 583 additions and 55 deletions.
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.

4 changes: 2 additions & 2 deletions rust/cross.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ RUN ./configure --host=x86_64-unknown-linux-gnu --with-pcap=linux
RUN cat config.log
RUN make install

RUN curl --output /tmp/zlib.tar.gz https://www.zlib.net/zlib-1.3.tar.gz
RUN curl --output /tmp/zlib.tar.gz https://www.zlib.net/zlib-1.3.1.tar.gz
WORKDIR /tmp
RUN tar xvf zlib.tar.gz
WORKDIR /tmp/zlib-1.3
WORKDIR /tmp/zlib-1.3.1
RUN ./configure
RUN make install
RUN ldconfig
Expand Down
4 changes: 2 additions & 2 deletions rust/cross_aarch64.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ RUN ./configure --host=aarch64-unknown-linux-gnu --with-pcap=linux
RUN cat config.log
RUN make install

RUN curl --output /tmp/zlib.tar.gz https://www.zlib.net/zlib-1.3.tar.gz
RUN curl --output /tmp/zlib.tar.gz https://www.zlib.net/zlib-1.3.1.tar.gz
WORKDIR /tmp
RUN tar xvzf zlib.tar.gz
WORKDIR /tmp/zlib-1.3
WORKDIR /tmp/zlib-1.3.1
RUN ./configure
RUN make install
RUN ldconfig
Expand Down
2 changes: 1 addition & 1 deletion rust/feed-verifier/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ fn main() {
};
let (ncd, nasl_cli) = run_get(
&mut kb,
&format!("{} feed update", nasl_cli.to_str().unwrap_or_default()),
&format!("{} feed update --vts-only", nasl_cli.to_str().unwrap_or_default()),
)
.expect("results");
let mut errors = 0;
Expand Down
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
197 changes: 197 additions & 0 deletions rust/models/src/advisories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// 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(),
}
}
}
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
14 changes: 11 additions & 3 deletions rust/nasl-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ Hello, world!

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


### feed

Handles feed related tasks.
Expand All @@ -48,19 +47,28 @@ Usage: `nasl-cli feed <COMMAND>`
#### update

Runs nasl scripts in description mode and updates data into redis so that ospd-openvas can read the data.
Also, load the Notus advisories up into the redis cache. The path to the notus advisories must be provided.

When either path or redis is not set it will get the defaults by calling `openvas -s`.

Usage `nasl-cli feed update [OPTIONS]`

Usage example, load both:
`GPGHOME=/path/to/.gnupg nasl-cli feed update --notus-path <path-to-the-advisories> --signature-check`

Options:
- `-p`, `--path <FILE>`: Path to the feed.
- `-r`, `--redis <VALUE>`: Redis url. Must either start `unix://` or `redis://`.
- `-v`, `--vts-only`: Load only nvts into redis cache
- `-n`, `--notus-only`: Load only Notus advisories into redis cache
- `--vts-path <FILE>`: Path to the feed.
- `--notus-path <FILE>`: Path to the notus advisories.
- `-x`, `--signature-check`: Enable NASL signature check.
- `-r`, `--redis <VALUE>`: Redis url. Must either start `unix://` or `redis://`.

On `feed update` it will first read the `sha256sums` file within the feed directory and verify each file with the corresponding sha256sums. When the hash is correct it will execute each mentioned `*.nasl` script within that dir with `description = 1`.
Optionally, it is possible to perform a signature verification of the sha256sums file before uploading. To perform the signature check, also the environment variable `GNUPGHOME` must be set with the gnupg home directory, where the `pubring.kbx` file is stored.

Notus advisories and VTs can be uploaded independtently using the options `--vts-only` and `--notus-only` respectively. They can not be used together.

#### transform
Runs nasl scripts in description mode and returns it as a json array into stdout.

Expand Down
Loading

0 comments on commit d399537

Please sign in to comment.