github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/dns/operators_test.go (about) 1 package dns 2 3 import ( 4 "net" 5 "strconv" 6 "testing" 7 8 "github.com/miekg/dns" 9 "github.com/stretchr/testify/require" 10 11 "github.com/projectdiscovery/nuclei/v2/pkg/model" 12 "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" 13 "github.com/projectdiscovery/nuclei/v2/pkg/operators" 14 "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" 15 "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" 16 "github.com/projectdiscovery/nuclei/v2/pkg/output" 17 "github.com/projectdiscovery/nuclei/v2/pkg/testutils" 18 ) 19 20 func TestResponseToDSLMap(t *testing.T) { 21 options := testutils.DefaultOptions 22 23 recursion := false 24 testutils.Init(options) 25 templateID := "testing-dns" 26 request := &Request{ 27 RequestType: DNSRequestTypeHolder{DNSRequestType: A}, 28 Class: "INET", 29 Retries: 5, 30 ID: templateID, 31 Recursion: &recursion, 32 Name: "{{FQDN}}", 33 } 34 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 35 ID: templateID, 36 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 37 }) 38 err := request.Compile(executerOpts) 39 require.Nil(t, err, "could not compile dns request") 40 41 req := new(dns.Msg) 42 req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET}) 43 44 resp := new(dns.Msg) 45 resp.Rcode = dns.RcodeSuccess 46 resp.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}}) 47 48 event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil) 49 require.Len(t, event, 15, "could not get correct number of items in dsl map") 50 require.Equal(t, dns.RcodeSuccess, event["rcode"], "could not get correct rcode") 51 require.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") 52 } 53 54 func TestDNSOperatorMatch(t *testing.T) { 55 options := testutils.DefaultOptions 56 57 recursion := false 58 testutils.Init(options) 59 templateID := "testing-dns" 60 request := &Request{ 61 RequestType: DNSRequestTypeHolder{DNSRequestType: A}, 62 Class: "INET", 63 Retries: 5, 64 ID: templateID, 65 Recursion: &recursion, 66 Name: "{{FQDN}}", 67 } 68 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 69 ID: templateID, 70 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 71 }) 72 err := request.Compile(executerOpts) 73 require.Nil(t, err, "could not compile dns request") 74 75 req := new(dns.Msg) 76 req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET}) 77 78 resp := new(dns.Msg) 79 resp.Rcode = dns.RcodeSuccess 80 resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}}) 81 82 event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil) 83 84 t.Run("valid", func(t *testing.T) { 85 matcher := &matchers.Matcher{ 86 Part: "raw", 87 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 88 Words: []string{"1.1.1.1"}, 89 } 90 err = matcher.CompileMatchers() 91 require.Nil(t, err, "could not compile matcher") 92 93 isMatch, matched := request.Match(event, matcher) 94 require.True(t, isMatch, "could not match valid response") 95 require.Equal(t, matcher.Words, matched) 96 }) 97 98 t.Run("rcode", func(t *testing.T) { 99 matcher := &matchers.Matcher{ 100 Part: "rcode", 101 Type: matchers.MatcherTypeHolder{MatcherType: matchers.StatusMatcher}, 102 Status: []int{dns.RcodeSuccess}, 103 } 104 err = matcher.CompileMatchers() 105 require.Nil(t, err, "could not compile rcode matcher") 106 107 isMatched, matched := request.Match(event, matcher) 108 require.True(t, isMatched, "could not match valid rcode response") 109 require.Equal(t, []string{}, matched) 110 }) 111 112 t.Run("negative", func(t *testing.T) { 113 matcher := &matchers.Matcher{ 114 Part: "raw", 115 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 116 Negative: true, 117 Words: []string{"random"}, 118 } 119 err := matcher.CompileMatchers() 120 require.Nil(t, err, "could not compile negative matcher") 121 122 isMatched, matched := request.Match(event, matcher) 123 require.True(t, isMatched, "could not match valid negative response matcher") 124 require.Equal(t, []string{}, matched) 125 }) 126 127 t.Run("invalid", func(t *testing.T) { 128 matcher := &matchers.Matcher{ 129 Part: "raw", 130 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 131 Words: []string{"random"}, 132 } 133 err := matcher.CompileMatchers() 134 require.Nil(t, err, "could not compile matcher") 135 136 isMatched, matched := request.Match(event, matcher) 137 require.False(t, isMatched, "could match invalid response matcher") 138 require.Equal(t, []string{}, matched) 139 }) 140 141 t.Run("caseInsensitive", func(t *testing.T) { 142 req := new(dns.Msg) 143 req.Question = append(req.Question, dns.Question{Name: "ONE.ONE.ONE.ONE.", Qtype: dns.TypeA, Qclass: dns.ClassINET}) 144 145 resp := new(dns.Msg) 146 resp.Rcode = dns.RcodeSuccess 147 resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "ONE.ONE.ONE.ONE."}}) 148 149 event := request.responseToDSLMap(req, resp, "ONE.ONE.ONE.ONE", "ONE.ONE.ONE.ONE", nil) 150 151 matcher := &matchers.Matcher{ 152 Part: "raw", 153 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 154 Words: []string{"one.ONE.one.ONE"}, 155 CaseInsensitive: true, 156 } 157 err = matcher.CompileMatchers() 158 require.Nil(t, err, "could not compile matcher") 159 160 isMatch, matched := request.Match(event, matcher) 161 require.True(t, isMatch, "could not match valid response") 162 require.Equal(t, []string{"one.one.one.one"}, matched) 163 }) 164 } 165 166 func TestDNSOperatorExtract(t *testing.T) { 167 options := testutils.DefaultOptions 168 169 recursion := false 170 testutils.Init(options) 171 templateID := "testing-dns" 172 request := &Request{ 173 RequestType: DNSRequestTypeHolder{DNSRequestType: A}, 174 Class: "INET", 175 Retries: 5, 176 ID: templateID, 177 Recursion: &recursion, 178 Name: "{{FQDN}}", 179 } 180 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 181 ID: templateID, 182 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 183 }) 184 err := request.Compile(executerOpts) 185 require.Nil(t, err, "could not compile dns request") 186 187 req := new(dns.Msg) 188 req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET}) 189 190 resp := new(dns.Msg) 191 resp.Rcode = dns.RcodeSuccess 192 resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}}) 193 194 event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil) 195 196 t.Run("extract", func(t *testing.T) { 197 extractor := &extractors.Extractor{ 198 Part: "raw", 199 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor}, 200 Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"}, 201 } 202 err = extractor.CompileExtractors() 203 require.Nil(t, err, "could not compile extractor") 204 205 data := request.Extract(event, extractor) 206 require.Greater(t, len(data), 0, "could not extractor valid response") 207 require.Equal(t, map[string]struct{}{"1.1.1.1": {}}, data, "could not extract correct data") 208 }) 209 210 t.Run("kval", func(t *testing.T) { 211 extractor := &extractors.Extractor{ 212 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.KValExtractor}, 213 KVal: []string{"rcode"}, 214 } 215 err = extractor.CompileExtractors() 216 require.Nil(t, err, "could not compile kval extractor") 217 218 data := request.Extract(event, extractor) 219 require.Greater(t, len(data), 0, "could not extractor kval valid response") 220 require.Equal(t, map[string]struct{}{strconv.Itoa(dns.RcodeSuccess): {}}, data, "could not extract correct kval data") 221 }) 222 } 223 224 func TestDNSMakeResult(t *testing.T) { 225 options := testutils.DefaultOptions 226 227 recursion := false 228 testutils.Init(options) 229 templateID := "testing-dns" 230 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 231 ID: templateID, 232 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 233 }) 234 request := &Request{ 235 RequestType: DNSRequestTypeHolder{DNSRequestType: A}, 236 Class: "INET", 237 Retries: 5, 238 ID: templateID, 239 Recursion: &recursion, 240 Name: "{{FQDN}}", 241 Operators: operators.Operators{ 242 Matchers: []*matchers.Matcher{{ 243 Name: "test", 244 Part: "raw", 245 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 246 Words: []string{"1.1.1.1"}, 247 }}, 248 Extractors: []*extractors.Extractor{{ 249 Part: "raw", 250 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor}, 251 Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"}, 252 }}, 253 }, 254 options: executerOpts, 255 } 256 err := request.Compile(executerOpts) 257 require.Nil(t, err, "could not compile dns request") 258 259 req := new(dns.Msg) 260 req.Question = append(req.Question, dns.Question{Name: "one.one.one.one.", Qtype: dns.TypeA, Qclass: dns.ClassINET}) 261 262 resp := new(dns.Msg) 263 resp.Rcode = dns.RcodeSuccess 264 resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}}) 265 266 event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil) 267 finalEvent := &output.InternalWrappedEvent{InternalEvent: event} 268 if request.CompiledOperators != nil { 269 result, ok := request.CompiledOperators.Execute(event, request.Match, request.Extract, false) 270 if ok && result != nil { 271 finalEvent.OperatorsResult = result 272 finalEvent.Results = request.MakeResultEvent(finalEvent) 273 } 274 } 275 require.Equal(t, 1, len(finalEvent.Results), "could not get correct number of results") 276 resultEvent := finalEvent.Results[0] 277 require.Equal(t, "test", resultEvent.MatcherName, "could not get correct matcher name of results") 278 require.Equal(t, "1.1.1.1", resultEvent.ExtractedResults[0], "could not get correct extracted results") 279 require.Equal(t, "one.one.one.one", resultEvent.Matched, "could not get matched value") 280 }