functions/ConvertFrom-SARIFToCodeDx.ps1
<#
.SYNOPSIS Converts a SARIF JSON report to a Code Dx report for importing results. .DESCRIPTION Used to convert a SARIF JSON report file to a Code Dx XML format so it can be imported. .EXAMPLE ConvertFrom-SARIFToCodeDX [scan_file_to_process] [output_directory] #> Function ConvertFrom-SARIFToCodeDx { [cmdletbinding()] param( [Parameter(Mandatory=$true)] [string]$SourceScanFilepath, [Parameter(Mandatory=$true)] [string]$OutputDir ) #Setup variables $CDate = Get-Date -format "yyyy-MM-dd-HHmmss" $OutputFilePath = $OutputDir.Trim("""") + "\TS2CDX-" + $CDate + ".xml" # Enable for Debugging # #$SARIFFilePath = "SARIF.json" #$OutputFilePath = "C:\Users\aacuna\Documents\repos\powershell\Code Dx\TS2CDX-" + $CDate + ".xml" $SourceScanFile = $SourceScanFilepath.Trim("""") $ToolName = "SARIF" $NativeIDName = "Scanner uniqueId" $NativeID $cwe $description $locationFile $locationLine $reportDate #Setup Code Dx output doc [xml]$doc = New-Object System.Xml.XmlDocument $dec = $doc.CreateXmlDeclaration("1.0","UTF-8",$null) $updateXML= $doc.AppendChild($dec) $reportComment = "SARIF to Code Dx - Generated $CDate" $updateXML= $doc.AppendChild($doc.CreateComment($reportComment)) $root = $doc.CreateNode("element","report",$null) #read source SARIF file and create custom PSO $SourceScanData = Get-Content -Encoding UTF8 -Raw -Path $SourceScanFile | ConvertFrom-Json #pull report date attributes and reformat for Code Dx file $reportDate = $SourceScanData.createdTime.SubString(0,10) $reportDate = [datetime]::parseexact($reportDate, 'dd/MM/yyyy', $null) $reportDate = $reportDate.ToString('yyyy-MM-dd') #Set Root attributes $root.SetAttribute("date",$reportDate) $root.SetAttribute("tool",$ToolName) #create findings Element $fds = $doc.CreateNode("element","findings",$null) #Get parent array of results $Results = $SourceScanData.results $Results | ForEach-Object{ #capture language for use in finding metadata $resultLanguage = $_.language #fetch results object from within results object. $subResults = $_.results If ($subResults.Count -gt 0){ $subResults | ForEach-Object{ #fetch vulns $vulns = $_.vulnerabilities If ($vulns.Count -gt 0){ #capture result level information $sev = $_.risk.ToLower() $code = $_.name $resDesc = $_.description $resRec = $_.recommendation #drill into each vulnerability $vulns | ForEach-Object{ #Create Code Dx elements $fd = $doc.CreateNode("element","finding",$null) $id = $doc.CreateNode("element","native-id",$null) $cwe = $doc.CreateNode("element","cwe",$null) $desc = $doc.CreateNode("element","description",$null) $tl = $doc.CreateNode("element","tool",$null) $loc = $doc.CreateNode("element","location",$null) $ln = $doc.CreateNode("element","line",$null) $md = $doc.CreateNode("element","metadata",$null) #Set finding "fd" attributes $fd.SetAttribute("severity", $_.risk.ToLower()) $fd.SetAttribute("type","static") If ($_.vulnerabilities.falsePositive){ $fd.SetAttribute("status", "false-positive") } else { $fd.SetAttribute("status", "new") } #Set Native ID attributes $id.SetAttribute("name",$NativeIDName) $id.SetAttribute("value", $_.uniqueId) #Set CWE attributes $cwe.SetAttribute("id", $_.cwe.SubString(4)) #Set Tool attributes $tl.SetAttribute("name",$ToolName) $tl.SetAttribute("category","Security") $tl.SetAttribute("code", $_.vulnerabilityType) #set line attributes $ln.SetAttribute("end", $_.functionCalls.line) $ln.SetAttribute("start", $_.functionCalls.line) $updateXML= $loc.AppendChild($ln) #build location node and attributes $loc.SetAttribute("type","file") $loc.SetAttribute("path", $_.vulnerableProjectFile) #Set description attributes $desc.SetAttribute("format", "plain-text") $desc.InnerText = $resDesc #Capture current vuln for use later $vo = $_ #Build most of the Metadata Node "vulnerableFunction","vulnerableFunctionCall","inputVariable","functionCalls" | forEach { If($_ -ne "functionCalls"){ $e = $doc.CreateNode("element","value",$null) $e.SetAttribute("key",$_) $e.InnerText = $vo.$_ $updateXML= $md.AppendChild($e) } else { $fc = $vo.$_ "name","line","file" | forEach{ $e = $doc.CreateNode("element","value",$null) $e.SetAttribute("key","Function Call $_") $e.InnerText = $fc.$_ $updateXML= $md.AppendChild($e) } } } #Add recommendation element to Metadata $e = $doc.CreateNode("element","value",$null) $e.SetAttribute("key","Recommendation") $e.InnerText = $resRec $updateXML= $md.AppendChild($e) #Build Dataflow metadata $flow = $_.userInputFlow $e = $doc.CreateNode("element","value",$null) $e.SetAttribute("key","User Input Flow") $dataflowtext = "" for ($i=0; $i -lt $flow.length; $i++) { $dataflowtext = $dataflowtext + $flow[$i].name $dataflowtext = $dataflowtext + " at line " + $flow[$i].line $dataflowtext = $dataflowtext + " in file " + $flow[$i].file if(($i+1) -lt $flow.length){ $dataflowtext = $dataflowtext + " --> " } } $e.InnerText = $dataflowtext $updateXML= $md.AppendChild($e) #append remaining children to finding $updateXML= $fd.AppendChild($id) $updateXML= $fd.AppendChild($cwe) $updateXML= $fd.AppendChild($tl) $updateXML= $fd.AppendChild($loc) $updateXML= $fd.AppendChild($desc) $updateXML= $fd.AppendChild($md) #append finding to findings $updateXML= $fds.AppendChild($fd) } } } } } $updateXML= $root.AppendChild($fds) $updateXML= $doc.AppendChild($root) | Out-Null Write-Host "Outputing file to: $OutputFilePath" $doc.Save($OutputFilePath) } |