github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/utils/variables.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  	"strings"
     7  
     8  	"github.com/projectdiscovery/gologger"
     9  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
    10  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
    11  	maputil "github.com/projectdiscovery/utils/maps"
    12  	urlutil "github.com/projectdiscovery/utils/url"
    13  	"github.com/weppos/publicsuffix-go/publicsuffix"
    14  )
    15  
    16  // KnownVariables are the variables that are known to input requests
    17  var KnownVariables maputil.Map[KnownVariable, string]
    18  
    19  func init() {
    20  	KnownVariables = maputil.Map[KnownVariable, string]{
    21  		BaseURL:  "BaseURL",
    22  		RootURL:  "RootURL",
    23  		Hostname: "Hostname",
    24  		Host:     "Host",
    25  		Port:     "Port",
    26  		Path:     "Path",
    27  		File:     "File",
    28  		Scheme:   "Scheme",
    29  		Input:    "Input",
    30  		Fqdn:     "FQDN",
    31  		Rdn:      "RDN",
    32  		Dn:       "DN",
    33  		Tld:      "TLD",
    34  		Sd:       "SD",
    35  	}
    36  }
    37  
    38  type KnownVariable uint16
    39  
    40  const (
    41  	BaseURL KnownVariable = iota
    42  	RootURL
    43  	Hostname
    44  	Host
    45  	Port
    46  	Path
    47  	File
    48  	Scheme
    49  	Input
    50  	Fqdn
    51  	Rdn
    52  	Dn
    53  	Tld
    54  	Sd
    55  )
    56  
    57  // GenerateVariables will create default variables with context args
    58  func GenerateVariablesWithContextArgs(input *contextargs.Context, trailingSlash bool) map[string]interface{} {
    59  	parsed, err := urlutil.Parse(input.MetaInput.Input)
    60  	if err != nil {
    61  		return nil
    62  	}
    63  	return GenerateVariables(parsed, trailingSlash, contextargs.GenerateVariables(input))
    64  }
    65  
    66  // GenerateDNSVariables from a dns name
    67  // This function is used by dns and ssl protocol to generate variables
    68  func GenerateDNSVariables(domain string) map[string]interface{} {
    69  	parsed, err := publicsuffix.Parse(strings.TrimSuffix(domain, "."))
    70  	if err != nil {
    71  		return map[string]interface{}{"FQDN": domain}
    72  	}
    73  
    74  	domainName := strings.Join([]string{parsed.SLD, parsed.TLD}, ".")
    75  	dnsVariables := make(map[string]interface{})
    76  	for k, v := range KnownVariables {
    77  		switch k {
    78  		case Fqdn:
    79  			dnsVariables[v] = domain
    80  		case Rdn:
    81  			dnsVariables[v] = domainName
    82  		case Dn:
    83  			dnsVariables[v] = parsed.SLD
    84  		case Tld:
    85  			dnsVariables[v] = parsed.TLD
    86  		case Sd:
    87  			dnsVariables[v] = parsed.TRD
    88  		}
    89  	}
    90  	return dnsVariables
    91  }
    92  
    93  // GenerateVariables accepts string or *urlutil.URL object as input
    94  // Returns the map of KnownVariables keys
    95  // This function is used by http, headless, websocket, network and whois protocols to generate protocol variables
    96  func GenerateVariables(input interface{}, removeTrailingSlash bool, additionalVars map[string]interface{}) map[string]interface{} {
    97  	var vars = make(map[string]interface{})
    98  	switch input := input.(type) {
    99  	case string:
   100  		parsed, err := urlutil.Parse(input)
   101  		if err != nil {
   102  			return map[string]interface{}{KnownVariables[Input]: input, KnownVariables[Hostname]: input}
   103  		}
   104  		vars = generateVariables(parsed, removeTrailingSlash)
   105  	case *urlutil.URL:
   106  		vars = generateVariables(input, removeTrailingSlash)
   107  	case urlutil.URL:
   108  		vars = generateVariables(&input, removeTrailingSlash)
   109  	default:
   110  		// return a non-fatal error
   111  		gologger.Error().Msgf("unknown type %T for input %v", input, input)
   112  	}
   113  	return generators.MergeMaps(vars, additionalVars)
   114  }
   115  
   116  func generateVariables(inputURL *urlutil.URL, removeTrailingSlash bool) map[string]interface{} {
   117  	parsed := inputURL.Clone()
   118  	parsed.Params = urlutil.NewOrderedParams()
   119  	port := parsed.Port()
   120  	if port == "" {
   121  		if parsed.Scheme == "https" {
   122  			port = "443"
   123  		} else if parsed.Scheme == "http" {
   124  			port = "80"
   125  		}
   126  	}
   127  	if removeTrailingSlash {
   128  		parsed.Path = strings.TrimSuffix(parsed.Path, "/")
   129  	}
   130  	escapedPath := parsed.EscapedPath()
   131  	requestPath := path.Dir(escapedPath)
   132  	if requestPath == "." {
   133  		requestPath = ""
   134  	}
   135  
   136  	base := path.Base(escapedPath)
   137  	if base == "." {
   138  		base = ""
   139  	}
   140  
   141  	if parsed.Scheme == "ws" {
   142  		if values := urlutil.GetParams(parsed.URL.Query()); len(values) > 0 {
   143  			requestPath = escapedPath + "?" + values.Encode()
   144  		}
   145  	}
   146  	knownVariables := make(map[string]interface{})
   147  	for k, v := range KnownVariables {
   148  		switch k {
   149  		case BaseURL:
   150  			knownVariables[v] = parsed.String()
   151  		case RootURL:
   152  			knownVariables[v] = fmt.Sprintf("%s://%s", parsed.Scheme, parsed.Host)
   153  		case Hostname:
   154  			knownVariables[v] = parsed.Host
   155  		case Host:
   156  			knownVariables[v] = parsed.Hostname()
   157  		case Port:
   158  			knownVariables[v] = port
   159  		case Path:
   160  			knownVariables[v] = requestPath
   161  		case File:
   162  			knownVariables[v] = base
   163  		case Scheme:
   164  			knownVariables[v] = parsed.Scheme
   165  		case Input:
   166  			knownVariables[v] = parsed.String()
   167  		}
   168  	}
   169  	return generators.MergeMaps(knownVariables, GenerateDNSVariables(parsed.Hostname()))
   170  }