Path: blob/dev/pkg/protocols/file/operators_test.go
2070 views
package file12import (3"testing"45"github.com/stretchr/testify/require"67"github.com/projectdiscovery/nuclei/v3/pkg/model"8"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"9"github.com/projectdiscovery/nuclei/v3/pkg/operators"10"github.com/projectdiscovery/nuclei/v3/pkg/operators/extractors"11"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"12"github.com/projectdiscovery/nuclei/v3/pkg/output"13"github.com/projectdiscovery/nuclei/v3/pkg/testutils"14)1516func newMockOperator() operators.Operators {17operators := operators.Operators{18Matchers: []*matchers.Matcher{19{20Type: matchers.MatcherTypeHolder{21MatcherType: matchers.WordsMatcher,22},23},24},25}26return operators27}2829func TestResponseToDSLMap(t *testing.T) {30options := testutils.DefaultOptions3132testutils.Init(options)33templateID := "testing-file"34request := &Request{35ID: templateID,36MaxSize: "1Gb",37NoRecursive: false,38Extensions: []string{"*", ".lock"},39DenyList: []string{".go"},40Operators: newMockOperator(),41}42executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{43ID: templateID,44Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},45})46err := request.Compile(executerOpts)47require.Nil(t, err, "could not compile file request")4849resp := "test-data\r\n"50event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")51require.Len(t, event, 7, "could not get correct number of items in dsl map")52require.Equal(t, resp, event["raw"], "could not get correct resp")53}5455func TestFileOperatorMatch(t *testing.T) {56options := testutils.DefaultOptions5758testutils.Init(options)59templateID := "testing-file"60request := &Request{61ID: templateID,62MaxSize: "1Gb",63NoRecursive: false,64Extensions: []string{"*", ".lock"},65DenyList: []string{".go"},66Operators: newMockOperator(),67}68executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{69ID: templateID,70Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},71})72err := request.Compile(executerOpts)73require.Nil(t, err, "could not compile file request")7475resp := "test-data\r\n1.1.1.1\r\n"76event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")77require.Len(t, event, 7, "could not get correct number of items in dsl map")78require.Equal(t, resp, event["raw"], "could not get correct resp")7980t.Run("valid", func(t *testing.T) {81matcher := &matchers.Matcher{82Part: "raw",83Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},84Words: []string{"1.1.1.1"},85}86err = matcher.CompileMatchers()87require.Nil(t, err, "could not compile matcher")8889isMatched, matched := request.Match(event, matcher)90require.True(t, isMatched, "could not match valid response")91require.Equal(t, matcher.Words, matched)92})9394t.Run("negative", func(t *testing.T) {95matcher := &matchers.Matcher{96Part: "raw",97Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},98Negative: true,99Words: []string{"random"},100}101err := matcher.CompileMatchers()102require.Nil(t, err, "could not compile negative matcher")103104isMatched, matched := request.Match(event, matcher)105require.True(t, isMatched, "could not match valid negative response matcher")106require.Equal(t, []string{}, matched)107})108109t.Run("invalid", func(t *testing.T) {110matcher := &matchers.Matcher{111Part: "raw",112Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},113Words: []string{"random"},114}115err := matcher.CompileMatchers()116require.Nil(t, err, "could not compile matcher")117118isMatched, matched := request.Match(event, matcher)119require.False(t, isMatched, "could match invalid response matcher")120require.Equal(t, []string{}, matched)121})122123t.Run("caseInsensitive", func(t *testing.T) {124resp := "TEST-DATA\r\n1.1.1.1\r\n"125event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")126require.Len(t, event, 7, "could not get correct number of items in dsl map")127require.Equal(t, resp, event["raw"], "could not get correct resp")128129matcher := &matchers.Matcher{130Part: "raw",131Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},132Words: []string{"TeSt-DaTA"},133CaseInsensitive: true,134}135err = matcher.CompileMatchers()136require.Nil(t, err, "could not compile matcher")137138isMatched, matched := request.Match(event, matcher)139require.True(t, isMatched, "could not match valid response")140require.Equal(t, []string{"test-data"}, matched)141})142}143144func TestFileOperatorExtract(t *testing.T) {145options := testutils.DefaultOptions146147testutils.Init(options)148templateID := "testing-file"149request := &Request{150ID: templateID,151MaxSize: "1Gb",152NoRecursive: false,153Extensions: []string{"*", ".lock"},154DenyList: []string{".go"},155Operators: newMockOperator(),156}157executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{158ID: templateID,159Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},160})161err := request.Compile(executerOpts)162require.Nil(t, err, "could not compile file request")163164resp := "test-data\r\n1.1.1.1\r\n"165event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")166require.Len(t, event, 7, "could not get correct number of items in dsl map")167require.Equal(t, resp, event["raw"], "could not get correct resp")168169t.Run("extract", func(t *testing.T) {170extractor := &extractors.Extractor{171Part: "raw",172Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},173Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"},174}175err = extractor.CompileExtractors()176require.Nil(t, err, "could not compile extractor")177178data := request.Extract(event, extractor)179require.Greater(t, len(data), 0, "could not extractor valid response")180require.Equal(t, map[string]struct{}{"1.1.1.1": {}}, data, "could not extract correct data")181})182183t.Run("kval", func(t *testing.T) {184extractor := &extractors.Extractor{185Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.KValExtractor},186KVal: []string{"raw"},187}188err = extractor.CompileExtractors()189require.Nil(t, err, "could not compile kval extractor")190191data := request.Extract(event, extractor)192require.Greater(t, len(data), 0, "could not extractor kval valid response")193require.Equal(t, map[string]struct{}{resp: {}}, data, "could not extract correct kval data")194})195}196197func TestFileMakeResultWithOrMatcher(t *testing.T) {198expectedValue := []string{"1.1.1.1"}199namedMatcherName := "test"200201finalEvent := testFileMakeResultOperators(t, "or")202require.Equal(t, namedMatcherName, finalEvent.Results[0].MatcherName)203require.Equal(t, expectedValue, finalEvent.OperatorsResult.Matches[namedMatcherName], "could not get matched value")204}205206func TestFileMakeResultWithAndMatcher(t *testing.T) {207finalEvent := testFileMakeResultOperators(t, "and")208require.Equal(t, "", finalEvent.Results[0].MatcherName)209require.Empty(t, finalEvent.OperatorsResult.Matches)210}211212func testFileMakeResultOperators(t *testing.T, matcherCondition string) *output.InternalWrappedEvent {213expectedValue := []string{"1.1.1.1"}214namedMatcherName := "test"215matcher := []*matchers.Matcher{216{217Part: "raw",218Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},219Words: expectedValue,220},221{222Name: namedMatcherName,223Part: "raw",224Type: matchers.MatcherTypeHolder{MatcherType: matchers.WordsMatcher},225Words: expectedValue,226},227}228229expectedValues := map[string][]string{230"word-1": expectedValue,231namedMatcherName: expectedValue,232}233234finalEvent := testFileMakeResult(t, matcher, matcherCondition, true)235for matcherName, matchedValues := range expectedValues {236var matchesOne = false237for i := 0; i <= len(expectedValue); i++ {238resultEvent := finalEvent.Results[i]239if matcherName == resultEvent.MatcherName {240matchesOne = true241}242}243require.True(t, matchesOne)244require.Equal(t, matchedValues, finalEvent.OperatorsResult.Matches[matcherName], "could not get matched value")245}246247finalEvent = testFileMakeResult(t, matcher, matcherCondition, false)248require.Equal(t, 1, len(finalEvent.Results))249return finalEvent250}251252func testFileMakeResult(t *testing.T, matchers []*matchers.Matcher, matcherCondition string, isDebug bool) *output.InternalWrappedEvent {253options := testutils.DefaultOptions254255testutils.Init(options)256templateID := "testing-file"257executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{258ID: templateID,259Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"},260})261request := &Request{262ID: templateID,263MaxSize: "1Gb",264NoRecursive: false,265Extensions: []string{"*", ".lock"},266DenyList: []string{".go"},267Operators: operators.Operators{268MatchersCondition: matcherCondition,269Matchers: matchers,270Extractors: []*extractors.Extractor{{271Part: "raw",272Type: extractors.ExtractorTypeHolder{ExtractorType: extractors.RegexExtractor},273Regex: []string{"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"},274}},275},276options: executerOpts,277}278err := request.Compile(executerOpts)279require.Nil(t, err, "could not compile file request")280281matchedFileName := "test.txt"282fileContent := "test-data\r\n1.1.1.1\r\n"283284event := request.responseToDSLMap(fileContent, "/tmp", matchedFileName)285require.Len(t, event, 7, "could not get correct number of items in dsl map")286require.Equal(t, fileContent, event["raw"], "could not get correct resp")287288finalEvent := &output.InternalWrappedEvent{InternalEvent: event}289if request.CompiledOperators != nil {290result, ok := request.CompiledOperators.Execute(event, request.Match, request.Extract, isDebug)291if ok && result != nil {292finalEvent.OperatorsResult = result293finalEvent.Results = request.MakeResultEvent(finalEvent)294}295}296resultEvent := finalEvent.Results[0]297require.Equal(t, "1.1.1.1", resultEvent.ExtractedResults[0], "could not get correct extracted results")298require.Equal(t, matchedFileName, resultEvent.Matched, "could not get matched value")299300return finalEvent301}302303304