2020-04-03 22:15:39 +00:00
|
|
|
package runner
|
|
|
|
|
|
|
|
import (
|
2020-08-29 13:26:11 +00:00
|
|
|
"errors"
|
|
|
|
"net/url"
|
2020-04-03 22:15:39 +00:00
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/projectdiscovery/gologger"
|
2020-12-29 10:08:14 +00:00
|
|
|
"github.com/projectdiscovery/gologger/formatter"
|
|
|
|
"github.com/projectdiscovery/gologger/levels"
|
2021-01-14 07:51:21 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
|
2020-12-29 10:08:14 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
2020-04-03 22:15:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ParseOptions parses the command line flags provided by a user
|
2021-01-12 09:44:49 +00:00
|
|
|
func ParseOptions(options *types.Options) {
|
2021-01-14 07:51:21 +00:00
|
|
|
err := protocolinit.Init(options)
|
|
|
|
if err != nil {
|
|
|
|
gologger.Fatal().Msgf("Could not initialize protocols: %s\n", err)
|
|
|
|
}
|
|
|
|
|
2020-04-03 22:15:39 +00:00
|
|
|
// Check if stdin pipe was given
|
|
|
|
options.Stdin = hasStdin()
|
|
|
|
|
|
|
|
// Read the inputs and configure the logging
|
2020-12-29 10:08:14 +00:00
|
|
|
configureOutput(options)
|
2020-04-03 22:15:39 +00:00
|
|
|
|
|
|
|
// Show the user the banner
|
|
|
|
showBanner()
|
|
|
|
|
|
|
|
if options.Version {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.Info().Msgf("Current Version: %s\n", Version)
|
2020-04-03 22:15:39 +00:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
2020-10-19 20:44:44 +00:00
|
|
|
if options.TemplatesVersion {
|
|
|
|
config, err := readConfiguration()
|
|
|
|
if err != nil {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.Fatal().Msgf("Could not read template configuration: %s\n", err)
|
2020-10-19 20:44:44 +00:00
|
|
|
}
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.Info().Msgf("Current nuclei-templates version: %s (%s)\n", config.CurrentVersion, config.TemplatesDirectory)
|
2020-10-19 20:44:44 +00:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
2020-04-26 01:18:10 +00:00
|
|
|
|
2020-04-03 22:15:39 +00:00
|
|
|
// Validate the options passed by the user and if any
|
|
|
|
// invalid options have been used, exit.
|
2021-01-14 07:51:21 +00:00
|
|
|
if err = validateOptions(options); err != nil {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.Fatal().Msgf("Program exiting: %s\n", err)
|
2020-04-03 22:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-29 10:08:14 +00:00
|
|
|
// hasStdin returns true if we have stdin input
|
2020-04-03 22:15:39 +00:00
|
|
|
func hasStdin() bool {
|
2020-09-28 10:50:00 +00:00
|
|
|
stat, err := os.Stdin.Stat()
|
2020-04-03 22:15:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2020-08-25 21:24:31 +00:00
|
|
|
|
2020-09-28 10:50:00 +00:00
|
|
|
isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0
|
|
|
|
isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0
|
2020-08-25 21:24:31 +00:00
|
|
|
|
2020-09-28 10:50:00 +00:00
|
|
|
return isPipedFromChrDev || isPipedFromFIFO
|
2020-04-03 22:15:39 +00:00
|
|
|
}
|
2020-08-29 13:26:11 +00:00
|
|
|
|
|
|
|
// validateOptions validates the configuration options passed
|
2020-12-29 10:08:14 +00:00
|
|
|
func validateOptions(options *types.Options) error {
|
2020-08-29 13:26:11 +00:00
|
|
|
// Both verbose and silent flags were used
|
|
|
|
if options.Verbose && options.Silent {
|
|
|
|
return errors.New("both verbose and silent mode specified")
|
|
|
|
}
|
|
|
|
|
2020-08-29 21:02:45 +00:00
|
|
|
if !options.TemplateList {
|
2020-08-29 13:26:11 +00:00
|
|
|
// Check if a list of templates was provided and it exists
|
2021-02-04 12:59:28 +00:00
|
|
|
if len(options.Templates) == 0 && len(options.Tags) == 0 && !options.UpdateTemplates {
|
2020-08-29 13:26:11 +00:00
|
|
|
return errors.New("no template/templates provided")
|
|
|
|
}
|
|
|
|
|
|
|
|
if options.Targets == "" && !options.Stdin && options.Target == "" && !options.UpdateTemplates {
|
|
|
|
return errors.New("no target input provided")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate proxy options if provided
|
2020-12-29 10:08:14 +00:00
|
|
|
err := validateProxyURL(options.ProxyURL, "invalid http proxy format (It should be http://username:password@host:port)")
|
2020-08-29 14:25:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-29 10:08:14 +00:00
|
|
|
err = validateProxyURL(options.ProxySocksURL, "invalid socks proxy format (It should be socks5://username:password@host:port)")
|
2020-08-29 14:25:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-08-29 13:26:11 +00:00
|
|
|
}
|
2020-08-29 14:25:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateProxyURL(proxyURL, message string) error {
|
|
|
|
if proxyURL != "" && !isValidURL(proxyURL) {
|
|
|
|
return errors.New(message)
|
2020-08-29 13:26:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:25:30 +00:00
|
|
|
func isValidURL(urlString string) bool {
|
|
|
|
_, err := url.Parse(urlString)
|
2020-08-29 13:26:11 +00:00
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// configureOutput configures the output on the screen
|
2020-12-29 10:08:14 +00:00
|
|
|
func configureOutput(options *types.Options) {
|
2020-08-29 13:26:11 +00:00
|
|
|
// If the user desires verbose output, show verbose output
|
|
|
|
if options.Verbose {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
|
|
|
|
}
|
|
|
|
if options.Debug {
|
|
|
|
gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug)
|
2020-08-29 13:26:11 +00:00
|
|
|
}
|
|
|
|
if options.NoColor {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.DefaultLogger.SetFormatter(formatter.NewCLI(true))
|
2020-08-29 13:26:11 +00:00
|
|
|
}
|
|
|
|
if options.Silent {
|
2020-12-29 10:08:14 +00:00
|
|
|
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
|
2020-08-29 13:26:11 +00:00
|
|
|
}
|
|
|
|
}
|