1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! CVSS v3.1 Base Metric Group - Attack Vector (AV)

use crate::{
    error::{Error, ErrorKind},
    v3::Metric,
};
use std::{fmt, str::FromStr};

/// Attack Vector (AV) - CVSS v3.1 Base Metric Group
///
/// Described in CVSS v3.1 Specification: Section 2.1.1:
/// <https://www.first.org/cvss/specification-document#t6>
///
/// > This metric reflects the context by which vulnerability exploitation
/// > is possible. This metric value (and consequently the Base Score) will be
/// > larger the more remote (logically, and physically) an attacker can be in
/// > order to exploit the vulnerable component. The assumption is that the
/// > number of potential attackers for a vulnerability that could be exploited
/// > from across a network is larger than the number of potential attackers
/// > that could exploit a vulnerability requiring physical access to a device,
/// > and therefore warrants a greater Base Score.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum AttackVector {
    /// Physical (P)
    ///
    /// > The attack requires the attacker to physically touch or manipulate
    /// > the vulnerable component. Physical interaction may be brief
    /// > (e.g., evil maid attack) or persistent. An example of such an attack
    /// > is a cold boot attack in which an attacker gains access to disk
    /// > encryption keys after physically accessing the target system.
    /// > Other examples include peripheral attacks via FireWire/USB Direct
    /// > Memory Access (DMA).
    Physical,

    /// Local (L)
    ///
    /// > The vulnerable component is not bound to the network stack and the
    /// > attacker’s path is via read/write/execute capabilities. Either:
    /// >
    /// > - the attacker exploits the vulnerability by accessing the target
    /// >   system locally (e.g., keyboard, console), or remotely (e.g., SSH)
    /// > - the attacker relies on User Interaction by another person to
    /// >   perform actions required to exploit the vulnerability (e.g., using
    /// >   social engineering techniques to trick a legitimate user into
    /// >   opening a malicious document).
    Local,

    /// Adjacent (A)
    ///
    /// > The vulnerable component is bound to the network stack, but the
    /// > attack is limited at the protocol level to a logically adjacent
    /// > topology. This can mean an attack must be launched from the same
    /// > shared physical (e.g., Bluetooth or IEEE 802.11) or logical
    /// > (e.g., local IP subnet) network, or from within a secure or
    /// > otherwise limited administrative domain (e.g., MPLS, secure VPN to
    /// > an administrative network zone). One example of an Adjacent attack
    /// > would be an ARP (IPv4) or neighbor discovery (IPv6) flood leading to
    /// > a denial of service on the local LAN segment (e.g., CVE‑2013‑6014).
    Adjacent,

    /// Network (N)
    ///
    /// > The vulnerable component is bound to the network stack and the set of
    /// > possible attackers extends beyond the other options listed below, up to
    /// > and including the entire Internet. Such a vulnerability is often
    /// > termed “remotely exploitable” and can be thought of as an attack being
    /// > exploitable at the protocol level one or more network hops away
    /// > (e.g., across one or more routers). An example of a network attack is
    /// > an attacker causing a denial of service (DoS) by sending a specially
    /// > crafted TCP packet across a wide area network (e.g., CVE‑2004‑0230).
    Network,
}

impl Metric for AttackVector {
    const NAME: &'static str = "AV";

    fn score(self) -> f64 {
        match self {
            AttackVector::Physical => 0.20,
            AttackVector::Local => 0.55,
            AttackVector::Adjacent => 0.62,
            AttackVector::Network => 0.85,
        }
    }

    fn as_str(self) -> &'static str {
        match self {
            AttackVector::Physical => "P",
            AttackVector::Local => "L",
            AttackVector::Adjacent => "A",
            AttackVector::Network => "N",
        }
    }
}

impl fmt::Display for AttackVector {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}", Self::NAME, self.as_str())
    }
}

impl FromStr for AttackVector {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Error> {
        match s {
            "P" => Ok(AttackVector::Physical),
            "L" => Ok(AttackVector::Local),
            "A" => Ok(AttackVector::Adjacent),
            "N" => Ok(AttackVector::Network),
            other => fail!(ErrorKind::Parse, "invalid AV (Base): {}", other),
        }
    }
}