2020-12-21 09:01:32 +00:00
|
|
|
package operators
|
|
|
|
|
|
|
|
import (
|
2020-12-24 20:54:55 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-12-21 09:01:32 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors"
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Operators contains the operators that can be applied on protocols
|
|
|
|
type Operators struct {
|
|
|
|
// Matchers contains the detection mechanism for the request to identify
|
|
|
|
// whether the request was successful
|
|
|
|
Matchers []*matchers.Matcher `yaml:"matchers"`
|
|
|
|
// Extractors contains the extraction mechanism for the request to identify
|
|
|
|
// and extract parts of the response.
|
|
|
|
Extractors []*extractors.Extractor `yaml:"extractors"`
|
|
|
|
// MatchersCondition is the condition of the matchers
|
|
|
|
// whether to use AND or OR. Default is OR.
|
|
|
|
MatchersCondition string `yaml:"matchers-condition"`
|
|
|
|
// cached variables that may be used along with request.
|
|
|
|
matchersCondition matchers.ConditionType
|
|
|
|
}
|
|
|
|
|
2020-12-24 20:54:55 +00:00
|
|
|
// Compile compiles the operators as well as their corresponding matchers and extractors
|
|
|
|
func (r *Operators) Compile() error {
|
|
|
|
if r.MatchersCondition != "" {
|
|
|
|
r.matchersCondition = matchers.ConditionTypes[r.MatchersCondition]
|
|
|
|
} else {
|
2020-12-30 07:56:55 +00:00
|
|
|
r.matchersCondition = matchers.ORCondition
|
2020-12-24 20:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, matcher := range r.Matchers {
|
|
|
|
if err := matcher.CompileMatchers(); err != nil {
|
|
|
|
return errors.Wrap(err, "could not compile matcher")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, extractor := range r.Extractors {
|
|
|
|
if err := extractor.CompileExtractors(); err != nil {
|
|
|
|
return errors.Wrap(err, "could not compile extractor")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-21 09:01:32 +00:00
|
|
|
// GetMatchersCondition returns the condition for the matchers
|
|
|
|
func (r *Operators) GetMatchersCondition() matchers.ConditionType {
|
|
|
|
return r.matchersCondition
|
|
|
|
}
|
2020-12-24 07:26:28 +00:00
|
|
|
|
|
|
|
// Result is a result structure created from operators running on data.
|
|
|
|
type Result struct {
|
|
|
|
// Matches is a map of matcher names that we matched
|
|
|
|
Matches map[string]struct{}
|
|
|
|
// Extracts contains all the data extracted from inputs
|
|
|
|
Extracts map[string][]string
|
2020-12-24 15:17:41 +00:00
|
|
|
// OutputExtracts is the list of extracts to be displayed on screen.
|
|
|
|
OutputExtracts []string
|
2020-12-24 07:26:28 +00:00
|
|
|
// DynamicValues contains any dynamic values to be templated
|
2021-01-01 11:22:41 +00:00
|
|
|
DynamicValues map[string]interface{}
|
2020-12-28 20:00:07 +00:00
|
|
|
// PayloadValues contains payload values provided by user. (Optional)
|
|
|
|
PayloadValues map[string]interface{}
|
2020-12-24 07:26:28 +00:00
|
|
|
}
|
|
|
|
|
2020-12-24 15:17:41 +00:00
|
|
|
// MatchFunc performs matching operation for a matcher on model and returns true or false.
|
|
|
|
type MatchFunc func(data map[string]interface{}, matcher *matchers.Matcher) bool
|
|
|
|
|
|
|
|
// ExtractFunc performs extracting operation for a extractor on model and returns true or false.
|
|
|
|
type ExtractFunc func(data map[string]interface{}, matcher *extractors.Extractor) map[string]struct{}
|
|
|
|
|
2020-12-24 07:26:28 +00:00
|
|
|
// Execute executes the operators on data and returns a result structure
|
2020-12-25 07:25:46 +00:00
|
|
|
func (r *Operators) Execute(data map[string]interface{}, match MatchFunc, extract ExtractFunc) (*Result, bool) {
|
2020-12-24 07:26:28 +00:00
|
|
|
matcherCondition := r.GetMatchersCondition()
|
|
|
|
|
2020-12-30 07:56:55 +00:00
|
|
|
var matches bool
|
2020-12-24 07:26:28 +00:00
|
|
|
result := &Result{
|
|
|
|
Matches: make(map[string]struct{}),
|
|
|
|
Extracts: make(map[string][]string),
|
2021-01-01 11:22:41 +00:00
|
|
|
DynamicValues: make(map[string]interface{}),
|
2020-12-24 07:26:28 +00:00
|
|
|
}
|
|
|
|
for _, matcher := range r.Matchers {
|
|
|
|
// Check if the matcher matched
|
2020-12-24 15:17:41 +00:00
|
|
|
if !match(data, matcher) {
|
2020-12-24 07:26:28 +00:00
|
|
|
// If the condition is AND we haven't matched, try next request.
|
|
|
|
if matcherCondition == matchers.ANDCondition {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If the matcher has matched, and its an OR
|
|
|
|
// write the first output then move to next matcher.
|
2020-12-30 07:56:55 +00:00
|
|
|
if matcherCondition == matchers.ORCondition && matcher.Name != "" {
|
2020-12-24 07:26:28 +00:00
|
|
|
result.Matches[matcher.Name] = struct{}{}
|
|
|
|
}
|
2020-12-30 07:56:55 +00:00
|
|
|
matches = true
|
2020-12-24 07:26:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// All matchers have successfully completed so now start with the
|
|
|
|
// next task which is extraction of input from matchers.
|
|
|
|
for _, extractor := range r.Extractors {
|
2020-12-24 15:17:41 +00:00
|
|
|
var extractorResults []string
|
|
|
|
|
|
|
|
for match := range extract(data, extractor) {
|
2020-12-24 07:26:28 +00:00
|
|
|
extractorResults = append(extractorResults, match)
|
|
|
|
|
|
|
|
if extractor.Internal {
|
|
|
|
if _, ok := result.DynamicValues[extractor.Name]; !ok {
|
|
|
|
result.DynamicValues[extractor.Name] = match
|
|
|
|
}
|
|
|
|
} else {
|
2020-12-24 15:17:41 +00:00
|
|
|
result.OutputExtracts = append(result.OutputExtracts, match)
|
2020-12-24 07:26:28 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-11 15:41:35 +00:00
|
|
|
if len(extractorResults) > 0 && !extractor.Internal && extractor.Name != "" {
|
2020-12-30 07:56:55 +00:00
|
|
|
result.Extracts[extractor.Name] = extractorResults
|
|
|
|
}
|
2020-12-24 07:26:28 +00:00
|
|
|
}
|
|
|
|
|
2020-12-30 07:56:55 +00:00
|
|
|
// Don't print if we have matchers and they have not matched, irregardless of extractor
|
|
|
|
if len(r.Matchers) > 0 && !matches {
|
|
|
|
return nil, false
|
|
|
|
}
|
2020-12-24 07:26:28 +00:00
|
|
|
// Write a final string of output if matcher type is
|
|
|
|
// AND or if we have extractors for the mechanism too.
|
2021-01-17 06:56:45 +00:00
|
|
|
if len(result.Extracts) > 0 || len(result.DynamicValues) > 0 || len(result.OutputExtracts) > 0 || matches {
|
2020-12-24 07:26:28 +00:00
|
|
|
return result, true
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|