Skip to content

Commit

Permalink
feat(cli): richer scan reports
Browse files Browse the repository at this point in the history
  • Loading branch information
mrl5 committed Feb 2, 2022
1 parent 0e42c43 commit 23799cc
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ binaries or to symlink `~/.cargo/bin/vulner` to some place covered by PATH
$ ./scripts/check-runtime-deps.sh
$ vulner --help
$ RUST_LOG=debug vulner sync
$ RUST_LOG=info vulner scan
$ RUST_LOG=info vulner scan -o ~/vulner/scan-results
```


Expand Down
9 changes: 5 additions & 4 deletions crates/cli/src/command/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use cpe_tag::package::Package;
use cpe_tag::query_builder::{get_grep_patterns, query};
use os_adapter::adapter::get_adapter;
use reqwest::Client;
use security_advisories::cve_summary::CveSummary;
use security_advisories::http::get_client;
use security_advisories::service::{fetch_cves_by_cpe, get_cve_summary, CPE_MATCH_FEED};
use security_advisories::service::{fetch_cves_by_cpe, get_cves_summary, CPE_MATCH_FEED};
use std::error::Error;
use std::fs::create_dir_all;
use std::fs::File;
Expand Down Expand Up @@ -81,7 +82,7 @@ async fn handle_cves(
let mut already_notified = false;
for cpe in matches {
let cves = fetch_cves_by_cpe(client, cpe).await?;
let cves = get_cve_summary(&cves);
let cves = get_cves_summary(&cves);

if cves.is_empty() {
continue;
Expand All @@ -97,13 +98,13 @@ async fn handle_cves(
Ok(())
}

fn write_report(cwd: &Path, cpe: &str, cves: &[String]) -> Result<(), Box<dyn Error>> {
fn write_report(cwd: &Path, cpe: &str, cves: &[CveSummary]) -> Result<(), Box<dyn Error>> {
log::info!("saving report in {:?} ...", cwd.as_os_str());
create_dir_all(cwd)?;
let mut f = File::create(cwd.join(format!("{}.txt", cpe)))?;

for cve in cves {
log::debug!("{}", cve);
log::debug!("{}", cve.id);
writeln!(f, "{}", cve)?;
}
Ok(())
Expand Down
1 change: 1 addition & 0 deletions crates/security-advisories/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ indicatif = "0.16.2"
log = "0.4.14"
reqwest = { version = "0.11.9", features = ["gzip", "json", "stream"] }
serde_json = "1.0.78"
serde = "1.0.136"
tokio = { version = "1.15.0", features = ["fs"] }
37 changes: 37 additions & 0 deletions crates/security-advisories/src/cve_summary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use serde::Serialize;
use serde_json::to_string;
use std::fmt;

#[derive(Serialize, Debug)]
pub struct CveSummary {
pub id: String,
pub description: String,
pub urls: Vec<String>,
}

impl CveSummary {
pub fn new(id: String, description: String, urls: Vec<String>) -> Self {
Self {
id,
description,
urls,
}
}
}

impl fmt::Display for CveSummary {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
to_string(&self).unwrap_or_else(|_| "{}".to_owned())
)
}
}
1 change: 1 addition & 0 deletions crates/security-advisories/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

pub mod cve_summary;
pub mod http;
pub mod service;
mod utils;
5 changes: 3 additions & 2 deletions crates/security-advisories/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use crate::cve_summary::CveSummary;
use reqwest::Client;
use serde_json::Value;
use std::error::Error;
Expand All @@ -24,8 +25,8 @@ pub async fn fetch_feed_checksum(client: &Client) -> Result<String, Box<dyn Erro
nvd::fetch_feed_checksum(client).await
}

pub fn get_cve_summary(full_cve_resp: &Value) -> Vec<String> {
nvd::get_cve_summary(full_cve_resp)
pub fn get_cves_summary(full_cve_resp: &Value) -> Vec<CveSummary> {
nvd::get_cves_summary(full_cve_resp)
}

pub async fn download_cpe_match_feed(
Expand Down
43 changes: 40 additions & 3 deletions crates/security-advisories/src/service/nvd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use crate::cve_summary::CveSummary;
use crate::utils::get_progress_bar;
use futures_util::StreamExt;
use reqwest::Client;
Expand Down Expand Up @@ -34,12 +35,13 @@ pub async fn fetch_cves_by_cpe(client: &Client, cpe: &str) -> Result<Value, Box<
Ok(json)
}

pub fn get_cve_summary(full_cve_resp: &Value) -> Vec<String> {
pub fn get_cves_summary(full_cve_resp: &Value) -> Vec<CveSummary> {
let mut ids = vec![];
if let Some(items) = full_cve_resp["result"]["CVE_Items"].as_array() {
for item in items {
if let Some(id) = item["cve"]["CVE_data_meta"]["ID"].as_str() {
ids.push(id.to_owned());
let cve_data = &item["cve"];
if let Some(summary) = get_cve_summary(cve_data) {
ids.push(summary);
}
}
}
Expand Down Expand Up @@ -107,6 +109,41 @@ fn get_checksum(meta: String) -> Result<String, io::Error> {
}
}

fn get_cve_summary(cve_data: &Value) -> Option<CveSummary> {
if let Some(id) = cve_data["CVE_data_meta"]["ID"].as_str() {
return Some(CveSummary::new(
id.to_owned(),
get_cve_desc(cve_data),
get_cve_urls(id, cve_data),
));
}
None
}

fn get_cve_desc(cve_data: &Value) -> String {
if let Some(descriptions) = cve_data["description"]["description_data"].as_array() {
if let Some(desc) = descriptions.iter().find(|x| x["lang"] == "en") {
if let Some(value) = desc["value"].as_str() {
return value.to_owned();
}
}
}
"".to_owned()
}

fn get_cve_urls(id: &str, cve_data: &Value) -> Vec<String> {
let nvd_url = "https://nvd.nist.gov/vuln/detail";
let mut urls = vec![format!("{}/{}", nvd_url, id)];

if let Some(ref_data) = cve_data["references"]["reference_data"].as_array() {
for url in ref_data.iter().map(|x| x["url"].as_str()).flatten() {
urls.push(url.to_owned());
}
}

urls
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
17 changes: 14 additions & 3 deletions docs/COOKBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,22 @@ $ tree ~/vulner/scan-results/
```
Report for particular package:
```bash
$ cat ~/vulner/scan-results/2022-01-30UTC/*/app-emulation/*containerd*.txt
$ cat ~/vulner/scan-results/2022-01-30UTC/*/app-emulation/*containerd*.txt | jq '.'
```
```
CVE-2021-43816
CVE-2021-41103
{
"id": "CVE-2021-41103",
"description": "A bug was found in containerd where container root directories and some plugins had insufficiently restricted permissions, allowing otherwise unprivileged Linux users to traverse directory contents and execute programs.",
,
"urls": [
"https://nvd.nist.gov/vuln/detail/CVE-2021-41103",
"https://github.com/containerd/containerd/commit/5b46e404f6b9f661a205e28d59c982d3634148f8",
"https://github.com/containerd/containerd/security/advisories/GHSA-c2h3-6mxw-7mvq",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZNFADTCHHYWVM6W4NJ6CB4FNFM2VMBIB/",
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/B5Q6G6I4W5COQE25QMC7FJY3I3PAYFBB/",
"https://www.debian.org/security/2021/dsa-5002"
]
}
```


Expand Down

0 comments on commit 23799cc

Please sign in to comment.