2020-12-21 14:31:32 +05:30
|
|
|
package dns
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
2020-12-25 02:24:55 +05:30
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
2020-12-24 12:56:28 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer"
|
2020-12-25 12:55:46 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns/dnsclientpool"
|
2020-12-25 02:24:55 +05:30
|
|
|
"github.com/projectdiscovery/retryabledns"
|
2020-12-21 14:31:32 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Request contains a DNS protocol request to be made from a template
|
|
|
|
|
type Request struct {
|
|
|
|
|
// Recursion specifies whether to recurse all the answers.
|
|
|
|
|
Recursion bool `yaml:"recursion"`
|
|
|
|
|
// Path contains the path/s for the request
|
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
|
// Type is the type of DNS request to make
|
|
|
|
|
Type string `yaml:"type"`
|
|
|
|
|
// Class is the class of the DNS request
|
|
|
|
|
Class string `yaml:"class"`
|
|
|
|
|
// Retries is the number of retries for the DNS request
|
|
|
|
|
Retries int `yaml:"retries"`
|
|
|
|
|
// Raw contains a raw request
|
|
|
|
|
Raw string `yaml:"raw,omitempty"`
|
|
|
|
|
|
2020-12-25 02:24:55 +05:30
|
|
|
// Operators for the current request go here.
|
2020-12-29 18:48:13 +05:30
|
|
|
*operators.Operators `yaml:",inline"`
|
2020-12-25 02:24:55 +05:30
|
|
|
|
2020-12-21 14:31:32 +05:30
|
|
|
// cache any variables that may be needed for operation.
|
2020-12-25 02:24:55 +05:30
|
|
|
class uint16
|
|
|
|
|
question uint16
|
|
|
|
|
dnsClient *retryabledns.Client
|
|
|
|
|
options *protocols.ExecuterOptions
|
2020-12-21 14:31:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compile compiles the protocol request for further execution.
|
2020-12-25 02:24:55 +05:30
|
|
|
func (r *Request) Compile(options *protocols.ExecuterOptions) error {
|
|
|
|
|
// Create a dns client for the class
|
2020-12-25 12:55:46 +05:30
|
|
|
client, err := dnsclientpool.Get(options.Options, &dnsclientpool.Configuration{
|
2020-12-25 02:24:55 +05:30
|
|
|
Retries: r.Retries,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not get dns client")
|
|
|
|
|
}
|
|
|
|
|
r.dnsClient = client
|
|
|
|
|
|
|
|
|
|
if r.Operators != nil {
|
|
|
|
|
if err := r.Operators.Compile(); err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not compile operators")
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-21 14:31:32 +05:30
|
|
|
r.class = classToInt(r.Class)
|
2020-12-25 02:24:55 +05:30
|
|
|
r.options = options
|
|
|
|
|
r.question = questionTypeToInt(r.Type)
|
2020-12-21 14:31:32 +05:30
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Requests returns the total number of requests the YAML rule will perform
|
2020-12-29 15:38:14 +05:30
|
|
|
func (r *Request) Requests() int {
|
2020-12-21 14:31:32 +05:30
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make returns the request to be sent for the protocol
|
|
|
|
|
func (r *Request) Make(domain string) (*dns.Msg, error) {
|
|
|
|
|
domain = dns.Fqdn(domain)
|
|
|
|
|
|
|
|
|
|
// Build a request on the specified URL
|
|
|
|
|
req := new(dns.Msg)
|
|
|
|
|
req.Id = dns.Id()
|
|
|
|
|
req.RecursionDesired = r.Recursion
|
|
|
|
|
|
|
|
|
|
var q dns.Question
|
|
|
|
|
|
2020-12-24 12:56:28 +05:30
|
|
|
replacer := replacer.New(map[string]interface{}{"FQDN": domain})
|
2020-12-21 14:31:32 +05:30
|
|
|
|
|
|
|
|
q.Name = dns.Fqdn(replacer.Replace(r.Name))
|
2020-12-25 02:24:55 +05:30
|
|
|
q.Qclass = r.class
|
|
|
|
|
q.Qtype = r.question
|
2020-12-21 14:31:32 +05:30
|
|
|
req.Question = append(req.Question, q)
|
|
|
|
|
return req, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// questionTypeToInt converts DNS question type to internal representation
|
|
|
|
|
func questionTypeToInt(Type string) uint16 {
|
|
|
|
|
Type = strings.TrimSpace(strings.ToUpper(Type))
|
|
|
|
|
question := dns.TypeA
|
|
|
|
|
|
|
|
|
|
switch Type {
|
|
|
|
|
case "A":
|
|
|
|
|
question = dns.TypeA
|
|
|
|
|
case "NS":
|
|
|
|
|
question = dns.TypeNS
|
|
|
|
|
case "CNAME":
|
|
|
|
|
question = dns.TypeCNAME
|
|
|
|
|
case "SOA":
|
|
|
|
|
question = dns.TypeSOA
|
|
|
|
|
case "PTR":
|
|
|
|
|
question = dns.TypePTR
|
|
|
|
|
case "MX":
|
|
|
|
|
question = dns.TypeMX
|
|
|
|
|
case "TXT":
|
|
|
|
|
question = dns.TypeTXT
|
|
|
|
|
case "AAAA":
|
|
|
|
|
question = dns.TypeAAAA
|
|
|
|
|
}
|
|
|
|
|
return uint16(question)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// classToInt converts a dns class name to it's internal representation
|
|
|
|
|
func classToInt(class string) uint16 {
|
|
|
|
|
class = strings.TrimSpace(strings.ToUpper(class))
|
|
|
|
|
result := dns.ClassINET
|
|
|
|
|
|
|
|
|
|
switch class {
|
|
|
|
|
case "INET":
|
|
|
|
|
result = dns.ClassINET
|
|
|
|
|
case "CSNET":
|
|
|
|
|
result = dns.ClassCSNET
|
|
|
|
|
case "CHAOS":
|
|
|
|
|
result = dns.ClassCHAOS
|
|
|
|
|
case "HESIOD":
|
|
|
|
|
result = dns.ClassHESIOD
|
|
|
|
|
case "NONE":
|
|
|
|
|
result = dns.ClassNONE
|
|
|
|
|
case "ANY":
|
|
|
|
|
result = dns.ClassANY
|
|
|
|
|
}
|
|
|
|
|
return uint16(result)
|
|
|
|
|
}
|