Path: blob/dev/pkg/protocols/headless/operators.go
2844 views
package headless12import (3"strconv"4"time"56"github.com/projectdiscovery/nuclei/v3/pkg/model"7"github.com/projectdiscovery/nuclei/v3/pkg/operators"8"github.com/projectdiscovery/nuclei/v3/pkg/operators/extractors"9"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"10"github.com/projectdiscovery/nuclei/v3/pkg/output"11"github.com/projectdiscovery/nuclei/v3/pkg/protocols"12protocolUtils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"13"github.com/projectdiscovery/nuclei/v3/pkg/types"14)1516// Match matches a generic data response again a given matcher17func (request *Request) Match(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string) {18itemStr, ok := request.getMatchPart(matcher.Part, data)19if !ok && matcher.Type.MatcherType != matchers.DSLMatcher {20return false, []string{}21}2223switch matcher.GetType() {24case matchers.StatusMatcher:25statusCode, ok := getStatusCode(data)26if !ok {27return false, []string{}28}29return matcher.Result(matcher.MatchStatusCode(statusCode)), []string{}30case matchers.SizeMatcher:31return matcher.Result(matcher.MatchSize(len(itemStr))), []string{}32case matchers.WordsMatcher:33return matcher.ResultWithMatchedSnippet(matcher.MatchWords(itemStr, data))34case matchers.RegexMatcher:35return matcher.ResultWithMatchedSnippet(matcher.MatchRegex(itemStr))36case matchers.BinaryMatcher:37return matcher.ResultWithMatchedSnippet(matcher.MatchBinary(itemStr))38case matchers.DSLMatcher:39return matcher.Result(matcher.MatchDSL(data)), []string{}40case matchers.XPathMatcher:41return matcher.Result(matcher.MatchXPath(itemStr)), []string{}42}43return false, []string{}44}4546func getStatusCode(data map[string]interface{}) (int, bool) {47statusCodeValue, ok := data["status_code"]48if !ok {49return 0, false50}51statusCodeStr, ok := statusCodeValue.(string)52if !ok {53return 0, false54}5556statusCode, err := strconv.Atoi(statusCodeStr)57if err != nil {58return 0, false59}6061return statusCode, true62}6364// Extract performs extracting operation for an extractor on model and returns true or false.65func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {66itemStr, ok := request.getMatchPart(extractor.Part, data)67if !ok && !extractors.SupportsMap(extractor) {68return nil69}7071switch extractor.GetType() {72case extractors.RegexExtractor:73return extractor.ExtractRegex(itemStr)74case extractors.KValExtractor:75return extractor.ExtractKval(data)76case extractors.DSLExtractor:77return extractor.ExtractDSL(data)78case extractors.XPathExtractor:79return extractor.ExtractXPath(itemStr)80case extractors.JSONExtractor:81return extractor.ExtractJSON(itemStr)82}83return nil84}8586func (request *Request) getMatchPart(part string, data output.InternalEvent) (string, bool) {87switch part {88case "body", "resp", "":89part = "data"90case "history":91part = "history"92case "header":93part = "header"94}9596item, ok := data[part]97if !ok {98return "", false99}100itemStr := types.ToString(item)101102return itemStr, true103}104105// responseToDSLMap converts a headless response to a map for use in DSL matching106func (request *Request) responseToDSLMap(resp, headers, status_code, req, host, matched string, history string) output.InternalEvent {107return output.InternalEvent{108"host": host,109"matched": matched,110"req": req,111"data": resp,112"header": headers,113"status_code": status_code,114"history": history,115"type": request.Type().String(),116"template-id": request.options.TemplateID,117"template-info": request.options.TemplateInfo,118"template-path": request.options.TemplatePath,119}120}121122// MakeResultEvent creates a result event from internal wrapped event123func (request *Request) MakeResultEvent(wrapped *output.InternalWrappedEvent) []*output.ResultEvent {124return protocols.MakeDefaultResultEvent(request, wrapped)125}126127func (request *Request) GetCompiledOperators() []*operators.Operators {128return []*operators.Operators{request.CompiledOperators}129}130131func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent {132fields := protocolUtils.GetJsonFieldsFromURL(types.ToString(wrapped.InternalEvent["host"]))133if types.ToString(wrapped.InternalEvent["ip"]) != "" {134fields.Ip = types.ToString(wrapped.InternalEvent["ip"])135}136if types.ToString(wrapped.InternalEvent["path"]) != "" {137fields.Path = types.ToString(wrapped.InternalEvent["path"])138}139data := &output.ResultEvent{140TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),141TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),142Info: wrapped.InternalEvent["template-info"].(model.Info),143TemplateVerifier: request.options.TemplateVerifier,144Type: types.ToString(wrapped.InternalEvent["type"]),145Host: fields.Host,146Path: fields.Path,147Port: fields.Port,148Scheme: fields.Scheme,149URL: fields.URL,150Matched: types.ToString(wrapped.InternalEvent["matched"]),151ExtractedResults: wrapped.OperatorsResult.OutputExtracts,152Timestamp: time.Now(),153MatcherStatus: true,154IP: fields.Ip,155Request: types.ToString(wrapped.InternalEvent["request"]),156Response: types.ToString(wrapped.InternalEvent["data"]),157TemplateEncoded: request.options.EncodeTemplate(),158Error: types.ToString(wrapped.InternalEvent["error"]),159}160return data161}162163164