github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/whois/whois.go (about) 1 package whois 2 3 import ( 4 "net/url" 5 "strings" 6 "time" 7 8 jsoniter "github.com/json-iterator/go" 9 "github.com/pkg/errors" 10 "github.com/projectdiscovery/rdap" 11 12 "github.com/projectdiscovery/gologger" 13 "github.com/projectdiscovery/nuclei/v2/pkg/operators" 14 "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" 15 "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" 16 "github.com/projectdiscovery/nuclei/v2/pkg/output" 17 "github.com/projectdiscovery/nuclei/v2/pkg/protocols" 18 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" 19 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators" 20 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator" 21 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter" 22 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/replacer" 23 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/utils/vardump" 24 protocolutils "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils" 25 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/whois/rdapclientpool" 26 templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types" 27 28 "github.com/projectdiscovery/nuclei/v2/pkg/types" 29 ) 30 31 // Request is a request for the WHOIS protocol 32 type Request struct { 33 // Operators for the current request go here. 34 operators.Operators `yaml:",inline,omitempty" json:",inline,omitempty"` 35 CompiledOperators *operators.Operators `yaml:"-" json:"-"` 36 37 // description: | 38 // Query contains query for the request 39 Query string `yaml:"query,omitempty" json:"query,omitempty" jsonschema:"title=query for the WHOIS request,description=Query contains query for the request"` 40 41 // description: | 42 // Optional WHOIS server URL. 43 // 44 // If present, specifies the WHOIS server to execute the Request on. 45 // Otherwise, nil enables bootstrapping 46 Server string `yaml:"server,omitempty" json:"server,omitempty" jsonschema:"title=server url to execute the WHOIS request on,description=Server contains the server url to execute the WHOIS request on"` 47 // cache any variables that may be needed for operation. 48 client *rdap.Client 49 options *protocols.ExecutorOptions 50 parsedServerURL *url.URL 51 } 52 53 // Compile compiles the request generators preparing any requests possible. 54 func (request *Request) Compile(options *protocols.ExecutorOptions) error { 55 var err error 56 if request.Server != "" { 57 request.parsedServerURL, err = url.Parse(request.Server) 58 if err != nil { 59 return errors.Wrap(err, "failed to parse server URL") 60 } 61 } 62 63 request.options = options 64 request.client, _ = rdapclientpool.Get(options.Options, nil) 65 66 if len(request.Matchers) > 0 || len(request.Extractors) > 0 { 67 compiled := &request.Operators 68 compiled.ExcludeMatchers = options.ExcludeMatchers 69 compiled.TemplateID = options.TemplateID 70 if err := compiled.Compile(); err != nil { 71 return errors.Wrap(err, "could not compile operators") 72 } 73 request.CompiledOperators = compiled 74 } 75 return nil 76 } 77 78 // Requests returns the total number of requests the rule will perform 79 func (request *Request) Requests() int { 80 return 1 81 } 82 83 // GetID returns the ID for the request if any. 84 func (request *Request) GetID() string { 85 return "" 86 } 87 88 // ExecuteWithResults executes the protocol requests and returns results instead of writing them. 89 func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error { 90 // generate variables 91 defaultVars := protocolutils.GenerateVariables(input.MetaInput.Input, false, nil) 92 optionVars := generators.BuildPayloadFromOptions(request.options.Options) 93 vars := request.options.Variables.Evaluate(generators.MergeMaps(defaultVars, optionVars, dynamicValues)) 94 95 variables := generators.MergeMaps(vars, defaultVars, optionVars, dynamicValues, request.options.Constants) 96 97 if vardump.EnableVarDump { 98 gologger.Debug().Msgf("Protocol request variables: \n%s\n", vardump.DumpVariables(variables)) 99 } 100 101 // and replace placeholders 102 query := replacer.Replace(request.Query, variables) 103 // build an rdap request 104 rdapReq := rdap.NewAutoRequest(query) 105 rdapReq.Server = request.parsedServerURL 106 res, err := request.client.Do(rdapReq) 107 if err != nil { 108 return errors.Wrap(err, "could not make whois request") 109 } 110 gologger.Verbose().Msgf("Sent WHOIS request to %s", query) 111 if request.options.Options.Debug || request.options.Options.DebugRequests { 112 gologger.Debug().Msgf("[%s] Dumped WHOIS request for %s", request.options.TemplateID, query) 113 } 114 115 data := make(map[string]interface{}) 116 var response interface{} 117 switch rdapReq.Type { 118 case rdap.DomainRequest: 119 // convert the rdap response to a whois style response (for domain request type only) 120 whoisResp := res.ToWhoisStyleResponse() 121 for k, v := range whoisResp.Data { 122 data[strings.ToLower(k)] = strings.Join(v, ",") 123 } 124 response = whoisResp 125 default: 126 response = res.Object 127 } 128 jsonData, _ := jsoniter.Marshal(response) 129 jsonDataString := string(jsonData) 130 131 data["type"] = request.Type().String() 132 data["host"] = query 133 data["response"] = jsonDataString 134 135 event := eventcreator.CreateEvent(request, data, request.options.Options.Debug || request.options.Options.DebugResponse) 136 if request.options.Options.Debug || request.options.Options.DebugResponse { 137 gologger.Debug().Msgf("[%s] Dumped WHOIS response for %s", request.options.TemplateID, query) 138 gologger.Print().Msgf("%s", responsehighlighter.Highlight(event.OperatorsResult, jsonDataString, request.options.Options.NoColor, false)) 139 } 140 141 callback(event) 142 return nil 143 } 144 145 // Match performs matching operation for a matcher on model and returns: 146 // true and a list of matched snippets if the matcher type is supports it 147 // otherwise false and an empty string slice 148 func (request *Request) Match(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string) { 149 return protocols.MakeDefaultMatchFunc(data, matcher) 150 } 151 152 // Extract performs extracting operation for an extractor on model and returns true or false. 153 func (request *Request) Extract(data map[string]interface{}, matcher *extractors.Extractor) map[string]struct{} { 154 return protocols.MakeDefaultExtractFunc(data, matcher) 155 } 156 157 // MakeResultEvent creates a result event from internal wrapped event 158 func (request *Request) MakeResultEvent(wrapped *output.InternalWrappedEvent) []*output.ResultEvent { 159 return protocols.MakeDefaultResultEvent(request, wrapped) 160 } 161 162 // GetCompiledOperators returns a list of the compiled operators 163 func (request *Request) GetCompiledOperators() []*operators.Operators { 164 return []*operators.Operators{request.CompiledOperators} 165 } 166 167 func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent { 168 data := &output.ResultEvent{ 169 TemplateID: types.ToString(request.options.TemplateID), 170 TemplatePath: types.ToString(request.options.TemplatePath), 171 Info: request.options.TemplateInfo, 172 Type: types.ToString(wrapped.InternalEvent["type"]), 173 Host: types.ToString(wrapped.InternalEvent["host"]), 174 Metadata: wrapped.OperatorsResult.PayloadValues, 175 ExtractedResults: wrapped.OperatorsResult.OutputExtracts, 176 Timestamp: time.Now(), 177 MatcherStatus: true, 178 Request: types.ToString(wrapped.InternalEvent["request"]), 179 Response: types.ToString(wrapped.InternalEvent["response"]), 180 } 181 return data 182 } 183 184 // Type returns the type of the protocol request 185 func (request *Request) Type() templateTypes.ProtocolType { 186 return templateTypes.WHOISProtocol 187 }