import * as fs from 'fs' ; import * as yaml from 'js-yaml' ; export enum impact { None = 'None' , Low = 'Low' , Medium = 'Medium' , High = 'High' } enum exploitabilityImpact { VeryLow = 'Very Low' , Low = 'Low' , Moderate = 'Moderate' , High = 'High' } export enum attackVector { Local = 'Local' , Remote = 'Remote' } export enum scopeImpact { None = 'Container' , Container = 'Container' , Host = 'Host' , Cluster = 'Cluster' } enum riskCategory { Low = 2 , Medium = 5 , High = 10 } export interface Impact { impact : impact ; description : string ; } interface Exploitability { impact : exploitabilityImpact ; description : string ; } export interface AttackVector { impact : attackVector ; description : string ; } ; export interface Scope { impact : scopeImpact ; category : string ; description : string ; } var impactScore = { High : 0.56 , Low : 0.22 , None : 0 } ; const scopeFactor = { Container : 0.25 , None : 0.25 , Host : 1.0 , Cluster : 1.0 } ; const attackVectorFactor = { Remote : 0.85 , Local : 0.55 } ; const exploitabilityFactor = { High : 0.54 , Moderate : 0.4 , Low : 0.1 , 'Very Low' : 0.05 , VeryLow : 0.05 } ; const impactConst = 4 ; const exploitabilityConst = 9 ; export class Rule { name : string = '' ; type : string = 'rremediation' ; id : string = '' ; revision : number = 1 ; category : string = '' ; rule : string = '' ; title : string = '' ; description : string = '' ; shortDescription : string = '' ; availability : Impact = { impact : impact . None , description : "" } ; confidentiality : Impact = { impact : impact . None , description : "" } ; integrity : Impact = { impact : impact . None , description : "" } ; scope : Scope = { impact : scopeImpact . None , category : "" , description : "" } ; attackVector : AttackVector = { impact : attackVector . Local , description : "" } ; vector : string = "" ; references ? : any ; protected file : string = "" ; protected getImpact ( doc ) { var result = { impact : impact . None , description : "" } ; result . impact = impact [ < impact > doc . impact ] ; result . description = doc . description ? doc . description : '' ; return result ; } protected getAttackVector ( doc ) { var result = { impact : attackVector . Local , description : "" } ; result . impact = attackVector [ < attackVector > doc . impact ] ; result . description = doc . description ? doc . description : '' ; return result ; } protected getScope ( doc ) { var result = { impact : scopeImpact . None , description : "" , category : "" } ; result . impact = scopeImpact [ doc . impact ] ; result . description = doc . description ? doc . description : '' ; result . category = doc . category ? doc . category : '' ; return result ; } protected computeVector ( ) { var vector = "AV:" + this . getVectorAttack ( this . attackVector . impact ) ; vector += "/S:" + this . getVectorScope ( this . scope . impact ) ; vector += "/C:" + this . getVectorImpact ( this . confidentiality . impact ) ; vector += "/I:" + this . getVectorImpact ( this . integrity . impact ) ; vector += "/A:" + this . getVectorImpact ( this . availability . impact ) ; return vector ; } private getVectorScope ( value ) { var vector = "" ; switch ( value ) { case scopeImpact . None : { vector = 'N' ; break ; } case scopeImpact . Host : { vector = 'H' ; break ; } case scopeImpact . Cluster : { vector = 'C' ; break ; } } return vector ; } private getVectorAttack ( value ) { var vector = "" ; switch ( value ) { case attackVector . Local : { vector = 'L' ; break ; } case attackVector . Remote : { vector = 'N' ; break ; } } return vector ; } private getVectorImpact ( value ) { var vector = "" ; switch ( value ) { case impact . Low : { vector = 'L' ; break ; } case impact . Medium : { vector = 'M' ; break ; } case impact . High : { vector = 'H' ; break ; } default : { vector = 'N' ; break ; } } return vector ; } save ( target = this . file , test = false ) { var object = this ; delete object . file ; if ( object . references == '' ) delete object . references ; const dump = yaml . safeDump ( object ) ; if ( target == '' ) { console . log ( dump ) ; return ; } if ( test == false ) fs . writeFileSync ( target , dump , { encoding : "utf8" } ) ; } } export class Risk extends Rule { type : string = 'risk' ; exploitability : Exploitability = { impact : exploitabilityImpact . VeryLow , description : "" } ; recommendation : string = '' ; baseScore : number = 0 ; exploitabilitScore : number = 0 ; score : number = 0 ; risk : string = 'Low' ; constructor ( file ) { super ( ) ; this . file = file ; var doc = yaml . safeLoad ( fs . readFileSync ( file , 'utf8' ) ) ; this . name = doc . name ? doc . name : '' ; this . type = doc . type ? doc . type : 'risk' ; this . id = doc . id ? doc . id : '' ; this . revision = doc . revision ? doc . revision : 1 ; this . title = doc . title ? doc . title : '' ; this . description = doc . description ? doc . description : '' ; this . shortDescription = doc . shortDescription ? doc . shortDescription : '' ; this . availability = this . getImpact ( doc . availability ) ; this . confidentiality = this . getImpact ( doc . confidentiality ) ; this . integrity = this . getImpact ( doc . integrity ) ; this . exploitability = this . getExploitability ( doc . exploitability ) ; this . attackVector = this . getAttackVector ( doc . attackVector ) ; this . scope = this . getScope ( doc . scope ) ; this . references = doc . references ? doc . references : '' ; this . recommendation = doc . recommendation ? doc . recommendation : '' ; this . validate ( ) ; this . vector = this . computeVector ( ) ; this . baseScore = Math . round ( 10 * this . computeBaseScore ( ) ) / 10 ; this . exploitabilitScore = Math . round ( 10 * this . computeExploitabilityScore ( ) ) / 10 ; this . score = Math . round ( 10 * ( this . baseScore + this . exploitabilitScore ) ) / 10 ; this . risk = this . computeRisk ( ) ; } protected computeVector ( ) { var vector = super . computeVector ( ) ; vector += "/E:" + this . getVectorExploitability ( this . exploitability . impact ) ; return vector ; } private getVectorExploitability ( value ) { var vector = "" ; switch ( value ) { case exploitabilityImpact . VeryLow : { vector = 'VL' ; break ; } case exploitabilityImpact . Low : { vector = 'L' ; break ; } case exploitabilityImpact . Moderate : { vector = 'M' ; break ; } case exploitabilityImpact . High : { vector = 'H' ; break ; } } return vector ; } private getExploitability ( doc ) { var result = { impact : exploitabilityImpact . VeryLow , description : "" } ; result . impact = exploitabilityImpact [ < exploitabilityImpact > doc . impact . replace ( ' ' , '' ) ] ; result . description = doc . description ? doc . description : '' ; return result ; } private computeBaseScore ( ) { return scopeFactor [ this . scope . impact . valueOf ( ) ] * impactConst * ( 1 - ( ( 1 - impactScore [ this . confidentiality . impact . valueOf ( ) ] ) * ( 1 - impactScore [ this . integrity . impact . valueOf ( ) ] ) * ( 1 - impactScore [ this . availability . impact . valueOf ( ) ] ) ) ) ; } private computeExploitabilityScore ( ) { return exploitabilityConst * attackVectorFactor [ this . attackVector . impact . valueOf ( ) ] * exploitabilityFactor [ this . exploitability . impact . valueOf ( ) ] ; } private computeRisk ( ) { if ( this . score <= riskCategory . Low ) { return 'Low' ; } else if ( this . score <= riskCategory . Medium ) { return 'Medium' ; } else { return "High" ; } } validate ( ) { if ( this . availability . impact == impact . None && this . confidentiality . impact == impact . None && this . integrity . impact == impact . None ) { console . error ( "Missing at least 1 impact" ) ; return false ; } if ( this . availability . impact != impact . None && this . availability . description == "" ) { console . error ( "Availability description is missing" ) ; return false ; } return true ; } }