From 68b9a99aa3ce4a49ad1ab45cc9db839edd5bb585 Mon Sep 17 00:00:00 2001 From: cn-kali-team Date: Wed, 26 Jul 2023 15:47:23 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=87=8D=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/src/cve.rs | 27 ++++------- cve/src/cvss.rs | 63 +++++------------------- cve/src/node.rs | 125 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 117 insertions(+), 98 deletions(-) diff --git a/cve/src/cve.rs b/cve/src/cve.rs index e201b1c..fa62b90 100644 --- a/cve/src/cve.rs +++ b/cve/src/cve.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; // 单个CVE信息 #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] #[allow(clippy::upper_case_acronyms)] pub struct CVEItem { // CVE 信息 @@ -12,57 +13,45 @@ pub struct CVEItem { // 配置 pub configurations: Configurations, // 公开时间 - #[serde(rename = "publishedDate")] pub published_date: String, // 最后修改时间 - #[serde(rename = "lastModifiedDate")] pub last_modified_date: String, } #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Impact { // TODO: Implement V1? // cvssV2 过期 - #[serde(rename = "baseMetricV2")] - pub metric_v2: Option, + pub base_metric_v2: Option, // cvssV3 - #[serde(rename = "baseMetricV3")] - pub metric_v3: Option, + pub base_metric_v3: Option, // TODO: Implement V4? } #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct ImpactMetricV2 { - #[serde(rename = "cvssV2")] - pub cvss: cvss::v2::CVSS, + pub cvss_v2: cvss::v2::CVSS, // 漏洞的可利用 评分 - #[serde(rename = "exploitabilityScore")] pub exploitability_score: f32, // 评分 - #[serde(rename = "impactScore")] pub impact_score: f32, // 评级 pub severity: String, - #[serde(rename = "acInsufInfo")] pub ac_insuf_info: Option, - #[serde(rename = "obtainAllPrivilege")] pub obtain_all_privilege: bool, - #[serde(rename = "obtainUserPrivilege")] pub obtain_user_privilege: bool, - #[serde(rename = "obtainOtherPrivilege")] pub obtain_other_privilege: bool, // 用户交互 - #[serde(rename = "userInteractionRequired")] pub user_interaction_required: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct ImpactMetricV3 { - #[serde(rename = "cvssV3")] - pub cvss: cvss::v3::CVSS, + pub cvss_v3: cvss::v3::CVSS, // 漏洞的可利用 评分 - #[serde(rename = "exploitabilityScore")] pub exploitability_score: f32, // cvss 评分 - #[serde(rename = "impactScore")] pub impact_score: f32, } diff --git a/cve/src/cvss.rs b/cve/src/cvss.rs index 08fc929..97a67b1 100644 --- a/cve/src/cvss.rs +++ b/cve/src/cvss.rs @@ -6,127 +6,104 @@ pub mod v3 { use serde::{Deserialize, Serialize}; // AV #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum AttackVectorType { // AV:N - #[serde(rename = "NETWORK")] Network, // AV:A - #[serde(rename = "ADJACENT_NETWORK")] AdjacentNetwork, // AV:L - #[serde(rename = "LOCAL")] Local, // AV:P - #[serde(rename = "PHYSICAL")] Physical, } // AC #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum AttackComplexityType { // AC:H - #[serde(rename = "HIGH")] High, // AC:L - #[serde(rename = "LOW")] Low, } // PR #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum PrivilegesRequiredType { // PR:H - #[serde(rename = "HIGH")] High, // PR:L - #[serde(rename = "LOW")] Low, // PR:N - #[serde(rename = "NONE")] None, } // UI #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum UserInteractionType { // UI:R - #[serde(rename = "REQUIRED")] Required, // UI:N - #[serde(rename = "NONE")] None, } // CIA 影响指标 原json schema为ciaType #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum ImpactMetricsType { - #[serde(rename = "HIGH")] High, - #[serde(rename = "LOW")] Low, - #[serde(rename = "NONE")] None, } // S #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum ScopeType { // S:U - #[serde(rename = "UNCHANGED")] Unchanged, // S:C - #[serde(rename = "CHANGED")] Changed, } // 严重性 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum SeverityType { // 未校正 - #[serde(rename = "NONE")] None, // 低危 - #[serde(rename = "LOW")] Low, // 中危 - #[serde(rename = "MEDIUM")] Medium, // 高危 - #[serde(rename = "HIGH")] High, // 严重 - #[serde(rename = "CRITICAL")] Critical, } #[derive(Debug, Serialize, Deserialize, Clone)] + #[serde(rename_all = "camelCase")] pub struct CVSS { // 版本: 3.0 和 3.1 pub version: String, // 向量: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H" - #[serde(rename = "vectorString")] pub vector_string: String, // 访问途径(AV) - #[serde(rename = "attackVector")] pub attack_vector: AttackVectorType, // 攻击复杂度(AC) - #[serde(rename = "attackComplexity")] pub attack_complexity: AttackComplexityType, // 所需权限(PR) - #[serde(rename = "privilegesRequired")] pub privileges_required: PrivilegesRequiredType, // 用户交互(UI) - #[serde(rename = "userInteraction")] pub user_interaction: UserInteractionType, // 影响范围(S) pub scope: ScopeType, // 机密性影响(C) - #[serde(rename = "confidentialityImpact")] pub confidentiality_impact: ImpactMetricsType, // 完整性影响(I) - #[serde(rename = "integrityImpact")] pub integrity_impact: ImpactMetricsType, // 可用性影响(A) - #[serde(rename = "availabilityImpact")] pub availability_impact: ImpactMetricsType, // 基础评分 - #[serde(rename = "baseScore")] pub base_score: f64, // 基础评级 - #[serde(rename = "baseSeverity")] pub base_severity: SeverityType, } } @@ -136,79 +113,65 @@ pub mod v2 { use serde::{Deserialize, Serialize}; // AV #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum AccessVectorType { // AV:N - #[serde(rename = "NETWORK")] Network, // AV:A - #[serde(rename = "ADJACENT_NETWORK")] AdjacentNetwork, // AV:L - #[serde(rename = "LOCAL")] Local, } // AC #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum AccessComplexityType { // AC:H - #[serde(rename = "HIGH")] High, // AC:M - #[serde(rename = "MEDIUM")] Medium, // AC:L - #[serde(rename = "LOW")] Low, } // Au #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum AuthenticationType { // Au:M - #[serde(rename = "MULTIPLE")] Multiple, // Au:S - #[serde(rename = "SINGLE")] Single, // Au:N - #[serde(rename = "NONE")] None, } // CIA 影响指标 原json schema为ciaType #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] + #[serde(rename_all = "UPPERCASE")] pub enum ImpactMetricsType { - #[serde(rename = "NONE")] None, - #[serde(rename = "PARTIAL")] Partial, - #[serde(rename = "COMPLETE")] Complete, } #[derive(Debug, Serialize, Deserialize, Clone)] + #[serde(rename_all = "camelCase")] pub struct CVSS { // 版本 pub version: String, // 向量: CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:C/A:C - #[serde(rename = "vectorString")] pub vector_string: String, // 访问向量 - #[serde(rename = "accessVector")] pub access_vector: AccessVectorType, // 访问复杂性 - #[serde(rename = "accessComplexity")] pub access_complexity: AccessComplexityType, // 认证 pub authentication: AuthenticationType, // 完整性影响(I) - #[serde(rename = "confidentialityImpact")] pub confidentiality_impact: ImpactMetricsType, // 完整性影响(I) - #[serde(rename = "integrityImpact")] pub integrity_impact: ImpactMetricsType, // 可用性影响(A) - #[serde(rename = "availabilityImpact")] pub availability_impact: ImpactMetricsType, // 基础评分 - #[serde(rename = "baseScore")] pub base_score: f64, } } diff --git a/cve/src/node.rs b/cve/src/node.rs index ff22490..5018165 100644 --- a/cve/src/node.rs +++ b/cve/src/node.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Node { // 逻辑操作符 @@ -8,47 +8,25 @@ pub struct Node { // CPE 匹配列表 pub cpe_match: Vec, } -// 字符串或者解析后的,如果想解析需要开启cpe特性 -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(untagged)] -pub enum CPE23 { - #[cfg(not(feature = "cpe"))] - Value(String), - #[cfg(feature = "cpe")] - #[serde(deserialize_with = "cpe::dictionary::uri_to_attribute")] - Attributes(cpe::CPEAttributes), -} - -fn cpe23_string_serialize(cpe: &CPE23, s: S) -> Result -where - S: Serializer, -{ - match cpe { - #[cfg(not(feature = "cpe"))] - CPE23::Value(v) => s.serialize_str(v), - #[cfg(feature = "cpe")] - CPE23::Attributes(c) => s.serialize_str(&c.to_string()), - } -} #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Match { // 是否存在漏洞 pub vulnerable: bool, // CPE - #[serde(rename = "cpe23Uri", serialize_with = "cpe23_string_serialize")] - pub cpe23_uri: CPE23, + #[serde( + serialize_with = "cpe::dictionary::attribute_to_uri", + deserialize_with = "cpe::dictionary::uri_to_attribute" + )] + pub cpe23_uri: cpe::CPEAttributes, // 包括 从版本开始 - #[serde(rename = "versionStartIncluding")] pub version_start_including: Option, // 排除 从版本开始 - #[serde(rename = "versionStartExcluding")] pub version_start_excluding: Option, // 包括 到版本结束 - #[serde(rename = "versionEndIncluding")] pub version_end_including: Option, // 排除 到版本结束 - #[serde(rename = "versionEndExcluding")] pub version_end_excluding: Option, } @@ -58,3 +36,92 @@ pub enum Operator { And, Or, } + +impl Match { + pub fn has_version_range(&self) -> bool { + self.version_start_including.is_some() + || self.version_start_excluding.is_some() + || self.version_end_including.is_some() + || self.version_end_excluding.is_some() + } + + pub fn match_version_range(&self, ver: &str) -> bool { + if let Some(start_inc) = &self.version_start_including { + if !cpe::version_cmp(ver, start_inc, ">=") { + return false; + } + } + + if let Some(start_exc) = &self.version_start_excluding { + if !cpe::version_cmp(ver, start_exc, ">") { + return false; + } + } + + if let Some(end_inc) = &self.version_end_including { + if !cpe::version_cmp(ver, end_inc, "<=") { + return false; + } + } + + if let Some(end_exc) = &self.version_end_excluding { + if !cpe::version_cmp(ver, end_exc, "<") { + return false; + } + } + true + } + + pub fn is_match(&self, product: &str, version: &str) -> bool { + if self.cpe23_uri.match_product(product) { + if self.has_version_range() { + return self.match_version_range(version); + } + return self.cpe23_uri.match_version(version); + } + false + } +} + +impl Node { + pub fn is_match(&self, product: &str, version: &str) -> bool { + if !self.cpe_match.is_empty() { + match &self.operator { + Operator::Or => { + for cpe_match in &self.cpe_match { + if cpe_match.is_match(product, version) { + return true; + } + } + } + Operator::And => { + for cpe_match in &self.cpe_match { + if !cpe_match.is_match(product, version) { + return false; + } + } + return true; + } + } + } else { + match &self.operator { + Operator::Or => { + for child in &self.children { + if child.is_match(product, version) { + return true; + } + } + } + Operator::And => { + for child in &self.children { + if !child.is_match(product, version) { + return false; + } + } + return true; + } + } + } + false + } +}