Path: blob/dev/pkg/protocols/dns/operators_test.go
2070 views
package dns12import (3"net"4"strconv"5"testing"67"github.com/miekg/dns"8"github.com/stretchr/testify/require"910"github.com/projectdiscovery/nuclei/v3/pkg/model"11"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"12"github.com/projectdiscovery/nuclei/v3/pkg/operators"13"github.com/projectdiscovery/nuclei/v3/pkg/operators/extractors"14"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"15"github.com/projectdiscovery/nuclei/v3/pkg/output"16"github.com/projectdiscovery/nuclei/v3/pkg/testutils"17)1819func TestResponseToDSLMap(t *testing.T) {20options := testutils.DefaultOptions2122recursion := false23testutils.Init(options)24templateID := "testing-dns"25request := &Request{26RequestType: DNSRequestTypeHolder{DNSRequestType: A},27Class: "INET",28Retries: 5,29ID: templateID,30Recursion: &recursion,31Name: "{{FQDN}}",32}33executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{34ID: templateID,35Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},36})37err := request.Compile(executerOpts)38require.Nil(t, err, "could not compile dns request")3940req := new(dns.Msg)41req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET})4243resp := new(dns.Msg)44resp.Rcode = dns.RcodeSuccess45resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one.", Rrtype: dns.TypeA}}, &dns.A{A: net.ParseIP("2.2.2.2"), Hdr: dns.RR_Header{Name: "one.one.one.one.", Rrtype: dns.TypeA}}, &dns.A{A: net.ParseIP("3.3.3.3"), Hdr: dns.RR_Header{Name: "one.one.one.one.", Rrtype: dns.TypeA}})4647event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil)48require.Len(t, event, 15, "could not get correct number of items in dsl map")49require.Equal(t, dns.RcodeSuccess, event["rcode"], "could not get correct rcode")50require.ElementsMatch(t, []string{net.ParseIP("1.1.1.1").String(), net.ParseIP("2.2.2.2").String(), net.ParseIP("3.3.3.3").String()}, event["a"], "could not get correct a record")51}5253func TestDNSOperatorMatch(t *testing.T) {54options := testutils.DefaultOptions5556recursion := false57testutils.Init(options)58templateID := "testing-dns"59request := &Request{60RequestType: DNSRequestTypeHolder{DNSRequestType: A},61Class: "INET",62Retries: 5,63ID: templateID,64Recursion: &recursion,65Name: "{{FQDN}}",66}67executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{68ID: templateID,69Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},70})71err := request.Compile(executerOpts)72require.Nil(t, err, "could not compile dns request")7374req := new(dns.Msg)75req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET})7677resp := new(dns.Msg)78resp.Rcode = dns.RcodeSuccess79resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}})8081event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil)8283t.Run("valid", func(t *testing.T) {84matcher := &matchers.Matcher{85Part: "raw",86Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},87Words: []string{"1.1.1.1"},88}89err = matcher.CompileMatchers()90require.Nil(t, err, "could not compile matcher")9192isMatch, matched := request.Match(event, matcher)93require.True(t, isMatch, "could not match valid response")94require.Equal(t, matcher.Words, matched)95})9697t.Run("rcode", func(t *testing.T) {98matcher := &matchers.Matcher{99Part: "rcode",100Type: matchers.MatcherTypeHolder{MatcherType: matchers.StatusMatcher},101Status: []int{dns.RcodeSuccess},102}103err = matcher.CompileMatchers()104require.Nil(t, err, "could not compile rcode matcher")105106isMatched, matched := request.Match(event, matcher)107require.True(t, isMatched, "could not match valid rcode response")108require.Equal(t, []string{}, matched)109})110111t.Run("negative", func(t *testing.T) {112matcher := &matchers.Matcher{113Part: "raw",114Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},115Negative: true,116Words: []string{"random"},117}118err := matcher.CompileMatchers()119require.Nil(t, err, "could not compile negative matcher")120121isMatched, matched := request.Match(event, matcher)122require.True(t, isMatched, "could not match valid negative response matcher")123require.Equal(t, []string{}, matched)124})125126t.Run("invalid", func(t *testing.T) {127matcher := &matchers.Matcher{128Part: "raw",129Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},130Words: []string{"random"},131}132err := matcher.CompileMatchers()133require.Nil(t, err, "could not compile matcher")134135isMatched, matched := request.Match(event, matcher)136require.False(t, isMatched, "could match invalid response matcher")137require.Equal(t, []string{}, matched)138})139140t.Run("caseInsensitive", func(t *testing.T) {141req := new(dns.Msg)142req.Question = append(req.Question, dns.Question{Name: "ONE.ONE.ONE.ONE.", Qtype: dns.TypeA, Qclass: dns.ClassINET})143144resp := new(dns.Msg)145resp.Rcode = dns.RcodeSuccess146resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "ONE.ONE.ONE.ONE."}})147148event := request.responseToDSLMap(req, resp, "ONE.ONE.ONE.ONE", "ONE.ONE.ONE.ONE", nil)149150matcher := &matchers.Matcher{151Part: "raw",152Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},153Words: []string{"one.ONE.one.ONE"},154CaseInsensitive: true,155}156err = matcher.CompileMatchers()157require.Nil(t, err, "could not compile matcher")158159isMatch, matched := request.Match(event, matcher)160require.True(t, isMatch, "could not match valid response")161require.Equal(t, []string{"one.one.one.one"}, matched)162})163}164165func TestDNSOperatorExtract(t *testing.T) {166options := testutils.DefaultOptions167168recursion := false169testutils.Init(options)170templateID := "testing-dns"171request := &Request{172RequestType: DNSRequestTypeHolder{DNSRequestType: A},173Class: "INET",174Retries: 5,175ID: templateID,176Recursion: &recursion,177Name: "{{FQDN}}",178}179executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{180ID: templateID,181Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},182})183err := request.Compile(executerOpts)184require.Nil(t, err, "could not compile dns request")185186req := new(dns.Msg)187req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET})188189resp := new(dns.Msg)190resp.Rcode = dns.RcodeSuccess191resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}})192193event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil)194195t.Run("extract", func(t *testing.T) {196extractor := &extractors.Extractor{197Part: "raw",198Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},199Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"},200}201err = extractor.CompileExtractors()202require.Nil(t, err, "could not compile extractor")203204data := request.Extract(event, extractor)205require.Greater(t, len(data), 0, "could not extractor valid response")206require.Equal(t, map[string]struct{}{"1.1.1.1": {}}, data, "could not extract correct data")207})208209t.Run("kval", func(t *testing.T) {210extractor := &extractors.Extractor{211Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.KValExtractor},212KVal: []string{"rcode"},213}214err = extractor.CompileExtractors()215require.Nil(t, err, "could not compile kval extractor")216217data := request.Extract(event, extractor)218require.Greater(t, len(data), 0, "could not extractor kval valid response")219require.Equal(t, map[string]struct{}{strconv.Itoa(dns.RcodeSuccess): {}}, data, "could not extract correct kval data")220})221}222223func TestDNSMakeResult(t *testing.T) {224options := testutils.DefaultOptions225226recursion := false227testutils.Init(options)228templateID := "testing-dns"229executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{230ID: templateID,231Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},232})233request := &Request{234RequestType: DNSRequestTypeHolder{DNSRequestType: A},235Class: "INET",236Retries: 5,237ID: templateID,238Recursion: &recursion,239Name: "{{FQDN}}",240Operators: operators.Operators{241Matchers: []*matchers.Matcher{{242Name: "test",243Part: "raw",244Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},245Words: []string{"1.1.1.1"},246}},247Extractors: []*extractors.Extractor{{248Part: "raw",249Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},250Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"},251}},252},253options: executerOpts,254}255err := request.Compile(executerOpts)256require.Nil(t, err, "could not compile dns request")257258req := new(dns.Msg)259req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET})260261resp := new(dns.Msg)262resp.Rcode = dns.RcodeSuccess263resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}})264265event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil)266finalEvent := &output.InternalWrappedEvent{InternalEvent: event}267if request.CompiledOperators != nil {268result, ok := request.CompiledOperators.Execute(event, request.Match, request.Extract, false)269if ok && result != nil {270finalEvent.OperatorsResult = result271finalEvent.Results = request.MakeResultEvent(finalEvent)272}273}274require.Equal(t, 1, len(finalEvent.Results), "could not get correct number of results")275resultEvent := finalEvent.Results[0]276require.Equal(t, "test", resultEvent.MatcherName, "could not get correct matcher name of results")277require.Equal(t, "1.1.1.1", resultEvent.ExtractedResults[0], "could not get correct extracted results")278require.Equal(t, "one.one.one.one", resultEvent.Matched, "could not get matched value")279}280281282