functions/ConvertFrom-InsightAppSecToCodeDx.ps1

#Converts a Rapid7 Insight AppSec CSV report to a Code Dx report for importing results.

Function ConvertFrom-InsightAppSecToCodeDx
{
    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$SourceScanFilepath,
        [Parameter(Mandatory=$true)]
        [string]$OutputDir
    )
    
    #Setup variables
    $CDate = Get-Date -format "yyyy-MM-dd-HHmmss"

    # Disable for Debugging
    #
    $OutputFilePath = $OutputDir.Trim("""") + "\IAS2CDX-" + $CDate + ".xml"
    
    # Enable for Debugging
    #
    #$SourceScanFilepath = "C:\Users\aacuna\Code Dx Inc\Code Dx - Documents\Sales Engineering\Technology Partners\Rapid7 InsightAppSec\r7insightappsec_sample.csv"
    #$OutputFilePath = "C:\Users\aacuna\Code Dx Inc\Code Dx - Documents\Sales Engineering\Technology Partners\Rapid7 InsightAppSec\IAS2CDX-" + $CDate + ".xml"
    
    $SourceScanFile = $SourceScanFilepath.Trim("""")
    $ToolName = "Rapid7 InsightAppSec"
    $cve
    $loctype
    $description
    $locationFile
    $locationLine
    $reportDate
    $mdtags = @("app_name","app_description","app_uuid","scanType",
    "parentScanUuid","variances_size","attackType","firstDiscovered","firstDiscoveredScan_appId",
    "firstDiscoveredScan_crawlOnly","firstDiscoveredScan_createTime","firstDiscoveredScan_endTime",
    "firstDiscoveredScan_engineUuid","firstDiscoveredScan_failureReason","firstDiscoveredScan_highestSeverity",
    "firstDiscoveredScan_parentScanUuid","firstDiscoveredScan_scanConfig_appUuid",
    "firstDiscoveredScan_scanConfig_attackTemplateUuid","firstDiscoveredScan_scanConfig_description",
    "firstDiscoveredScan_scanConfig_lastScanTime","firstDiscoveredScan_scanConfig_name",
    "firstDiscoveredScan_scanConfig_uuid","firstDiscoveredScan_scanType","firstDiscoveredScan_scheduleUuid",
    "firstDiscoveredScan_startTime","firstDiscoveredScan_status","firstDiscoveredScan_uuid",
    "firstDiscoveredScan_vulnCount","lastDiscoveredScan_appId","lastDiscoveredScan_crawlOnly",
    "lastDiscoveredScan_createTime","lastDiscoveredScan_endTime","lastDiscoveredScan_engineUuid",
    "lastDiscoveredScan_failureReason","lastDiscoveredScan_highestSeverity","lastDiscoveredScan_parentScanUuid",
    "lastDiscoveredScan_scanConfig_appUuid","lastDiscoveredScan_scanConfig_attackTemplateUuid",
    "lastDiscoveredScan_scanConfig_description","lastDiscoveredScan_scanConfig_lastScanTime",
    "lastDiscoveredScan_scanConfig_name","lastDiscoveredScan_scanConfig_uuid","lastDiscoveredScan_scanType",
    "lastDiscoveredScan_scheduleUuid","lastDiscoveredScan_startTime","lastDiscoveredScan_status",
    "lastDiscoveredScan_uuid","lastDiscoveredScan_vulnCount","newlyDiscovered","scans_size")

    #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 = "Rapid7 InsightAppSec to Code Dx - Generated $CDate"
    $updateXML= $doc.AppendChild($doc.CreateComment($reportComment))
    $root = $doc.CreateNode("element","report",$null)
    
    #read source file and create custom PSO
    $SourceScanData = Get-Content -Raw -Path $SourceScanFile | ConvertFrom-CSV

    #pull report date attributes and reformat for Code Dx file
    $reportDate = $SourceScanData[0]."lastDiscovered"

    #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

    #drill into each vulnerability
    $Results | ForEach-Object{
    
            #Create Code Dx elements
            $fd = $doc.CreateNode("element","finding",$null)
            $desc = $doc.CreateNode("element","description",$null)
            $tl = $doc.CreateNode("element","tool",$null)
            $loc = $doc.CreateNode("element","location",$null)
            $md = $doc.CreateNode("element","metadata",$null)
            $nid = $doc.CreateNode("element","native-id",$null)
            $vars = $doc.CreateNode("element","variants",$null)
            $var = $doc.CreateNode("element","variant",$null)
            $req = $doc.CreateNode("element","request",$null)
            $hdr = $doc.CreateNode("element","headers",$null)
            $qpar = $doc.CreateNode("element","element",$null)
            $hhost = $doc.CreateNode("element","host",$null)
            $hname = $doc.CreateNode("element","hostname",$null)

            #Set Query Parameter Element Info
            if($_."rootCause_parameter".length -gt 0){
                $qpar.SetAttribute("type", "query-parameter")
                $qpar.SetAttribute("name", $_."rootCause_parameter")
                $updateXML = $fd.AppendChild($qpar)
            }

            #Set Native ID
            $nid.SetAttribute("name", "InsightAppSec UID")
            $nid.SetAttribute("value", $_.uuid)
            $updateXML= $fd.AppendChild($nid)

            #Set finding severity value
            $sev = switch ($_."severity"){
                "SAFE" {"info"}
                "INFORMATIONAL" {"low"}
                "LOW" {"medium"}
                "MEDIUM" {"high"}
                "HIGH" {"critical"}
                default {"unspecified"}
            }

            #Set finding attributes
            # use "status" when it becomes available.
            $fd.SetAttribute("severity", $sev)
            $fd.SetAttribute("type","dynamic")
            If ($_.vulnerabilities.falsePositive){
                    $fd.SetAttribute("status", "false-positive")
                } else {
                    $fd.SetAttribute("status", "new")
            }

            #Set Tool Code attributes
            $tl.SetAttribute("name",$ToolName)
            $tl.SetAttribute("category","Security")
            $tl.SetAttribute("code", $_."attackType")

            #Split the root cause input to get more info since it contains the hostname and path
            $rootcause_split = $_."rootCause_url".split("/")

            #Set Host info and to finding element.
            $hname.InnerText = $rootcause_split[2]
            $updateXML = $hhost.AppendChild($hname)
            $updateXML = $fd.AppendChild($hhost)

            #parse url path for location
            $path = $_."rootCause_url"
            $path_start = $rootcause_split[0].length + $rootcause_split[2].length + 2
            $path = $path.substring($path_start)

            #build location node and attributes
            $loc.SetAttribute("type","url")
            $loc.SetAttribute("path", $path)

            #build request and response variants and add to variant parent element
            $req.SetAttribute("method",$_."rootCause_method")
            $req.SetAttribute("path",$path)
            $req.SetAttribute("query",$_."rootCause_parameter")
            $updateXML = $req.AppendChild($hdr)
            $updateXML = $var.AppendChild($req)
            $updateXML = $vars.AppendChild($var)
            $updateXMl = $loc.AppendChild($vars)

            #Set description attributes
            $desc.SetAttribute("format", "plain-text")
            $desc.InnerText = $_."moduleName"

            #Capture current vuln object for use later
            $vo = $_

            #Build the Metadata Node
            $mdtags | ForEach-Object {
                if($vo.$_.length -gt 0){
                    $e = $doc.CreateNode("element","value",$null)
                    $e.SetAttribute("key",$_)
                    $e.InnerText = $vo.$_
                    $updateXML= $md.AppendChild($e)
                }
            }

            #append remaining children to finding
            $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)
}