github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/file/operators_test.go (about) 1 package file 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/projectdiscovery/nuclei/v2/pkg/model" 9 "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" 10 "github.com/projectdiscovery/nuclei/v2/pkg/operators" 11 "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" 12 "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" 13 "github.com/projectdiscovery/nuclei/v2/pkg/output" 14 "github.com/projectdiscovery/nuclei/v2/pkg/testutils" 15 ) 16 17 func newMockOperator() operators.Operators { 18 operators := operators.Operators{ 19 Matchers: []*matchers.Matcher{ 20 { 21 Type: matchers.MatcherTypeHolder{ 22 MatcherType: matchers.WordsMatcher, 23 }, 24 }, 25 }, 26 } 27 return operators 28 } 29 30 func TestResponseToDSLMap(t *testing.T) { 31 options := testutils.DefaultOptions 32 33 testutils.Init(options) 34 templateID := "testing-file" 35 request := &Request{ 36 ID: templateID, 37 MaxSize: "1Gb", 38 NoRecursive: false, 39 Extensions: []string{"*", ".lock"}, 40 DenyList: []string{".go"}, 41 Operators: newMockOperator(), 42 } 43 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 44 ID: templateID, 45 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 46 }) 47 err := request.Compile(executerOpts) 48 require.Nil(t, err, "could not compile file request") 49 50 resp := "test-data\r\n" 51 event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") 52 require.Len(t, event, 7, "could not get correct number of items in dsl map") 53 require.Equal(t, resp, event["raw"], "could not get correct resp") 54 } 55 56 func TestFileOperatorMatch(t *testing.T) { 57 options := testutils.DefaultOptions 58 59 testutils.Init(options) 60 templateID := "testing-file" 61 request := &Request{ 62 ID: templateID, 63 MaxSize: "1Gb", 64 NoRecursive: false, 65 Extensions: []string{"*", ".lock"}, 66 DenyList: []string{".go"}, 67 Operators: newMockOperator(), 68 } 69 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 70 ID: templateID, 71 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 72 }) 73 err := request.Compile(executerOpts) 74 require.Nil(t, err, "could not compile file request") 75 76 resp := "test-data\r\n1.1.1.1\r\n" 77 event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") 78 require.Len(t, event, 7, "could not get correct number of items in dsl map") 79 require.Equal(t, resp, event["raw"], "could not get correct resp") 80 81 t.Run("valid", func(t *testing.T) { 82 matcher := &matchers.Matcher{ 83 Part: "raw", 84 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 85 Words: []string{"1.1.1.1"}, 86 } 87 err = matcher.CompileMatchers() 88 require.Nil(t, err, "could not compile matcher") 89 90 isMatched, matched := request.Match(event, matcher) 91 require.True(t, isMatched, "could not match valid response") 92 require.Equal(t, matcher.Words, matched) 93 }) 94 95 t.Run("negative", func(t *testing.T) { 96 matcher := &matchers.Matcher{ 97 Part: "raw", 98 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 99 Negative: true, 100 Words: []string{"random"}, 101 } 102 err := matcher.CompileMatchers() 103 require.Nil(t, err, "could not compile negative matcher") 104 105 isMatched, matched := request.Match(event, matcher) 106 require.True(t, isMatched, "could not match valid negative response matcher") 107 require.Equal(t, []string{}, matched) 108 }) 109 110 t.Run("invalid", func(t *testing.T) { 111 matcher := &matchers.Matcher{ 112 Part: "raw", 113 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 114 Words: []string{"random"}, 115 } 116 err := matcher.CompileMatchers() 117 require.Nil(t, err, "could not compile matcher") 118 119 isMatched, matched := request.Match(event, matcher) 120 require.False(t, isMatched, "could match invalid response matcher") 121 require.Equal(t, []string{}, matched) 122 }) 123 124 t.Run("caseInsensitive", func(t *testing.T) { 125 resp := "TEST-DATA\r\n1.1.1.1\r\n" 126 event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") 127 require.Len(t, event, 7, "could not get correct number of items in dsl map") 128 require.Equal(t, resp, event["raw"], "could not get correct resp") 129 130 matcher := &matchers.Matcher{ 131 Part: "raw", 132 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 133 Words: []string{"TeSt-DaTA"}, 134 CaseInsensitive: true, 135 } 136 err = matcher.CompileMatchers() 137 require.Nil(t, err, "could not compile matcher") 138 139 isMatched, matched := request.Match(event, matcher) 140 require.True(t, isMatched, "could not match valid response") 141 require.Equal(t, []string{"test-data"}, matched) 142 }) 143 } 144 145 func TestFileOperatorExtract(t *testing.T) { 146 options := testutils.DefaultOptions 147 148 testutils.Init(options) 149 templateID := "testing-file" 150 request := &Request{ 151 ID: templateID, 152 MaxSize: "1Gb", 153 NoRecursive: false, 154 Extensions: []string{"*", ".lock"}, 155 DenyList: []string{".go"}, 156 Operators: newMockOperator(), 157 } 158 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 159 ID: templateID, 160 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 161 }) 162 err := request.Compile(executerOpts) 163 require.Nil(t, err, "could not compile file request") 164 165 resp := "test-data\r\n1.1.1.1\r\n" 166 event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") 167 require.Len(t, event, 7, "could not get correct number of items in dsl map") 168 require.Equal(t, resp, event["raw"], "could not get correct resp") 169 170 t.Run("extract", func(t *testing.T) { 171 extractor := &extractors.Extractor{ 172 Part: "raw", 173 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor}, 174 Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"}, 175 } 176 err = extractor.CompileExtractors() 177 require.Nil(t, err, "could not compile extractor") 178 179 data := request.Extract(event, extractor) 180 require.Greater(t, len(data), 0, "could not extractor valid response") 181 require.Equal(t, map[string]struct{}{"1.1.1.1": {}}, data, "could not extract correct data") 182 }) 183 184 t.Run("kval", func(t *testing.T) { 185 extractor := &extractors.Extractor{ 186 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.KValExtractor}, 187 KVal: []string{"raw"}, 188 } 189 err = extractor.CompileExtractors() 190 require.Nil(t, err, "could not compile kval extractor") 191 192 data := request.Extract(event, extractor) 193 require.Greater(t, len(data), 0, "could not extractor kval valid response") 194 require.Equal(t, map[string]struct{}{resp: {}}, data, "could not extract correct kval data") 195 }) 196 } 197 198 func TestFileMakeResultWithOrMatcher(t *testing.T) { 199 expectedValue := []string{"1.1.1.1"} 200 namedMatcherName := "test" 201 202 finalEvent := testFileMakeResultOperators(t, "or") 203 require.Equal(t, namedMatcherName, finalEvent.Results[0].MatcherName) 204 require.Equal(t, expectedValue, finalEvent.OperatorsResult.Matches[namedMatcherName], "could not get matched value") 205 } 206 207 func TestFileMakeResultWithAndMatcher(t *testing.T) { 208 finalEvent := testFileMakeResultOperators(t, "and") 209 require.Equal(t, "", finalEvent.Results[0].MatcherName) 210 require.Empty(t, finalEvent.OperatorsResult.Matches) 211 } 212 213 func testFileMakeResultOperators(t *testing.T, matcherCondition string) *output.InternalWrappedEvent { 214 expectedValue := []string{"1.1.1.1"} 215 namedMatcherName := "test" 216 matcher := []*matchers.Matcher{ 217 { 218 Part: "raw", 219 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 220 Words: expectedValue, 221 }, 222 { 223 Name: namedMatcherName, 224 Part: "raw", 225 Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher}, 226 Words: expectedValue, 227 }, 228 } 229 230 expectedValues := map[string][]string{ 231 "word-1": expectedValue, 232 namedMatcherName: expectedValue, 233 } 234 235 finalEvent := testFileMakeResult(t, matcher, matcherCondition, true) 236 for matcherName, matchedValues := range expectedValues { 237 var matchesOne = false 238 for i := 0; i <= len(expectedValue); i++ { 239 resultEvent := finalEvent.Results[i] 240 if matcherName == resultEvent.MatcherName { 241 matchesOne = true 242 } 243 } 244 require.True(t, matchesOne) 245 require.Equal(t, matchedValues, finalEvent.OperatorsResult.Matches[matcherName], "could not get matched value") 246 } 247 248 finalEvent = testFileMakeResult(t, matcher, matcherCondition, false) 249 require.Equal(t, 1, len(finalEvent.Results)) 250 return finalEvent 251 } 252 253 func testFileMakeResult(t *testing.T, matchers []*matchers.Matcher, matcherCondition string, isDebug bool) *output.InternalWrappedEvent { 254 options := testutils.DefaultOptions 255 256 testutils.Init(options) 257 templateID := "testing-file" 258 executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ 259 ID: templateID, 260 Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, 261 }) 262 request := &Request{ 263 ID: templateID, 264 MaxSize: "1Gb", 265 NoRecursive: false, 266 Extensions: []string{"*", ".lock"}, 267 DenyList: []string{".go"}, 268 Operators: operators.Operators{ 269 MatchersCondition: matcherCondition, 270 Matchers: matchers, 271 Extractors: []*extractors.Extractor{{ 272 Part: "raw", 273 Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor}, 274 Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"}, 275 }}, 276 }, 277 options: executerOpts, 278 } 279 err := request.Compile(executerOpts) 280 require.Nil(t, err, "could not compile file request") 281 282 matchedFileName := "test.txt" 283 fileContent := "test-data\r\n1.1.1.1\r\n" 284 285 event := request.responseToDSLMap(fileContent, "/tmp", matchedFileName) 286 require.Len(t, event, 7, "could not get correct number of items in dsl map") 287 require.Equal(t, fileContent, event["raw"], "could not get correct resp") 288 289 finalEvent := &output.InternalWrappedEvent{InternalEvent: event} 290 if request.CompiledOperators != nil { 291 result, ok := request.CompiledOperators.Execute(event, request.Match, request.Extract, isDebug) 292 if ok && result != nil { 293 finalEvent.OperatorsResult = result 294 finalEvent.Results = request.MakeResultEvent(finalEvent) 295 } 296 } 297 resultEvent := finalEvent.Results[0] 298 require.Equal(t, "1.1.1.1", resultEvent.ExtractedResults[0], "could not get correct extracted results") 299 require.Equal(t, matchedFileName, resultEvent.Matched, "could not get matched value") 300 301 return finalEvent 302 }