mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-25 12:45:28 +00:00
The message "Sent Type request to" is redundant and noisy and does not provide any useful information, we enriched it adding the template id.
174 lines
4.5 KiB
Go
174 lines
4.5 KiB
Go
package executer
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"sync"
|
|
|
|
"github.com/logrusorgru/aurora"
|
|
"github.com/pkg/errors"
|
|
"github.com/projectdiscovery/gologger"
|
|
"github.com/projectdiscovery/nuclei/v2/internal/progress"
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/matchers"
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/requests"
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
|
retryabledns "github.com/projectdiscovery/retryabledns"
|
|
)
|
|
|
|
// DNSExecuter is a client for performing a DNS request
|
|
// for a template.
|
|
type DNSExecuter struct {
|
|
coloredOutput bool
|
|
debug bool
|
|
jsonOutput bool
|
|
jsonRequest bool
|
|
Results bool
|
|
dnsClient *retryabledns.Client
|
|
template *templates.Template
|
|
dnsRequest *requests.DNSRequest
|
|
writer *bufio.Writer
|
|
outputMutex *sync.Mutex
|
|
|
|
colorizer aurora.Aurora
|
|
decolorizer *regexp.Regexp
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
Writer *bufio.Writer
|
|
|
|
Colorizer aurora.Aurora
|
|
Decolorizer *regexp.Regexp
|
|
}
|
|
|
|
// NewDNSExecuter creates a new DNS executer from a template
|
|
// and a DNS request query.
|
|
func NewDNSExecuter(options *DNSOptions) *DNSExecuter {
|
|
dnsClient := retryabledns.New(DefaultResolvers, options.DNSRequest.Retries)
|
|
|
|
executer := &DNSExecuter{
|
|
debug: options.Debug,
|
|
jsonOutput: options.JSON,
|
|
jsonRequest: options.JSONRequests,
|
|
dnsClient: dnsClient,
|
|
template: options.Template,
|
|
dnsRequest: options.DNSRequest,
|
|
writer: options.Writer,
|
|
outputMutex: &sync.Mutex{},
|
|
coloredOutput: options.ColoredOutput,
|
|
colorizer: options.Colorizer,
|
|
decolorizer: options.Decolorizer,
|
|
}
|
|
|
|
return executer
|
|
}
|
|
|
|
// ExecuteDNS executes the DNS request on a URL
|
|
func (e *DNSExecuter) ExecuteDNS(p progress.IProgress, reqURL string) (result Result) {
|
|
// Parse the URL and return domain if URL.
|
|
var domain string
|
|
if isURL(reqURL) {
|
|
domain = extractDomain(reqURL)
|
|
} else {
|
|
domain = reqURL
|
|
}
|
|
|
|
// Compile each request for the template based on the URL
|
|
compiledRequest, err := e.dnsRequest.MakeDNSRequest(domain)
|
|
if err != nil {
|
|
result.Error = errors.Wrap(err, "could not make dns request")
|
|
|
|
p.Drop(1)
|
|
|
|
return
|
|
}
|
|
|
|
if e.debug {
|
|
gologger.Infof("Dumped DNS request for %s (%s)\n\n", reqURL, e.template.ID)
|
|
fmt.Fprintf(os.Stderr, "%s\n", compiledRequest.String())
|
|
}
|
|
|
|
// Send the request to the target servers
|
|
resp, err := e.dnsClient.Do(compiledRequest)
|
|
if err != nil {
|
|
result.Error = errors.Wrap(err, "could not send dns request")
|
|
|
|
p.Drop(1)
|
|
|
|
return
|
|
}
|
|
|
|
p.Update()
|
|
|
|
gologger.Verbosef("Sent for [%s] to %s\n", "dns-request", e.template.ID, reqURL)
|
|
|
|
if e.debug {
|
|
gologger.Infof("Dumped DNS response for %s (%s)\n\n", reqURL, e.template.ID)
|
|
fmt.Fprintf(os.Stderr, "%s\n", resp.String())
|
|
}
|
|
|
|
matcherCondition := e.dnsRequest.GetMatchersCondition()
|
|
|
|
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 {
|
|
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 {
|
|
e.writeOutputDNS(domain, compiledRequest, resp, matcher, nil)
|
|
result.GotResults = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// All matchers have successfully completed so now start with the
|
|
// next task which is extraction of input from matchers.
|
|
var extractorResults []string
|
|
|
|
for _, extractor := range e.dnsRequest.Extractors {
|
|
for match := range extractor.ExtractDNS(resp) {
|
|
if !extractor.Internal {
|
|
extractorResults = append(extractorResults, match)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
e.writeOutputDNS(domain, compiledRequest, resp, nil, extractorResults)
|
|
|
|
result.GotResults = true
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Close closes the dns executer for a template.
|
|
func (e *DNSExecuter) Close() {
|
|
e.outputMutex.Lock()
|
|
defer e.outputMutex.Unlock()
|
|
e.writer.Flush()
|
|
}
|