Display tpl contents (#2906)

* New "td" flag, displays the highlighted template contents
New verboseTemplate method to avoid duplicate code
Grouped (and sorted) template list per directory

* Updated README about the td flag

* Going back to the previous template list format

The new one can't be pipelined

* Implicit template list on template display
Respect --no-color option to disable colors when -td is used

* misc option update

Co-authored-by: Víctor Zamanillo <victor.zamanillo@cifraeducacion.com>
Co-authored-by: sandeep <8293321+ehsandeep@users.noreply.github.com>
This commit is contained in:
Víctor 2022-11-29 13:18:44 +01:00 committed by GitHub
parent d9afb33bb0
commit 9c17284616
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 82 additions and 22 deletions

View File

@ -110,6 +110,7 @@ TEMPLATES:
-validate validate the passed templates to nuclei
-nss, -no-strict-syntax Disable strict syntax check on templates
-tl list all available templates
-td displays the template contents
FILTERING:
-a, -author string[] templates to run based on authors (comma-separated, file)

View File

@ -108,6 +108,7 @@ Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板
-validate 验证通过的模板
-nss, -no-strict-syntax 禁用模板的严格检查
-tl 列出所有可用的模板
-td 显示模板内容
过滤:
-a, -author string[] 执行指定作者的模板(逗号分隔,文件)

View File

@ -106,6 +106,7 @@ TEMPLATES:
-wu, -workflow-url string[] 실행할 워크플로 URL 목록(쉼표로 구분된 파일)
-validate nuclei로 전달된 템플릿 검증
-tl 사용 가능한 모든 템플릿 목록
-td 템플릿 내용 표시
FILTERING:
-a, -author string[] 작성자를 기준으로 실행할 템플릿(쉼표로 구분된 파일)

View File

@ -140,6 +140,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", []string{}, "list of workflow urls to run (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.BoolVar(&options.Validate, "validate", false, "validate the passed templates to nuclei"),
flagSet.BoolVarP(&options.NoStrictSyntax, "no-strict-syntax", "nss", false, "disable strict syntax check on templates"),
flagSet.BoolVarP(&options.TemplateDisplay, "template-display", "td", false, "displays the templates content"),
flagSet.BoolVar(&options.TemplateList, "tl", false, "list all available templates"),
flagSet.StringSliceVarConfigOnly(&options.RemoteTemplateDomainList, "remote-template-domain", []string{"api.nuclei.sh"}, "allowed domain list to load remote templates from"),
)

View File

@ -86,6 +86,7 @@ require (
)
require (
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/projectdiscovery/folderutil v0.0.0-20220215113126-add60a1e8e08 // indirect
github.com/projectdiscovery/sliceutil v0.0.1 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
@ -202,6 +203,7 @@ require (
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/alecthomas/chroma v0.10.0
github.com/emirpasic/gods v1.12.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect

View File

@ -78,6 +78,8 @@ github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK
github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/jsonschema v0.0.0-20210818095345-1014919a589c/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725 h1:NjwIgLQlD46o79bheVG4SCdRnnOz4XtgUN1WABX5DLA=
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
@ -192,6 +194,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=

View File

@ -421,7 +421,7 @@ func (r *Runner) RunEnumeration() error {
}
}
// list all templates
if r.options.TemplateList {
if r.options.TemplateList || r.options.TemplateDisplay {
r.listAvailableStoreTemplates(store)
os.Exit(0)
}

View File

@ -1,10 +1,15 @@
package runner
import (
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"bytes"
"io/ioutil"
"path/filepath"
"strings"
"github.com/alecthomas/chroma/quick"
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
@ -17,36 +22,73 @@ func (r *Runner) logAvailableTemplate(tplPath string) {
if err != nil {
gologger.Error().Msgf("Could not parse file '%s': %s\n", tplPath, err)
} else {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(t.ID,
types.ToString(t.Info.Name),
t.Info.Authors.ToSlice(),
t.Info.SeverityHolder.Severity))
r.verboseTemplate(t)
}
}
// log available templates for verbose (-vv)
func (r *Runner) verboseTemplate(tpl *templates.Template) {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(tpl.ID,
types.ToString(tpl.Info.Name),
tpl.Info.Authors.ToSlice(),
tpl.Info.SeverityHolder.Severity))
}
func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
gologger.Print().Msgf(
"\nListing available v.%s nuclei templates for %s",
r.templatesConfig.TemplateVersion,
r.templatesConfig.TemplatesDirectory,
)
extraFlags := r.options.Templates != nil || r.options.Authors != nil ||
r.options.Tags != nil || len(r.options.ExcludeTags) > 3 ||
r.options.IncludeTags != nil || r.options.IncludeIds != nil ||
r.options.ExcludeIds != nil || r.options.IncludeTemplates != nil ||
r.options.ExcludedTemplates != nil || r.options.ExcludeMatchers != nil ||
r.options.Severities != nil || r.options.ExcludeSeverities != nil ||
r.options.Protocols != nil || r.options.ExcludeProtocols != nil ||
r.options.IncludeConditions != nil || r.options.TemplateList
for _, tl := range store.Templates() {
if extraFlags {
path := strings.TrimPrefix(tl.Path, r.templatesConfig.TemplatesDirectory+string(filepath.Separator))
gologger.Silent().Msgf("%s\n", path)
for _, tpl := range store.Templates() {
if hasExtraFlags(r.options) {
if r.options.TemplateDisplay {
colorize := !r.options.NoColor
path := tpl.Path
tplBody, err := ioutil.ReadFile(path)
if err != nil {
gologger.Error().Msgf("Could not read the template %s: %s", path, err)
continue
}
if colorize {
path = aurora.Cyan(tpl.Path).String()
tplBody, err = r.highlightTemplate(&tplBody)
if err != nil {
gologger.Error().Msgf("Could not hihglight the template %s: %s", tpl.Path, err)
continue
}
}
gologger.Silent().Msgf("Template: %s\n\n%s", path, tplBody)
} else {
gologger.Silent().Msgf("%s\n", strings.TrimPrefix(tpl.Path, r.templatesConfig.TemplatesDirectory+string(filepath.Separator)))
}
} else {
gologger.Print().Msgf("%s\n", templates.TemplateLogMessage(tl.ID,
types.ToString(tl.Info.Name),
tl.Info.Authors.ToSlice(),
tl.Info.SeverityHolder.Severity))
r.verboseTemplate(tpl)
}
}
}
func (r *Runner) highlightTemplate(body *[]byte) ([]byte, error) {
var buf bytes.Buffer
// YAML lexer, true color terminar formatter and monokai style
err := quick.Highlight(&buf, string(*body), "yaml", "terminal16m", "monokai")
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func hasExtraFlags(options *types.Options) bool {
return options.Templates != nil || options.Authors != nil ||
options.Tags != nil || len(options.ExcludeTags) > 3 ||
options.IncludeTags != nil || options.IncludeIds != nil ||
options.ExcludeIds != nil || options.IncludeTemplates != nil ||
options.ExcludedTemplates != nil || options.ExcludeMatchers != nil ||
options.Severities != nil || options.ExcludeSeverities != nil ||
options.Protocols != nil || options.ExcludeProtocols != nil ||
options.IncludeConditions != nil || options.TemplateList
}

View File

@ -2,6 +2,7 @@ package loader
import (
"os"
"sort"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
@ -284,6 +285,11 @@ func (store *Store) LoadTemplates(templatesList []string) []*templates.Template
gologger.Warning().Msgf("Could not load template %s: %s\n", templatePath, err)
}
}
sort.SliceStable(loadedTemplates, func(i, j int) bool {
return loadedTemplates[i].Path < loadedTemplates[j].Path
})
return loadedTemplates
}

View File

@ -202,6 +202,8 @@ type Options struct {
EnableProgressBar bool
// TemplatesVersion shows the templates installed version
TemplatesVersion bool
// TemplateDisplay displays the template contents
TemplateDisplay bool
// TemplateList lists available templates
TemplateList bool
// HangMonitor enables nuclei hang monitoring