package matchers import ( "regexp" "github.com/Knetic/govaluate" ) // Matcher is used to match a part in the output from a protocol. type Matcher struct { // description: | // Type is the type of the matcher. // values: // - "status" // - "size" // - "word" // - "regex" // - "binary" // - "dsl" Type string `yaml:"type" jsonschema:"title=type of matcher,description=Type of the matcher,enum=status,enum=size,enum=word,enum=regex,enum=binary,enum=dsl"` // description: | // Condition is the optional condition between two matcher variables. By default, // the condition is assumed to be OR. // values: // - "and" // - "or" Condition string `yaml:"condition,omitempty" jsonschema:"title=condition between matcher variables,description=Condition between the matcher variables,enum=and,enum=or"` // description: | // Part is the part of the request response to match data from. // // Each protocol exposes a lot of different parts which are well // documented in docs for each request type. // examples: // - value: "\"body\"" // - value: "\"raw\"" Part string `yaml:"part,omitempty" jsonschema:"title=part of response to match,description=Part of response to match data from"` // description: | // Negative specifies if the match should be reversed // It will only match if the condition is not true. Negative bool `yaml:"negative,omitempty" jsonschema:"title=negative specifies if match reversed,description=Negative specifies if the match should be reversed. It will only match if the condition is not true"` // description: | // Name of the matcher. Name should be lowercase and must not contain // spaces or underscores (_). // examples: // - value: "\"cookie-matcher\"" Name string `yaml:"name,omitempty" jsonschema:"title=name of the matcher,description=Name of the matcher"` // description: | // Status are the acceptable status codes for the response. // examples: // - value: > // []int{200, 302} Status []int `yaml:"status,omitempty" jsonschema:"title=status to match,description=Status to match for the response"` // description: | // Size is the acceptable size for the response // examples: // - value: > // []int{3029, 2042} Size []int `yaml:"size,omitempty" jsonschema:"title=acceptable size for response,description=Size is the acceptable size for the response"` // description: | // Words contains word patterns required to be present in the response part. // examples: // - name: Match for outlook mail protection domain // value: > // []string{"mail.protection.outlook.com"} // - name: Match for application/json in response headers // value: > // []string{"application/json"} Words []string `yaml:"words,omitempty" jsonschema:"title=words to match in response,description= Words contains word patterns required to be present in the response part"` // description: | // Regex contains Regular Expression patterns required to be present in the response part. // examples: // - name: Match for Linkerd Service via Regex // value: > // []string{`(?mi)^Via\\s*?:.*?linkerd.*$`} // - name: Match for Open Redirect via Location header // value: > // []string{`(?m)^(?:Location\\s*?:\\s*?)(?:https?://|//)?(?:[a-zA-Z0-9\\-_\\.@]*)example\\.com.*$`} Regex []string `yaml:"regex,omitempty" jsonschema:"title=regex to match in response,description=Regex contains regex patterns required to be present in the response part"` // description: | // Binary are the binary patterns required to be present in the response part. // examples: // - name: Match for Springboot Heapdump Actuator "JAVA PROFILE", "HPROF", "Gunzip magic byte" // value: > // []string{"4a4156412050524f46494c45", "4850524f46", "1f8b080000000000"} // - name: Match for 7zip files // value: > // []string{"377ABCAF271C"} Binary []string `yaml:"binary,omitempty" jsonschema:"title=binary patterns to match in response,description=Binary are the binary patterns required to be present in the response part"` // description: | // DSL are the dsl expressions that will be evaluated as part of nuclei matching rules. // A list of these helper functions are available [here](https://nuclei.projectdiscovery.io/templating-guide/helper-functions/). // examples: // - name: DSL Matcher for package.json file // value: > // []string{"contains(body, 'packages') && contains(tolower(all_headers), 'application/octet-stream') && status_code == 200"} // - name: DSL Matcher for missing strict transport security header // value: > // []string{"!contains(tolower(all_headers), ''strict-transport-security'')"} DSL []string `yaml:"dsl,omitempty" jsonschema:"title=dsl expressions to match in response,description=DSL are the dsl expressions that will be evaluated as part of nuclei matching rules"` // description: | // Encoding specifies the encoding for the words field if any. // values: // - "hex" Encoding string `yaml:"encoding,omitempty" jsonschema:"title=encoding for word field,description=Optional encoding for the word fields,enum=hex"` // cached data for the compiled matcher condition ConditionType matcherType MatcherType regexCompiled []*regexp.Regexp dslCompiled []*govaluate.EvaluableExpression } // MatcherType is the type of the matcher specified type MatcherType = int const ( // WordsMatcher matches responses with words WordsMatcher MatcherType = iota + 1 // RegexMatcher matches responses with regexes RegexMatcher // BinaryMatcher matches responses with words BinaryMatcher // StatusMatcher matches responses with status codes StatusMatcher // SizeMatcher matches responses with response size SizeMatcher // DSLMatcher matches based upon dsl syntax DSLMatcher ) // MatcherTypes is a table for conversion of matcher type from string. var MatcherTypes = map[string]MatcherType{ "status": StatusMatcher, "size": SizeMatcher, "word": WordsMatcher, "regex": RegexMatcher, "binary": BinaryMatcher, "dsl": DSLMatcher, } // ConditionType is the type of condition for matcher type ConditionType int const ( // ANDCondition matches responses with AND condition in arguments. ANDCondition ConditionType = iota + 1 // ORCondition matches responses with AND condition in arguments. ORCondition ) // ConditionTypes is a table for conversion of condition type from string. var ConditionTypes = map[string]ConditionType{ "and": ANDCondition, "or": ORCondition, } // Result reverts the results of the match if the matcher is of type negative. func (m *Matcher) Result(data bool) bool { if m.Negative { return !data } return data } // GetType returns the type of the matcher func (m *Matcher) GetType() MatcherType { return m.matcherType }