2021-12-16 17:08:02 +05:30
package whois
import (
"net/url"
"strings"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
2022-11-08 12:57:18 +01:00
"github.com/projectdiscovery/rdap"
2021-12-16 17:08:02 +05:30
"github.com/projectdiscovery/gologger"
2023-10-17 17:44:13 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/extractors"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/whois/rdapclientpool"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
2021-12-16 17:08:02 +05:30
)
// Request is a request for the WHOIS protocol
type Request struct {
// Operators for the current request go here.
2023-02-07 16:10:40 +08:00
operators . Operators ` yaml:",inline,omitempty" json:",inline,omitempty" `
CompiledOperators * operators . Operators ` yaml:"-" json:"-" `
2021-12-16 17:08:02 +05:30
2023-08-31 18:03:01 +05:30
// ID is the optional id of the request
ID string ` yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID of the network request" `
2021-12-16 17:08:02 +05:30
// description: |
// Query contains query for the request
2023-02-07 16:10:40 +08:00
Query string ` yaml:"query,omitempty" json:"query,omitempty" jsonschema:"title=query for the WHOIS request,description=Query contains query for the request" `
2021-12-16 17:08:02 +05:30
// description: |
// Optional WHOIS server URL.
//
// If present, specifies the WHOIS server to execute the Request on.
// Otherwise, nil enables bootstrapping
2023-02-07 16:10:40 +08:00
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" `
2021-12-16 17:08:02 +05:30
// cache any variables that may be needed for operation.
client * rdap . Client
2023-05-31 16:58:10 -04:00
options * protocols . ExecutorOptions
2021-12-16 17:08:02 +05:30
parsedServerURL * url . URL
}
// Compile compiles the request generators preparing any requests possible.
2023-05-31 16:58:10 -04:00
func ( request * Request ) Compile ( options * protocols . ExecutorOptions ) error {
2021-12-16 17:08:02 +05:30
var err error
if request . Server != "" {
request . parsedServerURL , err = url . Parse ( request . Server )
if err != nil {
return errors . Wrap ( err , "failed to parse server URL" )
}
}
request . options = options
2022-11-08 12:57:18 +01:00
request . client , _ = rdapclientpool . Get ( options . Options , nil )
2021-12-16 17:08:02 +05:30
if len ( request . Matchers ) > 0 || len ( request . Extractors ) > 0 {
compiled := & request . Operators
2022-06-24 23:09:27 +05:30
compiled . ExcludeMatchers = options . ExcludeMatchers
compiled . TemplateID = options . TemplateID
2021-12-16 17:08:02 +05:30
if err := compiled . Compile ( ) ; err != nil {
return errors . Wrap ( err , "could not compile operators" )
}
request . CompiledOperators = compiled
}
return nil
}
// Requests returns the total number of requests the rule will perform
func ( request * Request ) Requests ( ) int {
return 1
}
// GetID returns the ID for the request if any.
func ( request * Request ) GetID ( ) string {
return ""
}
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
2022-10-03 12:12:20 +02:00
func ( request * Request ) ExecuteWithResults ( input * contextargs . Context , dynamicValues , previous output . InternalEvent , callback protocols . OutputEventCallback ) error {
2021-12-16 17:08:02 +05:30
// generate variables
2023-05-02 23:49:56 +05:30
defaultVars := protocolutils . GenerateVariables ( input . MetaInput . Input , false , nil )
2023-04-12 01:50:58 +05:30
optionVars := generators . BuildPayloadFromOptions ( request . options . Options )
2023-06-09 19:52:56 +05:30
// add templatectx variables to varMap
2023-08-31 18:03:01 +05:30
vars := request . options . Variables . Evaluate ( generators . MergeMaps ( defaultVars , optionVars , dynamicValues , request . options . GetTemplateCtx ( input . MetaInput ) . GetAll ( ) ) )
2023-04-12 01:50:58 +05:30
2023-05-25 18:32:35 +02:00
variables := generators . MergeMaps ( vars , defaultVars , optionVars , dynamicValues , request . options . Constants )
2022-08-25 15:37:03 +05:30
2022-11-01 20:28:50 +05:30
if vardump . EnableVarDump {
2024-10-14 21:01:36 +07:00
gologger . Debug ( ) . Msgf ( "Whois Protocol request variables: %s\n" , vardump . DumpVariables ( variables ) )
2022-08-25 15:37:03 +05:30
}
2021-12-16 17:08:02 +05:30
// and replace placeholders
query := replacer . Replace ( request . Query , variables )
// build an rdap request
rdapReq := rdap . NewAutoRequest ( query )
2021-12-21 19:02:09 +05:30
rdapReq . Server = request . parsedServerURL
2021-12-16 17:08:02 +05:30
res , err := request . client . Do ( rdapReq )
if err != nil {
return errors . Wrap ( err , "could not make whois request" )
}
gologger . Verbose ( ) . Msgf ( "Sent WHOIS request to %s" , query )
if request . options . Options . Debug || request . options . Options . DebugRequests {
gologger . Debug ( ) . Msgf ( "[%s] Dumped WHOIS request for %s" , request . options . TemplateID , query )
}
data := make ( map [ string ] interface { } )
var response interface { }
switch rdapReq . Type {
case rdap . DomainRequest :
// convert the rdap response to a whois style response (for domain request type only)
whoisResp := res . ToWhoisStyleResponse ( )
for k , v := range whoisResp . Data {
data [ strings . ToLower ( k ) ] = strings . Join ( v , "," )
}
response = whoisResp
default :
response = res . Object
}
jsonData , _ := jsoniter . Marshal ( response )
jsonDataString := string ( jsonData )
data [ "type" ] = request . Type ( ) . String ( )
data [ "host" ] = query
data [ "response" ] = jsonDataString
2023-06-09 19:52:56 +05:30
// add response fields to template context and merge templatectx variables to output event
2023-08-31 18:03:01 +05:30
request . options . AddTemplateVars ( input . MetaInput , request . Type ( ) , request . ID , data )
data = generators . MergeMaps ( data , request . options . GetTemplateCtx ( input . MetaInput ) . GetAll ( ) )
2023-06-09 19:52:56 +05:30
2021-12-16 17:08:02 +05:30
event := eventcreator . CreateEvent ( request , data , request . options . Options . Debug || request . options . Options . DebugResponse )
if request . options . Options . Debug || request . options . Options . DebugResponse {
gologger . Debug ( ) . Msgf ( "[%s] Dumped WHOIS response for %s" , request . options . TemplateID , query )
gologger . Print ( ) . Msgf ( "%s" , responsehighlighter . Highlight ( event . OperatorsResult , jsonDataString , request . options . Options . NoColor , false ) )
}
callback ( event )
return nil
}
// Match performs matching operation for a matcher on model and returns:
// true and a list of matched snippets if the matcher type is supports it
// otherwise false and an empty string slice
func ( request * Request ) Match ( data map [ string ] interface { } , matcher * matchers . Matcher ) ( bool , [ ] string ) {
return protocols . MakeDefaultMatchFunc ( data , matcher )
}
// Extract performs extracting operation for an extractor on model and returns true or false.
func ( request * Request ) Extract ( data map [ string ] interface { } , matcher * extractors . Extractor ) map [ string ] struct { } {
return protocols . MakeDefaultExtractFunc ( data , matcher )
}
// MakeResultEvent creates a result event from internal wrapped event
func ( request * Request ) MakeResultEvent ( wrapped * output . InternalWrappedEvent ) [ ] * output . ResultEvent {
return protocols . MakeDefaultResultEvent ( request , wrapped )
}
// GetCompiledOperators returns a list of the compiled operators
func ( request * Request ) GetCompiledOperators ( ) [ ] * operators . Operators {
return [ ] * operators . Operators { request . CompiledOperators }
}
func ( request * Request ) MakeResultEventItem ( wrapped * output . InternalWrappedEvent ) * output . ResultEvent {
data := & output . ResultEvent {
TemplateID : types . ToString ( request . options . TemplateID ) ,
TemplatePath : types . ToString ( request . options . TemplatePath ) ,
Info : request . options . TemplateInfo ,
2024-09-19 18:58:20 +05:30
TemplateVerifier : request . options . TemplateVerifier ,
2021-12-16 17:08:02 +05:30
Type : types . ToString ( wrapped . InternalEvent [ "type" ] ) ,
Host : types . ToString ( wrapped . InternalEvent [ "host" ] ) ,
Metadata : wrapped . OperatorsResult . PayloadValues ,
ExtractedResults : wrapped . OperatorsResult . OutputExtracts ,
Timestamp : time . Now ( ) ,
MatcherStatus : true ,
Request : types . ToString ( wrapped . InternalEvent [ "request" ] ) ,
Response : types . ToString ( wrapped . InternalEvent [ "response" ] ) ,
2023-11-11 02:12:27 +03:00
TemplateEncoded : request . options . EncodeTemplate ( ) ,
2023-11-27 19:54:45 +01:00
Error : types . ToString ( wrapped . InternalEvent [ "error" ] ) ,
2021-12-16 17:08:02 +05:30
}
return data
}
// Type returns the type of the protocol request
func ( request * Request ) Type ( ) templateTypes . ProtocolType {
return templateTypes . WHOISProtocol
}
2025-07-09 14:47:26 -05:00
// UpdateOptions replaces this request's options with a new copy
func ( r * Request ) UpdateOptions ( opts * protocols . ExecutorOptions ) {
r . options . ApplyNewEngineOptions ( opts )
}