Skip to content

Commit

Permalink
Feature: Nessus & CIS CAT Converters (#2535)
Browse files Browse the repository at this point in the history
* feat: cis cat pro json converter

* bug: exclude passing tests from results for match forward baseline status

* feat: nessus converter v0

* bug: fingerprint targetid + empty plugin output

* feat: cis cat unit tests

* feat: nessus unit tests

* bug: omit 0 severity results + cvss override

* bug: cis cat set unknown status to warning

* feat: set rank for critical capability

* chore: update test cases

* chore: codeql cleanup

* chore: dotnet format errors

* feat: gh property tags
  • Loading branch information
ejohn20 authored Nov 8, 2022
1 parent 31f49b2 commit 466f5c9
Show file tree
Hide file tree
Showing 45 changed files with 1,603 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docs/multitool-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,19 @@ Sarif.Multitool validate Other.sarif
```

## Supported Converters

Run ```Sarif.Multitool convert --help``` for the current list.

- AndroidStudio
- CisCat
- ClangAnalyzer
- ClangTidy
- CppCheck
- ContrastSecurity
- Fortify
- FortifyFpr
- FxCop
- Nessus
- PREfast
- Pylint
- SemmleQL
Expand Down
2 changes: 2 additions & 0 deletions src/Sarif.Converters/BuiltInConverterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ private static Dictionary<string, Lazy<ToolFileConverterBase>> CreateBuiltInConv
{
var result = new Dictionary<string, Lazy<ToolFileConverterBase>>();
CreateConverterRecord<AndroidStudioConverter>(result, ToolFormat.AndroidStudio);
CreateConverterRecord<CisCatConverter>(result, ToolFormat.CisCat);
CreateConverterRecord<CppCheckConverter>(result, ToolFormat.CppCheck);
CreateConverterRecord<ClangAnalyzerConverter>(result, ToolFormat.ClangAnalyzer);
CreateConverterRecord<ClangTidyConverter>(result, ToolFormat.ClangTidy);
Expand All @@ -34,6 +35,7 @@ private static Dictionary<string, Lazy<ToolFileConverterBase>> CreateBuiltInConv
CreateConverterRecord<FxCopConverter>(result, ToolFormat.FxCop);
CreateConverterRecord<FlawFinderConverter>(result, ToolFormat.FlawFinder);
CreateConverterRecord<HdfConverter>(result, ToolFormat.Hdf);
CreateConverterRecord<NessusConverter>(result, ToolFormat.Nessus);
CreateConverterRecord<PREfastConverter>(result, ToolFormat.PREfast);
CreateConverterRecord<PylintConverter>(result, ToolFormat.Pylint);
CreateConverterRecord<SemmleQLConverter>(result, ToolFormat.SemmleQL);
Expand Down
188 changes: 188 additions & 0 deletions src/Sarif.Converters/CisCatConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.CodeAnalysis.Sarif.Converters.CisCatObjectModel;

namespace Microsoft.CodeAnalysis.Sarif.Converters
{
public class CisCatConverter : ToolFileConverterBase
{
private readonly LogReader<CisCatReport> logReader;

public CisCatConverter()
{
logReader = new CisCatReportReader();
}

public override string ToolName => ToolFormat.CisCat;

public override void Convert(Stream input, IResultLogWriter output, OptionallyEmittedData dataToInsert)
{
input = input ?? throw new ArgumentNullException(nameof(input));
output = output ?? throw new ArgumentNullException(nameof(output));

//Read CIS CAT data
CisCatReport log = logReader.ReadLog(input);

//Top level run object for the scan data
var run = new Run();

//Set the tool details
run.Tool = new Tool();
run.Tool.Driver = CreateDriver(log);

//Set the list of tool rules
run.Tool.Driver.Rules = new List<ReportingDescriptor>();
foreach (CisCatRule rule in log.Rules)
{
run.Tool.Driver.Rules.Add(CreateReportDescriptor(rule));
}

var results = new List<Result>();
foreach (CisCatRule rule in log.Rules.Where(i => !i.IsPass()))
{
results.Add(CreateResult(rule));
}

PersistResults(output, results, run);
}

internal ToolComponent CreateDriver(CisCatReport report)
{

var driver = new ToolComponent();

driver.Name = this.ToolName;
driver.FullName = report.BenchmarkTitle;
driver.Version = report.BenchmarkVersion;
driver.SemanticVersion = report.BenchmarkVersion;
driver.InformationUri = new Uri("https://www.cisecurity.org/cybersecurity-tools/cis-cat-pro_pre");

driver.SetProperty("benchmarkId", report.BenchmarkId);
driver.SetProperty("profileId", report.ProfileId);
driver.SetProperty("profileTitle", report.ProfileTitle);
driver.SetProperty("score", report.Score);

return driver;
}

internal ReportingDescriptor CreateReportDescriptor(CisCatRule rule)
{
ReportingDescriptor descriptor = new ReportingDescriptor();

descriptor.Id = rule.RuleId;
descriptor.Name = rule.RuleTitle;
descriptor.ShortDescription = new MultiformatMessageString()
{
Text = rule.RuleTitle,
Markdown = rule.RuleTitle,
};
descriptor.FullDescription = new MultiformatMessageString()
{
Text = rule.RuleTitle,
Markdown = rule.RuleTitle,
};
descriptor.Help = new MultiformatMessageString()
{
Text = rule.RuleTitle,
Markdown = rule.RuleTitle,
};

//Use for GH Security Advisories
//set result level and rank (Critical - Low risk rating)
FailureLevel level = FailureLevel.None;
ResultKind kind = ResultKind.None;
double rank = RankConstants.None;
getResultSeverity(rule.Result, out level, out kind, out rank);

//Create only if a valid is assigned
if (rank != RankConstants.None)
{
descriptor.SetProperty("security-severity", rank);
}

//Tags for GH filtering
var tags = new List<string>()
{
"security",
};

descriptor.SetProperty("tags", tags);

return descriptor;
}

internal Result CreateResult(CisCatRule rule)
{
//set the result metadata
Result result = new Result
{
RuleId = rule.RuleId,
Message = new Message { Text = rule.RuleTitle },
};

//set result kind, level and rank (Critical - Low risk rating)
FailureLevel level = FailureLevel.None;
ResultKind kind = ResultKind.None;
double rank = RankConstants.None;
getResultSeverity(rule.Result, out level, out kind, out rank);

//Set result object data
result.Level = level;
result.Kind = kind;
result.Rank = rank;

//Set the unique fingerprint
result.Fingerprints = new Dictionary<string, string>();
result.Fingerprints.Add("0", HashUtilities.ComputeSha256HashValue(rule.RuleId).ToLower());

return result;
}

private void getResultSeverity(string result, out FailureLevel level, out ResultKind kind, out double rank)
{
// Default values
level = FailureLevel.None;
kind = ResultKind.None;
rank = RankConstants.None;

//Kind & Level determine the status
//Result: "fail": Level = Error, Kind = Fail
//Result: "info|notchecked|pass|unknown": Level = None, Kind = Informational|NotApplicable|Pass|Review
switch (result)
{
case "pass":
level = FailureLevel.None;
kind = ResultKind.Pass;
rank = RankConstants.None;
break;
case "fail":
level = FailureLevel.Error;
kind = ResultKind.Fail;
rank = RankConstants.High;
break;
case "notchecked":
level = FailureLevel.None;
kind = ResultKind.NotApplicable;
rank = RankConstants.None;
break;
case "informational":
level = FailureLevel.None;
kind = ResultKind.Informational;
rank = RankConstants.None;
break;
case "unknown":
default:
level = FailureLevel.Warning;
kind = ResultKind.Fail;
rank = RankConstants.Medium;
break;
};
}
}
}
33 changes: 33 additions & 0 deletions src/Sarif.Converters/CisCatObjectModel/CisCatReport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;

using Newtonsoft.Json;

namespace Microsoft.CodeAnalysis.Sarif.Converters.CisCatObjectModel
{
public class CisCatReport
{
[JsonProperty("benchmark-id")]
public string BenchmarkId { get; set; }

[JsonProperty("benchmark-title")]
public string BenchmarkTitle { get; set; }

[JsonProperty("benchmark-version")]
public string BenchmarkVersion { get; set; }

[JsonProperty("profile-id")]
public string ProfileId { get; set; }

[JsonProperty("profile-title")]
public string ProfileTitle { get; set; }

[JsonProperty("score")]
public string Score { get; set; }

[JsonProperty("rules")]
public IEnumerable<CisCatRule> Rules { get; set; }
}
}
25 changes: 25 additions & 0 deletions src/Sarif.Converters/CisCatObjectModel/CisCatReportReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.IO;

using Newtonsoft.Json;

namespace Microsoft.CodeAnalysis.Sarif.Converters.CisCatObjectModel
{
public class CisCatReportReader : LogReader<CisCatReport>
{
public override CisCatReport ReadLog(Stream input)
{
string reportData;

using (TextReader streamReader = new StreamReader(input))
{
reportData = streamReader.ReadToEnd();
}

return JsonConvert.DeserializeObject<CisCatReport>(reportData);
}
}
}
24 changes: 24 additions & 0 deletions src/Sarif.Converters/CisCatObjectModel/CisCatRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Newtonsoft.Json;

namespace Microsoft.CodeAnalysis.Sarif.Converters.CisCatObjectModel
{
public class CisCatRule
{
[JsonProperty("rule-id")]
public string RuleId { get; set; }

[JsonProperty("rule-title")]
public string RuleTitle { get; set; }

[JsonProperty("result")]
public string Result { get; set; }

public bool IsPass()
{
return this.Result == "pass";
}
}
}
Loading

0 comments on commit 466f5c9

Please sign in to comment.