Markdown Export Sorting (#3961)

* Sort markdown exports by host, severity, or template

* Switch default to empty string

* use fileutil to create folder

---------

Co-authored-by: Tarun Koyalwar <tarun@projectdiscovery.io>
dev
Keith Chason 2023-07-21 16:54:06 -04:00 committed by GitHub
parent 9558e22a64
commit 759ee3d5f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 2 deletions

View File

@ -407,6 +407,13 @@ func readEnvInputVars(options *types.Options) {
options.GitLabTemplateDisableDownload = getBoolEnvValue("DISABLE_NUCLEI_TEMPLATES_GITLAB_DOWNLOAD")
options.AwsTemplateDisableDownload = getBoolEnvValue("DISABLE_NUCLEI_TEMPLATES_AWS_DOWNLOAD")
options.AzureTemplateDisableDownload = getBoolEnvValue("DISABLE_NUCLEI_TEMPLATES_AZURE_DOWNLOAD")
// Options to modify the behavior of exporters
options.MarkdownExportSortMode = strings.ToLower(os.Getenv("MARKDOWN_EXPORT_SORT_MODE"))
// If the user has not specified a valid sort mode, use the default
if options.MarkdownExportSortMode != "template" && options.MarkdownExportSortMode != "severity" && options.MarkdownExportSortMode != "host" {
options.MarkdownExportSortMode = ""
}
}
func getBoolEnvValue(key string) bool {

View File

@ -346,12 +346,14 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
reportingOptions.MarkdownExporter = &markdown.Options{
Directory: options.MarkdownExportDirectory,
IncludeRawPayload: !options.OmitRawRequests,
SortMode: options.MarkdownExportSortMode,
}
} else {
reportingOptions = &reporting.Options{}
reportingOptions.MarkdownExporter = &markdown.Options{
Directory: options.MarkdownExportDirectory,
IncludeRawPayload: !options.OmitRawRequests,
SortMode: options.MarkdownExportSortMode,
}
}
}

View File

@ -6,9 +6,12 @@ import (
"path/filepath"
"strings"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/exporters/markdown/util"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/format"
fileutil "github.com/projectdiscovery/utils/file"
stringsutil "github.com/projectdiscovery/utils/strings"
)
@ -25,6 +28,7 @@ type Options struct {
// Directory is the directory to export found results to
Directory string `yaml:"directory"`
IncludeRawPayload bool `yaml:"include-raw-payload"`
SortMode string `yaml:"sort-mode"`
}
// New creates a new markdown exporter integration client based on options.
@ -69,7 +73,35 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
defer file.Close()
filename := createFileName(event)
host := util.CreateLink(event.Host, filename)
// If the sort mode is set to severity, host, or template, then we need to get a safe version of the name for a
// subdirectory to store the file in.
// This will allow us to sort the files into subdirectories based on the sort mode. The subdirectory will need to
// be created if it does not exist.
fileUrl := filename
subdirectory := ""
switch exporter.options.SortMode {
case "severity":
subdirectory = event.Info.SeverityHolder.Severity.String()
case "host":
subdirectory = event.Host
case "template":
subdirectory = event.TemplateID
}
if subdirectory != "" {
// Sanitize the subdirectory name to remove any characters that are not allowed in a directory name
subdirectory = sanitizeFilename(subdirectory)
// Prepend the subdirectory name to the filename for the fileUrl
fileUrl = filepath.Join(subdirectory, filename)
// Create the subdirectory if it does not exist
if err = fileutil.CreateFolders(filepath.Join(exporter.directory, subdirectory)); err != nil {
gologger.Warning().Msgf("Could not create subdirectory for markdown report: %s", err)
}
}
host := util.CreateLink(event.Host, fileUrl)
finding := event.TemplateID + " " + event.MatcherName
severity := event.Info.SeverityHolder.Severity.String()
@ -85,7 +117,7 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
dataBuilder.WriteString(format.CreateReportDescription(event, util.MarkdownFormatter{}))
data := dataBuilder.Bytes()
return os.WriteFile(filepath.Join(exporter.directory, filename), data, 0644)
return os.WriteFile(filepath.Join(exporter.directory, subdirectory, filename), data, 0644)
}
func createFileName(event *output.ResultEvent) string {

View File

@ -93,6 +93,8 @@ type Options struct {
ReportingConfig string
// MarkdownExportDirectory is the directory to export reports in Markdown format
MarkdownExportDirectory string
// MarkdownExportSortMode is the method to sort the markdown reports (options: severity, template, host, none)
MarkdownExportSortMode string
// SarifExport is the file to export sarif output format to
SarifExport string
// CloudURL is the URL for the nuclei cloud endpoint