完成扫描整体结果展示

Signed-off-by: Jia Chao <jiachao2130@126.com>
This commit is contained in:
Jia Chao 2024-08-06 11:32:38 +08:00
parent 946f13f35c
commit f82ff6ac72
5 changed files with 43478 additions and 45 deletions

View File

@ -6,6 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["derive"] } clap = { version = "4.0", features = ["derive"] }
serde = { version = "1", features = ["serde_derive"] } serde = { version = "1", features = ["serde_derive"] }
serde_json = { version = "1.0" }
toml = { version = "0.8" } toml = { version = "0.8" }
updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.0" } updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.0" }
cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" } cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" }

View File

@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use cvrf_xmlparser::{SaInfo, CVE}; use cvrf_xmlparser::{CUSA, CVE};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo}; use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
// PackageDb 从 updateinfo 中获取 // PackageDb 从 updateinfo 中获取
// 以包名为键,值为一个 Vector ,里面包含更新的不同版本的 rpm 包信息 // 以包名为键,值为一个 Vector ,里面包含更新的不同版本的 rpm 包信息
@ -13,9 +13,7 @@ pub struct PackgeDb {
impl PackgeDb { impl PackgeDb {
pub fn new() -> Self { pub fn new() -> Self {
PackgeDb { PackgeDb { db: HashMap::new() }
db: HashMap::new(),
}
} }
/// 从已有的 updateinfo 仓库文件中,获取所有与安全更新相关的软件包 /// 从已有的 updateinfo 仓库文件中,获取所有与安全更新相关的软件包
@ -43,24 +41,26 @@ impl PackgeDb {
// 其键为 SA id值为详情 // 其键为 SA id值为详情
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SaDb { pub struct SaDb {
db: HashMap<String, SaInfo>, db: HashMap<String, CUSA>,
} }
impl SaDb { impl SaDb {
pub fn new() -> Self { pub fn new() -> Self {
SaDb { SaDb { db: HashMap::new() }
db: HashMap::new(),
}
} }
/// 一般来自对 cvrf 文件解析并转换为 SaInfo 的文本数据文件 pub fn db(&self) -> &HashMap<String, CUSA> {
&self.db
}
/// 一般来自对 cvrf 文件解析并转换为 CUSA 的文本数据文件
pub fn load_from_file(&mut self, file: &str) -> crate::Result<()> { pub fn load_from_file(&mut self, file: &str) -> crate::Result<()> {
let data = std::fs::read_to_string(file)?; let data = std::fs::read_to_string(file)?;
self.db = toml::from_str(&data)?; self.db = serde_json::from_str(&data)?;
Ok(()) Ok(())
} }
/// 从 SaInfo 中提取出所有的 CVE 源 /// 从 CUSA 中提取出所有的 CVE 源
pub fn get_cvedb(&self) -> CveDb { pub fn get_cvedb(&self) -> CveDb {
let mut cvedb = CveDb::new(); let mut cvedb = CveDb::new();
@ -84,9 +84,7 @@ pub struct CveDb {
impl CveDb { impl CveDb {
#[allow(dead_code)] #[allow(dead_code)]
pub fn new() -> Self { pub fn new() -> Self {
CveDb { CveDb { db: HashMap::new() }
db: HashMap::new(),
}
} }
} }

View File

@ -1,18 +1,17 @@
use std::collections::HashSet; use std::collections::HashMap;
use std::str::FromStr;
use cvrf_xmlparser::{Severity, CUSA};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rpm_rs::rpm::{ use rpm_rs::rpm::{get_installed_packages, Package};
get_installed_packages,
Package,
};
use rpm_rs::rpmio::rpmvercmp; use rpm_rs::rpmio::rpmvercmp;
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo}; use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
use crate::analyzer::db::{CveDb, PackgeDb, SaDb};
use crate::cli::Cli; use crate::cli::Cli;
use crate::analyzer::db::PackgeDb;
lazy_static! { lazy_static! {
pub static ref update_pkgs: PackgeDb= { pub static ref update_pkgs: PackgeDb = {
let mut updatedb = UpdateInfoDb::new(); let mut updatedb = UpdateInfoDb::new();
updatedb.load_xml("test/updateinfo.xml").unwrap(); updatedb.load_xml("test/updateinfo.xml").unwrap();
@ -20,6 +19,13 @@ lazy_static! {
pkgdb.load_from_updateinfodb(&updatedb); pkgdb.load_from_updateinfodb(&updatedb);
pkgdb pkgdb
}; };
pub static ref sadb: SaDb = {
let mut _sadb = SaDb::new();
_sadb.load_from_file("test/cvrf_sainfos.json").unwrap();
_sadb
};
pub static ref cvedb: CveDb = sadb.get_cvedb();
} }
pub mod db; pub mod db;
@ -27,17 +33,17 @@ pub mod db;
pub fn cuvat_run(cli: &Cli) -> crate::Result<()> { pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
// 只报告 cve 相关 // 只报告 cve 相关
if cli.cves { if cli.cves {
return list_cves(cli) return list_cves(cli);
} }
// 只报告 sa 相关 // 只报告 sa 相关
if cli.sas { if cli.sas {
return list_sas(cli) return list_sas(cli);
} }
// 生成报告 // 生成报告
if cli.report { if cli.report {
return repoter(cli) return repoter(cli);
} }
// 默认报告格式 // 默认报告格式
@ -57,45 +63,87 @@ fn repoter(cli: &Cli) -> crate::Result<()> {
} }
fn summary(cli: &Cli) -> crate::Result<()> { fn summary(cli: &Cli) -> crate::Result<()> {
let mut sa_ids: HashSet<String> = HashSet::new(); let avaliable = get_avaliable()?;
let severity = Severity::from_str(&cli.severity)?;
let mut res = vec![0; 5];
for (cusa, rpms) in &avaliable {
// 过滤
if cusa.severity() < &severity {
continue;
}
let pos: usize = cusa.severity().into();
res[pos] += 1;
}
let msg = format!("
{:3}
{:3}
{:3}
{:3}
", res[4], res[3], res[2], res[1]);
println!("{}", msg);
Ok(())
}
// 获取当前可用的更新,所有安全检查均基于此
fn get_avaliable() -> crate::Result<HashMap<CUSA, Vec<RpmInfo>>> {
let mut avaliable: HashMap<CUSA, Vec<RpmInfo>> = HashMap::new();
// 当前系统所有已安装的 rpm 包 // 当前系统所有已安装的 rpm 包
let installed = get_installed_packages(); let installed = get_installed_packages();
// installed 已被消费掉 // installed 已被消费掉
// latest_installed 是所有最新版本软件包的 Vec // latest_installed 是所有最新版本软件包的 Vec
let latest_installed: Vec<Package> = installed.into_iter().map(|(_, pkgs)| { let latest_installed: Vec<Package> = installed
.into_iter()
.map(|(_, pkgs)| {
let mut latest = pkgs[0].clone(); let mut latest = pkgs[0].clone();
for pkg in pkgs.into_iter() { for pkg in pkgs.into_iter() {
latest = rpmdb_package_vercmp(latest, pkg); latest = rpmdb_package_vercmp(latest, pkg);
} }
latest latest
}).collect(); })
.collect();
// 获取 sa 更新列表 // 获取 sa 更新列表
for pkg in latest_installed { for pkg in latest_installed {
let name = pkg.name(); let name = pkg.name();
if let Some(updates) = update_pkgs.db().get(name) { if let Some(updates) = update_pkgs.db().get(name) {
for update in updates { for update in updates {
// 因 updateinfo 里包含所有架构,故于此做个判断
// 是否考虑架构信息在不同的版本有所不同?
if update.arch() != pkg.arch().unwrap() {
continue;
}
// epoch 判断 // epoch 判断
match (update.epoch(), pkg.epoch()) { match (update.epoch(), pkg.epoch()) {
(Some(_), None) => { (Some(_), None) => {
let _ = sa_ids.insert(update.sa().into()); _add_to_avaliable(&mut avaliable, update.sa(), update.clone());
}, }
(None, Some(_)) => continue, (None, Some(_)) => continue,
_ => {} _ => {}
} }
// evr 对比 // evr 对比
if rpmvercmp(&update.evr(), &pkg.evr()) > 0 { if rpmvercmp(&update.evr(), &pkg.evr()) > 0 {
sa_ids.insert(update.sa().into()); _add_to_avaliable(&mut avaliable, update.sa(), update.clone());
} }
} }
} }
} }
println!("{:#?}", sa_ids.len()); Ok(avaliable)
// TODO: sa -> { rpms, cves } }
Ok(()) fn _add_to_avaliable(avaliable: &mut HashMap<CUSA, Vec<RpmInfo>>, sa: &str, rpm: RpmInfo) {
let sainfo = sadb.db().get(sa).unwrap();
if let Some(rpms) = avaliable.get_mut(sainfo) {
rpms.push(rpm);
} else {
let rpms = vec![rpm];
avaliable.insert(sainfo.clone(), rpms);
}
} }
// 对比两个 rpm Package 的版本,返回最新的一个 // 对比两个 rpm Package 的版本,返回最新的一个
@ -104,12 +152,12 @@ fn rpmdb_package_vercmp(pa: Package, pb: Package) -> Package {
match (pa.epoch(), pb.epoch()) { match (pa.epoch(), pb.epoch()) {
(Some(_), None) => return pa, (Some(_), None) => return pa,
(None, Some(_)) => return pb, (None, Some(_)) => return pb,
_ => {}, // 继续往下对比 _ => {} // 继续往下对比
} }
if rpmvercmp(&pa.evr(), &pb.evr()) > 0 { if rpmvercmp(&pa.evr(), &pb.evr()) > 0 {
return pa return pa;
} else { } else {
return pb return pb;
} }
} }

View File

@ -30,8 +30,8 @@ pub struct Cli {
#[arg(action = clap::ArgAction::Append)] #[arg(action = clap::ArgAction::Append)]
pub sources: Vec<String>, pub sources: Vec<String>,
/// 设置过滤级别,由高到低为:[Critical, Important, Moderate, Low] /// 设置过滤级别,由高到低为:[Critical, High, Medium, Low, None]
#[arg(long, default_value_t = String::from("Low"))] #[arg(long, default_value_t = String::from("None"))]
pub severity: String, pub severity: String,
/// 生成漏洞扫描报告 /// 生成漏洞扫描报告

43386
test/cvrf_sainfos.json Normal file

File diff suppressed because one or more lines are too long