| Security-CVSS documentation | Contained in the Security-CVSS distribution. |
Security::CVSS - Calculate CVSS values (Common Vulnerability Scoring System)
use Security::CVSS;
my $CVSS = new Security::CVSS;
$CVSS->AccessVector('Local');
$CVSS->AccessComplexity('High');
$CVSS->Authentication('Not-Required');
$CVSS->ConfidentialityImpact('Complete');
$CVSS->IntegrityImpact('Complete');
$CVSS->AvailabilityImpact('Complete');
$CVSS->ImpactBias('Normal');
my $BaseScore = $CVSS->BaseScore();
$CVSS->Exploitability('Proof-Of-Concept');
$CVSS->RemediationLevel('Official-Fix');
$CVSS->ReportConfidence('Confirmed');
my $TemporalScore = $CVSS->TemporalScore()
$CVSS->CollateralDamagePotential('None');
$CVSS->TargetDistribution('None');
my $EnvironmentalScore = $CVSS->EnvironmentalScore();
my $CVSS = new CVSS({AccessVector => 'Local',
AccessComplexity => 'High',
Authentication => 'Not-Required',
ConfidentialityImpact => 'Complete',
IntegrityImpact => 'Complete',
AvailabilityImpact => 'Complete',
ImpactBias => 'Normal'
});
my $BaseScore = $CVSS->BaseScore();
$CVSS->UpdateFromHash({AccessVector => 'Remote',
AccessComplexity => 'Low');
my $NewBaseScore = $CVSS->BaseScore();
$CVSS->Vector('(AV:L/AC:H/Au:NR/C:N/I:P/A:C/B:C)');
my $BaseScore = $CVSS->BaseScore();
my $Vector = $CVSS->Vector();
CVSS allows you to calculate all three types of score described under the CVSS system: Base, Temporal and Environmental.
You can modify any parameter via its accessor and recalculate at any time.
The temporal score depends on the base score, and the environmental score depends on the temporal score. Therefore you must remember to supply all necessary parameters.
Vector allows you to parse a CVSS vector as described at: http://nvd.nist.gov/cvss.cfm?vectorinfo
Called without any parameters it will return the CVSS vector as a string.
For meaning of these values see the official CVSS FAQ at https://www.first.org/cvss/faq/#c7
AccessVector Local, Remote AccessComplexity Low, High Authentication Required, Not-Required ConfidentialityImpact None, Partial, Complete IntegrityImpact None, Partial, Complete AvailabilityImpact None, Partial, Complete
Exploitability Unproven, Proof-of-Concept, Functional, High
RemediationLevel Official-Fix, Temporary-Fix, Workaround,
Unavailable
ReportConfidence Unconfirmed, Uncorroborated, Confirmed
CollateralDamagePotential None, Low, Medium, High TargetDistribution None, Low, Medium, High
This module is based on the formulas supplied at: http://www.first.org/cvss/
Periscan LLC, <cpan@periscan.com>
Copyright 2006 by Periscan LLC
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Security-CVSS documentation | Contained in the Security-CVSS distribution. |
package Security::CVSS; use 5.008; use strict; use warnings; use Module::Check_Args; use Carp qw( croak ); our $VERSION = '0.3'; our %BASE_PARAMS = ( AccessVector => {Params => {'remote' => 1, 'local' => 0.7}, P2V => {'remote' => 'R', 'local' => 'L'}}, AccessComplexity => {Params => {'low' => 1, 'high' => 0.8}, P2V => {'low' => 'L', 'high' => 'H'}}, Authentication => {Params => {'required' => 0.6, 'not-required' => 1}, P2V => {'required' => 'R', 'not-required' => 'NR'}}, ConfidentialityImpact => {Params => {'none' => 0, 'partial' => 0.7, 'complete' => 1}, P2V => {'none' => 'N', 'partial' => 'P', 'complete' => 'C'}}, IntegrityImpact => {Params => {'none' => 0, 'partial' => 0.7, 'complete' => 1}, P2V => {'none' => 'N', 'partial' => 'P', 'complete' => 'C'}}, AvailabilityImpact => {Params => {'none' => 0, 'partial' => 0.7, 'complete' => 1}, P2V => {'none' => 'N', 'partial' => 'P', 'complete' => 'C'}}, ImpactBias => {Params => {'normal' => 1, 'confidentiality' => 1, 'integrity' => 1, 'availability' => 1}, P2V => {'normal' => 'N', 'confidentiality' => 'C', 'integrity' => 'I', 'availability' => 'A'}} ); _CreateV2P(\%BASE_PARAMS); our %TEMPORAL_PARAMS = ( Exploitability => {Params => {'unproven' => 0.85, 'proof-of-concept' => 0.9, 'functional' => 0.95, 'high' => 1}, P2V => {'unproven' => 'U', 'proof-of-concept' => 'P', 'functional' => 'F', 'high' => 'H'}}, RemediationLevel => {Params => {'official-fix' => 0.87, 'temporary-fix' => 0.9, 'workaround' => 0.95, 'unavailable' => 1}, P2V => {'official-fix' => 'O', 'temporary-fix' => 'T', 'workaround' => 'W', 'unavailable' => 'U'}}, ReportConfidence => {Params => {'unconfirmed' => 0.9, 'uncorroborated' => 0.95, 'confirmed' => 1}, P2V => {'unconfirmed' => 'U', 'uncorroborated' => 'Uc', 'confirmed' => 'C'}} ); _CreateV2P(\%TEMPORAL_PARAMS); our %ENVIRONMENTAL_PARAMS = ( CollateralDamagePotential => {Params => {'none' => 0, 'low' => 0.1, 'medium' => 0.3, 'high' => 0.5}}, TargetDistribution => {Params => {'none' => 0, 'low' => 0.25, 'medium' => 0.75, 'high' => 1}} ); our %ALL_PARAMS = (%BASE_PARAMS, %TEMPORAL_PARAMS, %ENVIRONMENTAL_PARAMS); # Create accessors for all parameters foreach my $Accessor (keys %ALL_PARAMS) { no strict 'refs'; *{"Security::CVSS::$Accessor"} = sub { exact_argcount(2); my $self = shift; $self->_ValidateParam($Accessor, @_); }; } sub new { range_argcount(1, 2); my $class = shift; my $Params = shift; my $self = bless({}, $class); if (defined($Params)) { $self->UpdateFromHash($Params); } return $self; } # Create the Vector-to-Param hash from the P2V hash sub _CreateV2P { exact_argcount(1); my $Params = shift; foreach my $Param (keys %$Params) { $Params->{$Param}->{V2P} = { map { $Params->{$Param}->{P2V}->{$_} => $_ } keys %{$Params->{$Param}->{P2V}} }; } } sub _ValidateParam { exact_argcount(3); my $self = shift; my $Param = shift; my $Value = shift; # If vector value - convert to full value if (exists($ALL_PARAMS{$Param}->{V2P}->{$Value})) { $Value = $ALL_PARAMS{$Param}->{V2P}->{$Value}; } else { $Value = lc($Value); } if (!grep(/^$Value$/i, keys %{$ALL_PARAMS{$Param}->{Params}})) { croak("Invalid value '$Value' for $Param"); } $self->{$Param} = $Value; } sub _ConvertToVectorValue { my $Value = shift; my @Words = split('-', $Value); my $VectorValue; foreach my $Word (@Words) { $VectorValue .= uc(substr($Word, 0, 1)); } } # Sets up the object from a vector in the format at: # http://nvd.nist.gov/cvss.cfm?vectorinfo sub Vector { range_argcount(1, 2); my ($self, $Vector) = @_; if (defined($Vector)) { if ($Vector !~ m#^\(AV:([RL])/AC:([HL])/Au:(R|NR)/C:([NPC])/I:([NPC])/A:([NPC])/B:([NCIA])(/E:([UPFH])/RL:([OTWU])/RC:(U|Uc|C))?\)#) { croak('Invalid CVSS vector'); } my %Values = ( AccessVector => $1, AccessComplexity => $2, Authentication => $3, ConfidentialityImpact => $4, IntegrityImpact => $5, AvailabilityImpact => $6, ImpactBias => $7 ); if (defined($8)) { # Has temporal portion %Values = ( %Values, Exploitability => $9, RemediationLevel => $10, ReportConfidence => $11 ); } $self->UpdateFromHash(\%Values); } else { # Check all parameters exist foreach my $Param (keys %BASE_PARAMS) { if (!defined($self->{$Param})) { croak("You must set '$Param' to output the CVSS vector"); } } my $VectorValue = sub { return $ALL_PARAMS{$_[0]}->{P2V}->{$self->{$_[0]}}; }; my $Vector = sprintf('AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s/B:%s', &$VectorValue('AccessVector'), &$VectorValue('AccessComplexity'), &$VectorValue('Authentication'), &$VectorValue('ConfidentialityImpact'), &$VectorValue('IntegrityImpact'), &$VectorValue('AvailabilityImpact'), &$VectorValue('ImpactBias')); my $Environmental = 1; foreach my $Param (keys %TEMPORAL_PARAMS) { if (!defined($self->{$Param})) { $Environmental = 0; last; } } if ($Environmental) { $Vector .= sprintf('/E:%s/RL:%s/RC:%s', &$VectorValue('Exploitability'), &$VectorValue('RemediationLevel'), &$VectorValue('ReportConfidence')); } return "($Vector)"; } } sub UpdateFromHash { exact_argcount(2); my ($self, $Params) = @_; if (ref($Params) ne 'HASH') { croak 'Parameter must be a hash reference'; } foreach my $Param (keys %$Params) { if (!exists($ALL_PARAMS{$Param})) { croak "$Param is not a valid parameter"; } $self->$Param($Params->{$Param}); } } sub BaseScore { exact_argcount(1); my $self = shift; # Check all parameters exist foreach my $Param (keys %BASE_PARAMS) { if (!defined($self->{$Param})) { croak("You must set '$Param' to calculate the Base CVSS score"); } } my $Score = 10; foreach my $Param ('AccessVector', 'AccessComplexity', 'Authentication') { $Score *= $BASE_PARAMS{$Param}->{Params}->{$self->{$Param}}; } # Calculate the impact portion of the score taking into account the weighting bias my $ImpactScore = 0; foreach my $ImpactType ('ConfidentialityImpact', 'IntegrityImpact', 'AvailabilityImpact') { my $Value = $BASE_PARAMS{$ImpactType}->{Params}->{$self->{$ImpactType}}; if ($self->{ImpactBias} . 'impact' eq lc($ImpactType)) { $Value *= 0.5; } elsif ($self->{ImpactBias} eq 'normal') { $Value *= 0.333; } else { $Value *= 0.25; } $ImpactScore += $Value; } $Score *= $ImpactScore; # Round to one sig fig return sprintf('%.1f', $Score); } sub TemporalScore { exact_argcount(1); my $self = shift; # Check all parameters exist foreach my $Param (keys %TEMPORAL_PARAMS) { if (!defined($self->{$Param})) { croak("You must set '$Param' to calculate the Temporal CVSS score"); } } my $Score = $self->BaseScore(); foreach my $Param (keys %TEMPORAL_PARAMS) { $Score *= $TEMPORAL_PARAMS{$Param}->{Params}->{$self->{$Param}}; } # Round to one sig fig return sprintf('%.1f', $Score); } sub EnvironmentalScore { exact_argcount(1); my $self = shift; # Check all parameters exist foreach my $Param (keys %ENVIRONMENTAL_PARAMS) { if (!defined($self->{$Param})) { croak("You must set '$Param' to calculate the Environmental CVSS score"); } } my $TemporalScore = $self->TemporalScore; my $Score = ($TemporalScore + ((10 - $TemporalScore) * $ENVIRONMENTAL_PARAMS{CollateralDamagePotential}->{Params}->{$self->{CollateralDamagePotential}})) * $ENVIRONMENTAL_PARAMS{TargetDistribution}->{Params}->{$self->{TargetDistribution}}; # Round to one sig fig return sprintf('%.1f', $Score); } 1; __END__