merging master

dev
Mzack9999 2020-10-20 19:21:11 +02:00
commit 173b55af92
16 changed files with 243 additions and 230 deletions

View File

@ -59,7 +59,6 @@ linters:
- bodyclose
- deadcode
- dogsled
- dupl
- errcheck
- exhaustive
- gochecknoinits

View File

@ -36,6 +36,7 @@ We have also [open-sourced a template repository](https://github.com/projectdisc
- [Running with multiple templates.](#running-with-multiple-templates)
- [Running with subfinder](#running-with-subfinder)
- [Running in Docker](#running-in-docker-container)
- [Template exclusion](#template-exclusion)
- [Thanks](#thanks)
@ -76,8 +77,8 @@ This will display help for the tool. Here are all the switches it supports.
| -retries | Number of times to retry a failed request (default 1) | nuclei -retries 1 |
| -timeout | Seconds to wait before timeout (default 5) | nuclei -timeout 5 |
| -rl | Rate-Limit of requests per specified target | nuclei -rl 100 |
| -severity |Filter templates based on their severity and only run the matching ones| nuclei -severity critical, low |
| -exclude |Template input dir/file/files to exclude | nuclei -exclude panels, tokens |
| -severity |Run templates based on severity | nuclei -severity critical, low |
| -exclude |Template input dir/file/files to exclude | nuclei -exclude panels -exclude tokens |
| -debug | Allow debugging of request/responses. | nuclei -debug |
| -update-templates | Download and updates nuclei templates | nuclei -update-templates |
| -update-directory | Directory for storing nuclei-templates(optional) | nuclei -update-directory templates |
@ -113,7 +114,7 @@ nuclei requires **go1.14+** to install successfully. Run the following command t
### From Github
```sh
▶ git clone https://github.com/projectdiscovery/nuclei.git; cd nuclei/v2/cmd/nuclei/; go build; mv nuclei /usr/local/bin/; nuclei -h
▶ git clone https://github.com/projectdiscovery/nuclei.git; cd nuclei/v2/cmd/nuclei/; go build; mv nuclei /usr/local/bin/; nuclei -version
```
## Nuclei templates
@ -148,6 +149,13 @@ You can also pass the list of urls at standard input (STDIN). This allows for ea
▶ cat urls.txt | nuclei -t files/git-core.yaml -o results.txt
```
💡 Nuclei accepts list of URLs as input, for example here is how `urls.txt` looks like:-
```
https://test.some-site.com
http://vuls-testing.com
https://test.com
```
### Running with multiple templates.
This will run the tool against all the urls in `urls.txt` with all the templates in the `cves` and `files` directory and returns the matched results.
@ -184,8 +192,53 @@ For example, this will run the tool against all the hosts in `urls.txt` and outp
Remember to change `/path-to-nuclei-templates` to the real path on your host file system.
### Template Exclusion
[Nuclei-templates](https://github.com/projectdiscovery/nuclei-templates) includes multiple checks including many that are useful for attack surface mapping and not necessarily a security issue, in cases where you only looking to scan few specific templates or directory, here are few options / flags to filter or exclude them from running.
#### Running templates based on severity
You can run the templates based on the specific severity of the template, single and multiple severity can be used for scan.
```sh
nuclei -l urls.txt -t cves/ -severity critical, medium
```
The above example will run all the templates under `cves` directory with `critical` and `medium` severity.
```sh
nuclei -l urls.txt -t panels/ -t technologies -severity info
```
The above example will run all the templates under `panels` and `technologies` directory with **severity** marked as `info`
#### Running templates with exclusion
We do not suggest running all the nuclei-templates directory at once, in case of doing so, one can make use of `exclude` flag to exclude specific directory or templates to ignore from scanning.
```sh
nuclei -l urls.txt -t nuclei-templates -exclude panels/ -exclude technologies -exclude files/wp-xmlrpc.yaml
```
Note:- both directory and specific templates case be excluded from scan as shared in the above example.
#### Using `.nuclei-ignore` file for template exclusion
Since release of nuclei [v2.1.1](https://github.com/projectdiscovery/nuclei/releases/tag/v2.1.1), we have added support of `.nuclei-ignore` file that works along with `update-templates` flag of nuclei, in **.nuclei-ignore** file, you can define all the template directory or template path that you wanted to exclude from all the nuclei scans, to start using this feature, make sure you installed nuclei templates using `nuclei -update-templates` flag, now you can add/update/remove templates in the file that you wanted to exclude from running.
```
nano ~/nuclei-templates/.nuclei-ignore
```
Default **nuclei-ignore** list can be accessed from [here](https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore), in case you don't want to exclude anything, simply remove the `.nuclei-ignore` file.
* * *
# 📋 Notes
- Progress bar is experimental feature, might not work in few cases.
- Progress bar doesn't work with workflows, numbers are not accurate due to conditional execution.
## Thanks
nuclei is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. Community contributions have made the project what it is. See the **[Thanks.md](https://github.com/projectdiscovery/nuclei/blob/master/THANKS.md)** file for more details.

View File

@ -27,7 +27,7 @@ const nucleiConfigFilename = ".nuclei-config.json"
var reVersion = regexp.MustCompile(`\d+\.\d+\.\d+`)
// readConfiguration reads the nuclei configuration file from disk.
func (r *Runner) readConfiguration() (*nucleiConfig, error) {
func readConfiguration() (*nucleiConfig, error) {
home, err := os.UserHomeDir()
if err != nil {
return nil, err

View File

@ -13,20 +13,6 @@ import (
// Options contains the configuration options for tuning
// the template requesting process.
type Options struct {
Templates multiStringFlag // Signature specifies the template/templates to use
ExcludedTemplates multiStringFlag // Signature specifies the template/templates to exclude
CustomHeaders requests.CustomHeaders // Custom global headers
Severity string // Filter templates based on their severity and only run the matching ones.
Target string // Target is a single URL/Domain to scan usng a template
Targets string // Targets specifies the targets to scan using templates.
Output string // Output is the file to write found subdomains to.
ProxyURL string // ProxyURL is the URL for the proxy server
ProxySocksURL string // ProxySocksURL is the URL for the proxy socks server
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
Threads int // Thread controls the number of concurrent requests to make.
Timeout int // Timeout is the seconds to wait for a response from the server.
Retries int // Retries is the number of times to retry the request
RateLimit int // Rate-Limit of requests per specified target
Debug bool // Debug mode allows debugging request/responses for the engine
Silent bool // Silent suppresses any extra text and only writes found URLs on screen.
Version bool // Version specifies if we should just show version and exit
@ -36,13 +22,28 @@ type Options struct {
JSON bool // JSON writes json output to files
JSONRequests bool // write requests/responses for matches in JSON output
EnableProgressBar bool // Enable progrss bar
TemplatesVersion bool // Show the templates installed version
TemplateList bool // List available templates
Stdin bool // Stdin specifies whether stdin input was given to the process
StopAtFirstMatch bool // Stop processing template at first full match (this may break chained requests)
NoMeta bool // Don't display metadata for the matches
BulkSize int // Number of targets analyzed in parallel for each template
TemplateThreads int // Number of templates executed in parallel
TemplateThreads int // Number of templates executed in parallel
Project bool // Nuclei uses project folder to avoid sending same HTTP request multiple times
ProjectPath string // Nuclei uses a user defined project folder
Timeout int // Timeout is the seconds to wait for a response from the server.
Retries int // Retries is the number of times to retry the request
RateLimit int // Rate-Limit of requests per specified target
Severity string // Filter templates based on their severity and only run the matching ones.
Target string // Target is a single URL/Domain to scan usng a template
Targets string // Targets specifies the targets to scan using templates.
Output string // Output is the file to write found subdomains to.
ProxyURL string // ProxyURL is the URL for the proxy server
ProxySocksURL string // ProxySocksURL is the URL for the proxy socks server
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
Templates multiStringFlag // Signature specifies the template/templates to use
ExcludedTemplates multiStringFlag // Signature specifies the template/templates to exclude
CustomHeaders requests.CustomHeaders // Custom global headers
}
type multiStringFlag []string
@ -82,13 +83,14 @@ func ParseOptions() *Options {
flag.BoolVar(&options.JSONRequests, "json-requests", false, "Write requests/responses for matches in JSON output")
flag.BoolVar(&options.EnableProgressBar, "pbar", false, "Enable the progress bar")
flag.BoolVar(&options.TemplateList, "tl", false, "List available templates")
flag.IntVar(&options.RateLimit, "rate-limit", -1, "Per Target Rate-Limit")
flag.IntVar(&options.RateLimit, "rate-limit", 150, "Rate-Limit Per Target (maximum requests/second")
flag.BoolVar(&options.StopAtFirstMatch, "stop-at-first-match", false, "Stop processing http requests at first match (this may break template/workflow logic)")
flag.IntVar(&options.BulkSize, "bulk-size", 25, "Number of hosts analyzed in parallel per template")
flag.IntVar(&options.TemplateThreads, "c", 10, "Number of templates executed in parallel")
flag.IntVar(&options.BulkSize, "bulk-size", 25, "Maximum Number of hosts analyzed in parallel per template")
flag.IntVar(&options.TemplateThreads, "c", 10, "Maximum Number of templates executed in parallel")
flag.BoolVar(&options.Project, "project", false, "Use a project folder to avoid sending same request multiple times")
flag.StringVar(&options.ProjectPath, "project-path", "", "Use a user defined project folder, temporary folder is used if not specified but enabled")
flag.BoolVar(&options.NoMeta, "no-meta", false, "Don't display metadata for the matches")
flag.BoolVar(&options.TemplatesVersion, "templates-version", false, "Shows the installed nuclei-templates version")
flag.Parse()
// Check if stdin pipe was given
@ -104,6 +106,14 @@ func ParseOptions() *Options {
gologger.Infof("Current Version: %s\n", Version)
os.Exit(0)
}
if options.TemplatesVersion {
config, err := readConfiguration()
if err != nil {
gologger.Fatalf("Could not read template configuration: %s\n", err)
}
gologger.Infof("Current nuclei-templates version: %s (%s)\n", config.CurrentVersion, config.TemplatesDirectory)
os.Exit(0)
}
// Validate the options passed by the user and if any
// invalid options have been used, exit.

View File

@ -45,6 +45,7 @@ func (r *Runner) processTemplateWithList(p progress.IProgress, template *templat
Writer: r.output,
JSON: r.options.JSON,
JSONRequests: r.options.JSONRequests,
NoMeta: r.options.NoMeta,
ColoredOutput: !r.options.NoColor,
Colorizer: r.colorizer,
Decolorizer: r.decolorizer,
@ -62,6 +63,7 @@ func (r *Runner) processTemplateWithList(p progress.IProgress, template *templat
CustomHeaders: r.options.CustomHeaders,
JSON: r.options.JSON,
JSONRequests: r.options.JSONRequests,
NoMeta: r.options.NoMeta,
CookieReuse: value.CookieReuse,
ColoredOutput: !r.options.NoColor,
Colorizer: &r.colorizer,

View File

@ -136,16 +136,16 @@ func (r *Runner) getParsedTemplatesFor(templatePaths []string, severities string
switch tp := t.(type) {
case *templates.Template:
// only include if severity matches or no severity filtering
sev := strings.ToLower(tp.Info.Severity)
sev := strings.ToLower(tp.Info["severity"])
if !filterBySeverity || hasMatchingSeverity(sev, allSeverities) {
parsedTemplates = append(parsedTemplates, tp)
gologger.Infof("%s\n", r.templateLogMsg(tp.ID, tp.Info.Name, tp.Info.Author, tp.Info.Severity))
gologger.Infof("%s\n", r.templateLogMsg(tp.ID, tp.Info["name"], tp.Info["author"], tp.Info["severity"]))
} else {
gologger.Warningf("Excluding template %s due to severity filter (%s not in [%s])", tp.ID, sev, severities)
}
case *workflows.Workflow:
parsedTemplates = append(parsedTemplates, tp)
gologger.Infof("%s\n", r.templateLogMsg(tp.ID, tp.Info.Name, tp.Info.Author, tp.Info.Severity))
gologger.Infof("%s\n", r.templateLogMsg(tp.ID, tp.Info["name"], tp.Info["author"], tp.Info["severity"]))
workflowCount++
default:
gologger.Errorf("Could not parse file '%s': %s\n", match, err)
@ -198,9 +198,9 @@ func (r *Runner) logAvailableTemplate(tplPath string) {
if t != nil {
switch tp := t.(type) {
case *templates.Template:
gologger.Silentf("%s\n", r.templateLogMsg(tp.ID, tp.Info.Name, tp.Info.Author, tp.Info.Severity))
gologger.Silentf("%s\n", r.templateLogMsg(tp.ID, tp.Info["name"], tp.Info["author"], tp.Info["severity"]))
case *workflows.Workflow:
gologger.Silentf("%s\n", r.templateLogMsg(tp.ID, tp.Info.Name, tp.Info.Author, tp.Info.Severity))
gologger.Silentf("%s\n", r.templateLogMsg(tp.ID, tp.Info["name"], tp.Info["author"], tp.Info["severity"]))
default:
gologger.Errorf("Could not parse file '%s': %s\n", tplPath, err)
}

View File

@ -39,12 +39,10 @@ func (r *Runner) updateTemplates() error {
templatesConfigFile := path.Join(home, nucleiConfigFilename)
if _, statErr := os.Stat(templatesConfigFile); !os.IsNotExist(statErr) {
config, readErr := r.readConfiguration()
if readErr != nil {
config, readErr := readConfiguration()
if err != nil {
return readErr
}
r.templatesConfig = config
}

View File

@ -1,30 +0,0 @@
package executer
import "net/url"
// isURL tests a string to determine if it is a well-structured url or not.
func isURL(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false
}
u, err := url.Parse(toTest)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
return true
}
// extractDomain extracts the domain name of a URL
func extractDomain(theURL string) string {
u, err := url.Parse(theURL)
if err != nil {
return ""
}
hostname := u.Hostname()
return hostname
}

View File

@ -25,6 +25,7 @@ type DNSExecuter struct {
debug bool
jsonOutput bool
jsonRequest bool
noMeta bool
Results bool
dnsClient *retryabledns.Client
template *templates.Template
@ -49,6 +50,7 @@ type DNSOptions struct {
Debug bool
JSON bool
JSONRequests bool
NoMeta bool
Template *templates.Template
DNSRequest *requests.DNSRequest
Writer *bufwriter.Writer
@ -64,6 +66,7 @@ func NewDNSExecuter(options *DNSOptions) *DNSExecuter {
executer := &DNSExecuter{
debug: options.Debug,
noMeta: options.NoMeta,
jsonOutput: options.JSON,
jsonRequest: options.JSONRequests,
dnsClient: dnsClient,

View File

@ -57,6 +57,7 @@ type HTTPExecuter struct {
Results bool
jsonOutput bool
jsonRequest bool
noMeta bool
stopAtFirstMatch bool
}
@ -76,6 +77,7 @@ type HTTPOptions struct {
Debug bool
JSON bool
JSONRequests bool
NoMeta bool
CookieReuse bool
ColoredOutput bool
StopAtFirstMatch bool
@ -122,6 +124,7 @@ func NewHTTPExecuter(options *HTTPOptions) (*HTTPExecuter, error) {
debug: options.Debug,
jsonOutput: options.JSON,
jsonRequest: options.JSONRequests,
noMeta: options.NoMeta,
httpClient: client,
rawHTTPClient: rawClient,
template: options.Template,

View File

@ -1,51 +0,0 @@
package executer
import (
"net/http"
"strings"
"unsafe"
)
type jsonOutput struct {
Template string `json:"template"`
Type string `json:"type"`
Matched string `json:"matched"`
MatcherName string `json:"matcher_name,omitempty"`
ExtractedResults []string `json:"extracted_results,omitempty"`
Name string `json:"name"`
Severity string `json:"severity"`
Author string `json:"author"`
Description string `json:"description"`
Request string `json:"request,omitempty"`
Response string `json:"response,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
// unsafeToString converts byte slice to string with zero allocations
func unsafeToString(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))
}
// headersToString converts http headers to string
func headersToString(headers http.Header) string {
builder := &strings.Builder{}
for header, values := range headers {
builder.WriteString(header)
builder.WriteString(": ")
for i, value := range values {
builder.WriteString(value)
if i != len(values)-1 {
builder.WriteRune('\n')
builder.WriteString(header)
builder.WriteString(": ")
}
}
builder.WriteRune('\n')
}
return builder.String()
}

View File

@ -14,36 +14,32 @@ import (
// nolint:interfacer // dns.Msg is out of current scope
func (e *DNSExecuter) writeOutputDNS(domain string, req, resp *dns.Msg, matcher *matchers.Matcher, extractorResults []string) {
if e.jsonOutput {
output := jsonOutput{
Template: e.template.ID,
Type: "dns",
Matched: domain,
Name: e.template.Info.Name,
Severity: e.template.Info.Severity,
Author: e.template.Info.Author,
Description: e.template.Info.Description,
}
output := make(jsonOutput)
output["matched"] = domain
if matcher != nil && len(matcher.Name) > 0 {
output.MatcherName = matcher.Name
}
if len(extractorResults) > 0 {
output.ExtractedResults = extractorResults
}
if e.jsonRequest {
output.Request = req.String()
output.Response = resp.String()
if !e.noMeta {
output["template"] = e.template.ID
output["type"] = "dns"
for k, v := range e.template.Info {
output[k] = v
}
if matcher != nil && len(matcher.Name) > 0 {
output["matcher_name"] = matcher.Name
}
if len(extractorResults) > 0 {
output["extracted_results"] = extractorResults
}
if e.jsonRequest {
output["request"] = req.String()
output["response"] = resp.String()
}
}
data, err := jsoniter.Marshal(output)
if err != nil {
gologger.Warningf("Could not marshal json output: %s\n", err)
}
gologger.Silentf("%s", string(data))
if e.writer != nil {
if err := e.writer.Write(data); err != nil {
gologger.Errorf("Could not write output data: %s\n", err)
@ -56,28 +52,29 @@ func (e *DNSExecuter) writeOutputDNS(domain string, req, resp *dns.Msg, matcher
builder := &strings.Builder{}
colorizer := e.colorizer
builder.WriteRune('[')
builder.WriteString(colorizer.Colorizer.BrightGreen(e.template.ID).String())
if !e.noMeta {
builder.WriteRune('[')
builder.WriteString(colorizer.Colorizer.BrightGreen(e.template.ID).String())
if matcher != nil && len(matcher.Name) > 0 {
builder.WriteString(":")
builder.WriteString(colorizer.Colorizer.BrightGreen(matcher.Name).Bold().String())
}
if matcher != nil && len(matcher.Name) > 0 {
builder.WriteString(":")
builder.WriteString(colorizer.Colorizer.BrightGreen(matcher.Name).Bold().String())
}
builder.WriteString("] [")
builder.WriteString(colorizer.Colorizer.BrightBlue("dns").String())
builder.WriteString("] ")
if e.template.Info.Severity != "" {
builder.WriteString("[")
builder.WriteString(colorizer.GetColorizedSeverity(e.template.Info.Severity))
builder.WriteString("] [")
builder.WriteString(colorizer.Colorizer.BrightBlue("dns").String())
builder.WriteString("] ")
}
if e.template.Info["severity"] != "" {
builder.WriteString("[")
builder.WriteString(colorizer.GetColorizedSeverity(e.template.Info["severity"]))
builder.WriteString("] ")
}
}
builder.WriteString(domain)
// If any extractors, write the results
if len(extractorResults) > 0 {
if len(extractorResults) > 0 && !e.noMeta {
builder.WriteString(" [")
for i, result := range extractorResults {
@ -87,10 +84,8 @@ func (e *DNSExecuter) writeOutputDNS(domain string, req, resp *dns.Msg, matcher
builder.WriteRune(',')
}
}
builder.WriteString("]")
}
builder.WriteRune('\n')
// Write output to screen as well as any output file

View File

@ -14,59 +14,55 @@ import (
// writeOutputHTTP writes http output to streams
func (e *HTTPExecuter) writeOutputHTTP(req *requests.HTTPRequest, resp *http.Response, body string, matcher *matchers.Matcher, extractorResults []string, meta map[string]interface{}) {
var URL string
// rawhttp
if req.RawRequest != nil {
URL = req.RawRequest.FullURL
}
// retryablehttp
if req.Request != nil {
URL = req.Request.URL.String()
}
if e.jsonOutput {
output := jsonOutput{
Template: e.template.ID,
Type: "http",
Matched: URL,
Name: e.template.Info.Name,
Severity: e.template.Info.Severity,
Author: e.template.Info.Author,
Description: e.template.Info.Description,
Meta: meta,
}
output := make(jsonOutput)
if matcher != nil && len(matcher.Name) > 0 {
output.MatcherName = matcher.Name
}
if len(extractorResults) > 0 {
output.ExtractedResults = extractorResults
}
// TODO: URL should be an argument
if e.jsonRequest {
dumpedRequest, err := requests.Dump(req, URL)
if err != nil {
gologger.Warningf("could not dump request: %s\n", err)
} else {
output.Request = string(dumpedRequest)
output["matched"] = URL
if !e.noMeta {
output["template"] = e.template.ID
output["type"] = "http"
if len(meta) > 0 {
output["meta"] = meta
}
for k, v := range e.template.Info {
output[k] = v
}
if matcher != nil && len(matcher.Name) > 0 {
output["matcher_name"] = matcher.Name
}
if len(extractorResults) > 0 {
output["extracted_results"] = extractorResults
}
dumpedResponse, err := httputil.DumpResponse(resp, false)
// TODO: URL should be an argument
if e.jsonRequest {
dumpedRequest, err := requests.Dump(req, URL)
if err != nil {
gologger.Warningf("could not dump request: %s\n", err)
} else {
output["request"] = string(dumpedRequest)
}
if err != nil {
gologger.Warningf("could not dump response: %s\n", err)
} else {
output.Response = string(dumpedResponse) + body
dumpedResponse, err := httputil.DumpResponse(resp, false)
if err != nil {
gologger.Warningf("could not dump response: %s\n", err)
} else {
output["response"] = string(dumpedResponse) + body
}
}
}
data, err := jsoniter.Marshal(output)
if err != nil {
gologger.Warningf("Could not marshal json output: %s\n", err)
}
gologger.Silentf("%s", string(data))
if e.writer != nil {
@ -75,35 +71,35 @@ func (e *HTTPExecuter) writeOutputHTTP(req *requests.HTTPRequest, resp *http.Res
return
}
}
return
}
builder := &strings.Builder{}
colorizer := e.colorizer
builder.WriteRune('[')
builder.WriteString(colorizer.Colorizer.BrightGreen(e.template.ID).String())
if !e.noMeta {
builder.WriteRune('[')
builder.WriteString(colorizer.Colorizer.BrightGreen(e.template.ID).String())
if matcher != nil && len(matcher.Name) > 0 {
builder.WriteString(":")
builder.WriteString(colorizer.Colorizer.BrightGreen(matcher.Name).Bold().String())
}
if matcher != nil && len(matcher.Name) > 0 {
builder.WriteString(":")
builder.WriteString(colorizer.Colorizer.BrightGreen(matcher.Name).Bold().String())
}
builder.WriteString("] [")
builder.WriteString(colorizer.Colorizer.BrightBlue("http").String())
builder.WriteString("] ")
if e.template.Info.Severity != "" {
builder.WriteString("[")
builder.WriteString(colorizer.GetColorizedSeverity(e.template.Info.Severity))
builder.WriteString("] [")
builder.WriteString(colorizer.Colorizer.BrightBlue("http").String())
builder.WriteString("] ")
}
if e.template.Info["severity"] != "" {
builder.WriteString("[")
builder.WriteString(colorizer.GetColorizedSeverity(e.template.Info["severity"]))
builder.WriteString("] ")
}
}
builder.WriteString(URL)
// If any extractors, write the results
if len(extractorResults) > 0 {
if len(extractorResults) > 0 && !e.noMeta {
builder.WriteString(" [")
for i, result := range extractorResults {
@ -118,7 +114,7 @@ func (e *HTTPExecuter) writeOutputHTTP(req *requests.HTTPRequest, resp *http.Res
}
// write meta if any
if len(req.Meta) > 0 {
if len(req.Meta) > 0 && !e.noMeta {
builder.WriteString(" [")
var metas []string

59
v2/pkg/executer/utils.go Normal file
View File

@ -0,0 +1,59 @@
package executer
import (
"net/http"
"net/url"
"strings"
"unsafe"
)
type jsonOutput map[string]interface{}
// unsafeToString converts byte slice to string with zero allocations
func unsafeToString(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))
}
// headersToString converts http headers to string
func headersToString(headers http.Header) string {
builder := &strings.Builder{}
for header, values := range headers {
builder.WriteString(header)
builder.WriteString(": ")
for i, value := range values {
builder.WriteString(value)
if i != len(values)-1 {
builder.WriteRune('\n')
builder.WriteString(header)
builder.WriteString(": ")
}
}
builder.WriteRune('\n')
}
return builder.String()
}
// isURL tests a string to determine if it is a well-structured url or not.
func isURL(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false
}
u, err := url.Parse(toTest)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
return true
}
// extractDomain extracts the domain name of a URL
func extractDomain(theURL string) string {
u, err := url.Parse(theURL)
if err != nil {
return ""
}
return u.Hostname()
}

View File

@ -9,7 +9,7 @@ type Template struct {
// ID is the unique id for the template
ID string `yaml:"id"`
// Info contains information about the template
Info Info `yaml:"info"`
Info map[string]string `yaml:"info"`
// BulkRequestsHTTP contains the http request to make in the template
BulkRequestsHTTP []*requests.BulkHTTPRequest `yaml:"requests,omitempty"`
// RequestsDNS contains the dns request to make in the template
@ -22,18 +22,6 @@ func (t *Template) GetPath() string {
return t.path
}
// Info contains information about the request template
type Info struct {
// Name is the name of the template
Name string `yaml:"name"`
// Author is the name of the author of the template
Author string `yaml:"author"`
// Severity optionally describes the severity of the template
Severity string `yaml:"severity,omitempty"`
// Description optionally describes the template.
Description string `yaml:"description,omitempty"`
}
func (t *Template) GetHTTPRequestCount() int64 {
var count int64 = 0
for _, request := range t.BulkRequestsHTTP {

View File

@ -5,7 +5,7 @@ type Workflow struct {
// ID is the unique id for the template
ID string `yaml:"id"`
// Info contains information about the template
Info Info `yaml:"info"`
Info map[string]string `yaml:"info"`
// CookieReuse makes all cookies shared by templates within the workflow
CookieReuse bool `yaml:"cookie-reuse,omitempty"`
// Variables contains the variables accessible to the pseudo-code
@ -19,15 +19,3 @@ type Workflow struct {
func (w *Workflow) GetPath() string {
return w.path
}
// Info contains information about workflow
type Info struct {
// Name is the name of the workflow
Name string `yaml:"name"`
// Author is the name of the author of the workflow
Author string `yaml:"author"`
// Severity optionally describes the severity of the template
Severity string `yaml:"severity,omitempty"`
// Description optionally describes the template.
Description string `yaml:"description,omitempty"`
}