github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/headless/operators.go (about)

     1  package headless
     2  
     3  import (
     4  	"strconv"
     5  	"time"
     6  
     7  	"github.com/projectdiscovery/nuclei/v2/pkg/model"
     8  	"github.com/projectdiscovery/nuclei/v2/pkg/operators"
     9  	"github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors"
    10  	"github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers"
    11  	"github.com/projectdiscovery/nuclei/v2/pkg/output"
    12  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
    13  	"github.com/projectdiscovery/nuclei/v2/pkg/types"
    14  )
    15  
    16  // Match matches a generic data response again a given matcher
    17  func (request *Request) Match(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string) {
    18  	itemStr, ok := request.getMatchPart(matcher.Part, data)
    19  	if !ok && matcher.Type.MatcherType != matchers.DSLMatcher {
    20  		return false, []string{}
    21  	}
    22  
    23  	switch matcher.GetType() {
    24  	case matchers.StatusMatcher:
    25  		statusCode, ok := getStatusCode(data)
    26  		if !ok {
    27  			return false, []string{}
    28  		}
    29  		return matcher.Result(matcher.MatchStatusCode(statusCode)), []string{}
    30  	case matchers.SizeMatcher:
    31  		return matcher.Result(matcher.MatchSize(len(itemStr))), []string{}
    32  	case matchers.WordsMatcher:
    33  		return matcher.ResultWithMatchedSnippet(matcher.MatchWords(itemStr, data))
    34  	case matchers.RegexMatcher:
    35  		return matcher.ResultWithMatchedSnippet(matcher.MatchRegex(itemStr))
    36  	case matchers.BinaryMatcher:
    37  		return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(itemStr))
    38  	case matchers.DSLMatcher:
    39  		return matcher.Result(matcher.MatchDSL(data)), []string{}
    40  	case matchers.XPathMatcher:
    41  		return matcher.Result(matcher.MatchXPath(itemStr)), []string{}
    42  	}
    43  	return false, []string{}
    44  }
    45  
    46  func getStatusCode(data map[string]interface{}) (int, bool) {
    47  	statusCodeValue, ok := data["status_code"]
    48  	if !ok {
    49  		return 0, false
    50  	}
    51  	statusCodeStr, ok := statusCodeValue.(string)
    52  	if !ok {
    53  		return 0, false
    54  	}
    55  
    56  	statusCode, err := strconv.Atoi(statusCodeStr)
    57  	if err != nil {
    58  		return 0, false
    59  	}
    60  
    61  	return statusCode, true
    62  }
    63  
    64  // Extract performs extracting operation for an extractor on model and returns true or false.
    65  func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
    66  	itemStr, ok := request.getMatchPart(extractor.Part, data)
    67  	if !ok && !extractors.SupportsMap(extractor) {
    68  		return nil
    69  	}
    70  
    71  	switch extractor.GetType() {
    72  	case extractors.RegexExtractor:
    73  		return extractor.ExtractRegex(itemStr)
    74  	case extractors.KValExtractor:
    75  		return extractor.ExtractKval(data)
    76  	case extractors.DSLExtractor:
    77  		return extractor.ExtractDSL(data)
    78  	}
    79  	return nil
    80  }
    81  
    82  func (request *Request) getMatchPart(part string, data output.InternalEvent) (string, bool) {
    83  	switch part {
    84  	case "body", "resp", "":
    85  		part = "data"
    86  	case "history":
    87  		part = "history"
    88  	case "header":
    89  		part = "header"
    90  	}
    91  
    92  	item, ok := data[part]
    93  	if !ok {
    94  		return "", false
    95  	}
    96  	itemStr := types.ToString(item)
    97  
    98  	return itemStr, true
    99  }
   100  
   101  // responseToDSLMap converts a headless response to a map for use in DSL matching
   102  func (request *Request) responseToDSLMap(resp, headers, status_code, req, host, matched string, history string) output.InternalEvent {
   103  	return output.InternalEvent{
   104  		"host":          host,
   105  		"matched":       matched,
   106  		"req":           req,
   107  		"data":          resp,
   108  		"header":        headers,
   109  		"status_code":   status_code,
   110  		"history":       history,
   111  		"type":          request.Type().String(),
   112  		"template-id":   request.options.TemplateID,
   113  		"template-info": request.options.TemplateInfo,
   114  		"template-path": request.options.TemplatePath,
   115  	}
   116  }
   117  
   118  // MakeResultEvent creates a result event from internal wrapped event
   119  func (request *Request) MakeResultEvent(wrapped *output.InternalWrappedEvent) []*output.ResultEvent {
   120  	return protocols.MakeDefaultResultEvent(request, wrapped)
   121  }
   122  
   123  func (request *Request) GetCompiledOperators() []*operators.Operators {
   124  	return []*operators.Operators{request.CompiledOperators}
   125  }
   126  
   127  func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent {
   128  	data := &output.ResultEvent{
   129  		TemplateID:       types.ToString(wrapped.InternalEvent["template-id"]),
   130  		TemplatePath:     types.ToString(wrapped.InternalEvent["template-path"]),
   131  		Info:             wrapped.InternalEvent["template-info"].(model.Info),
   132  		Type:             types.ToString(wrapped.InternalEvent["type"]),
   133  		Host:             types.ToString(wrapped.InternalEvent["host"]),
   134  		Matched:          types.ToString(wrapped.InternalEvent["matched"]),
   135  		ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
   136  		Timestamp:        time.Now(),
   137  		MatcherStatus:    true,
   138  		IP:               types.ToString(wrapped.InternalEvent["ip"]),
   139  		Request:          types.ToString(wrapped.InternalEvent["request"]),
   140  		Response:         types.ToString(wrapped.InternalEvent["data"]),
   141  	}
   142  	return data
   143  }