nuclei/pkg/executer/executer_dns.go

167 lines
4.4 KiB
Go
Raw Normal View History

2020-07-16 10:57:28 +02:00
package executer
2020-04-26 05:50:33 +05:30
import (
2020-06-22 19:30:01 +05:30
"fmt"
"os"
"regexp"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
2020-06-22 19:30:01 +05:30
"github.com/projectdiscovery/gologger"
2020-09-10 16:32:01 +05:30
"github.com/projectdiscovery/nuclei/v2/internal/bufwriter"
"github.com/projectdiscovery/nuclei/v2/internal/progress"
2020-07-01 16:17:24 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/matchers"
"github.com/projectdiscovery/nuclei/v2/pkg/requests"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
2020-04-26 05:50:33 +05:30
retryabledns "github.com/projectdiscovery/retryabledns"
)
2020-07-16 10:57:28 +02:00
// DNSExecuter is a client for performing a DNS request
2020-04-26 05:50:33 +05:30
// for a template.
2020-07-16 10:57:28 +02:00
type DNSExecuter struct {
coloredOutput bool
debug bool
jsonOutput bool
jsonRequest bool
Results bool
dnsClient *retryabledns.Client
template *templates.Template
dnsRequest *requests.DNSRequest
2020-09-10 16:32:01 +05:30
writer *bufwriter.Writer
colorizer aurora.Aurora
decolorizer *regexp.Regexp
2020-04-26 05:50:33 +05:30
}
// DefaultResolvers contains the list of resolvers known to be trusted.
var DefaultResolvers = []string{
"1.1.1.1:53", // Cloudflare
"1.0.0.1:53", // Cloudflare
"8.8.8.8:53", // Google
"8.8.4.4:53", // Google
}
2020-07-16 10:57:28 +02:00
// DNSOptions contains configuration options for the DNS executer.
type DNSOptions struct {
ColoredOutput bool
Debug bool
JSON bool
JSONRequests bool
Template *templates.Template
DNSRequest *requests.DNSRequest
2020-09-10 16:32:01 +05:30
Writer *bufwriter.Writer
Colorizer aurora.Aurora
Decolorizer *regexp.Regexp
}
2020-07-16 10:57:28 +02:00
// NewDNSExecuter creates a new DNS executer from a template
2020-04-26 05:50:33 +05:30
// and a DNS request query.
2020-07-16 10:57:28 +02:00
func NewDNSExecuter(options *DNSOptions) *DNSExecuter {
dnsClient := retryabledns.New(DefaultResolvers, options.DNSRequest.Retries)
2020-04-26 05:50:33 +05:30
2020-07-16 10:57:28 +02:00
executer := &DNSExecuter{
debug: options.Debug,
jsonOutput: options.JSON,
2020-08-04 15:16:41 +02:00
jsonRequest: options.JSONRequests,
dnsClient: dnsClient,
template: options.Template,
dnsRequest: options.DNSRequest,
writer: options.Writer,
coloredOutput: options.ColoredOutput,
colorizer: options.Colorizer,
decolorizer: options.Decolorizer,
2020-04-26 05:50:33 +05:30
}
2020-04-26 05:50:33 +05:30
return executer
}
// ExecuteDNS executes the DNS request on a URL
func (e *DNSExecuter) ExecuteDNS(p progress.IProgress, reqURL string) (result Result) {
2020-04-26 05:50:33 +05:30
// Parse the URL and return domain if URL.
var domain string
if isURL(reqURL) {
domain = extractDomain(reqURL)
2020-04-26 05:50:33 +05:30
} else {
domain = reqURL
2020-04-26 05:50:33 +05:30
}
// Compile each request for the template based on the URL
compiledRequest, err := e.dnsRequest.MakeDNSRequest(domain)
2020-04-26 05:50:33 +05:30
if err != nil {
2020-07-10 09:04:38 +02:00
result.Error = errors.Wrap(err, "could not make dns request")
p.Drop(1)
2020-07-10 09:04:38 +02:00
return
2020-04-26 05:50:33 +05:30
}
2020-06-22 19:30:01 +05:30
if e.debug {
gologger.Infof("Dumped DNS request for %s (%s)\n\n", reqURL, e.template.ID)
2020-06-22 19:30:01 +05:30
fmt.Fprintf(os.Stderr, "%s\n", compiledRequest.String())
}
2020-04-26 05:50:33 +05:30
// Send the request to the target servers
resp, err := e.dnsClient.Do(compiledRequest)
if err != nil {
2020-07-10 09:04:38 +02:00
result.Error = errors.Wrap(err, "could not send dns request")
p.Drop(1)
2020-07-10 09:04:38 +02:00
return
2020-04-26 05:50:33 +05:30
}
p.Update()
2020-07-26 16:36:01 +02:00
gologger.Verbosef("Sent for [%s] to %s\n", "dns-request", e.template.ID, reqURL)
2020-06-22 19:30:01 +05:30
if e.debug {
gologger.Infof("Dumped DNS response for %s (%s)\n\n", reqURL, e.template.ID)
2020-06-22 19:30:01 +05:30
fmt.Fprintf(os.Stderr, "%s\n", resp.String())
}
matcherCondition := e.dnsRequest.GetMatchersCondition()
2020-04-26 05:50:33 +05:30
for _, matcher := range e.dnsRequest.Matchers {
// Check if the matcher matched
if !matcher.MatchDNS(resp) {
// If the condition is AND we haven't matched, return.
if matcherCondition == matchers.ANDCondition {
2020-07-10 09:04:38 +02:00
return
}
} else {
// If the matcher has matched, and its an OR
// write the first output then move to next matcher.
if matcherCondition == matchers.ORCondition && len(e.dnsRequest.Extractors) == 0 {
2020-08-04 15:16:41 +02:00
e.writeOutputDNS(domain, compiledRequest, resp, matcher, nil)
2020-07-25 20:45:31 +02:00
result.GotResults = true
}
2020-04-26 05:50:33 +05:30
}
}
// All matchers have successfully completed so now start with the
// next task which is extraction of input from matchers.
2020-04-26 05:50:33 +05:30
var extractorResults []string
2020-04-26 05:50:33 +05:30
for _, extractor := range e.dnsRequest.Extractors {
2020-07-16 10:32:00 +02:00
for match := range extractor.ExtractDNS(resp) {
2020-07-25 21:15:28 +02:00
if !extractor.Internal {
extractorResults = append(extractorResults, match)
}
2020-04-27 23:34:08 +05:30
}
2020-04-26 05:50:33 +05:30
}
// Write a final string of output if matcher type is
// AND or if we have extractors for the mechanism too.
if len(e.dnsRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition {
2020-08-04 15:16:41 +02:00
e.writeOutputDNS(domain, compiledRequest, resp, nil, extractorResults)
result.GotResults = true
}
2020-07-10 09:04:38 +02:00
return result
}
2020-07-16 10:57:28 +02:00
// Close closes the dns executer for a template.
2020-09-10 16:32:01 +05:30
func (e *DNSExecuter) Close() {}