|
| 1 | +package zgrab2 |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "strconv" |
| 6 | + "strings" |
| 7 | + |
| 8 | + log "github.com/sirupsen/logrus" |
| 9 | + flags "github.com/zmap/zflags" |
| 10 | +) |
| 11 | + |
| 12 | +var ( |
| 13 | + parser *flags.Parser // parser for main zgrab2 command |
| 14 | + // iniParser is a parser just for ini files. It's frustrating that we need both, but the ini parser needs an option |
| 15 | + // group 'Application Options' and it seems we can't have this along with option groups in the main parser and have |
| 16 | + // options set correctly. The hidden one shadows the other and no CLI flags are set. |
| 17 | + iniParser *flags.Parser |
| 18 | +) |
| 19 | + |
| 20 | +const defaultDNSPort = "53" |
| 21 | + |
| 22 | +func init() { |
| 23 | + parser = flags.NewParser(nil, flags.Default) |
| 24 | + desc := []string{ |
| 25 | + // Using a long single line so the terminal can handle wrapping, except for Input/Examples which should be on |
| 26 | + // separate lines |
| 27 | + "zgrab2 is fast, modular L7 application-layer scanner. It is commonly used with tools like ZMap which identify " + |
| 28 | + "\"potential services\", or services we know are active on a given IP + port, and these are fed into ZGrab2 " + |
| 29 | + "to confirm and provide details of the service. It has support for a number of protocols listed below as " + |
| 30 | + "'Available commands' including SSH and HTTP. By default, zgrab2 will accept input from stdin and output " + |
| 31 | + "results to stdout, with updates and logs to stderr. Please see 'zgrab2 <command> --help' for more details " + |
| 32 | + "on a specific command.", |
| 33 | + "Input is taken from stdin or --input-file, if specified. Input is CSV-formatted with 'IP, Domain, Tag, Port' " + |
| 34 | + "or simply 'IP' or 'Domain'. See README.md for more details.", |
| 35 | + "", |
| 36 | + "Example usages:", |
| 37 | + "echo '1.1.1.1' | zgrab2 tls # Scan 1.1.1.1 with TLS", |
| 38 | + "echo example.com | zgrab2 http # Scan example.com with HTTP", |
| 39 | + } |
| 40 | + parser.LongDescription = strings.Join(desc, "\n") |
| 41 | + _, err := parser.AddCommand("multiple", "Run multiple commands in a single run", "", &config.Multiple) |
| 42 | + if err != nil { |
| 43 | + log.Fatalf("could not add multiple command: %v", err) |
| 44 | + } |
| 45 | + _, err = parser.AddGroup("General Options", "General options for controlling the behavior of ZGrab2", &config.GeneralOptions) |
| 46 | + if err != nil { |
| 47 | + log.Fatalf("could not add general options group: %v", err) |
| 48 | + } |
| 49 | + _, err = parser.AddGroup("Input/Output Options", "Options for controlling the input/output behavior of ZGrab2", &config.InputOutputOptions) |
| 50 | + if err != nil { |
| 51 | + log.Fatalf("could not add I/O options group: %v", err) |
| 52 | + } |
| 53 | + _, err = parser.AddGroup("Network Options", "Options for controlling the network behavior of ZGrab2", &config.NetworkingOptions) |
| 54 | + if err != nil { |
| 55 | + log.Fatalf("could not add networking options group: %v", err) |
| 56 | + } |
| 57 | + iniParser = flags.NewParser(nil, flags.Default) |
| 58 | +} |
| 59 | + |
| 60 | +// NewIniParser creates and returns a ini parser initialized |
| 61 | +// with the default parser |
| 62 | +func NewIniParser() *flags.IniParser { |
| 63 | + group, err := iniParser.AddGroup("Application Options", "Hidden group including all global options for ini files", &config) |
| 64 | + if err != nil { |
| 65 | + log.Fatalf("could not add Application Options group: %v", err) |
| 66 | + } |
| 67 | + group.Hidden = true |
| 68 | + |
| 69 | + return flags.NewIniParser(iniParser) |
| 70 | +} |
| 71 | + |
| 72 | +// AddCommand adds a module to the parser and returns a pointer to |
| 73 | +// a flags.command object or an error |
| 74 | +func AddCommand(command string, shortDescription string, longDescription string, port int, m ScanModule) (*flags.Command, error) { |
| 75 | + cmd, err := parser.AddCommand(command, shortDescription, longDescription, m) |
| 76 | + if err != nil { |
| 77 | + return nil, fmt.Errorf("could not add command to default parser: %w", err) |
| 78 | + } |
| 79 | + cmd.FindOptionByLongName("port").Default = []string{strconv.Itoa(port)} |
| 80 | + cmd.FindOptionByLongName("name").Default = []string{command} |
| 81 | + |
| 82 | + // Add the same command to the ini parser |
| 83 | + cmd, err = iniParser.AddCommand(command, shortDescription, longDescription, m) |
| 84 | + if err != nil { |
| 85 | + return nil, fmt.Errorf("could not add command to ini parser: %w", err) |
| 86 | + } |
| 87 | + cmd.FindOptionByLongName("port").Default = []string{strconv.Itoa(port)} |
| 88 | + cmd.FindOptionByLongName("name").Default = []string{command} |
| 89 | + modules[command] = m |
| 90 | + return cmd, nil |
| 91 | +} |
| 92 | + |
| 93 | +// ParseCommandLine parses the commands given on the command line |
| 94 | +// and validates the framework configuration (global options) |
| 95 | +// immediately after parsing |
| 96 | +func ParseCommandLine(flags []string) ([]string, string, ScanFlags, error) { |
| 97 | + posArgs, moduleType, f, err := parser.ParseCommandLine(flags) |
| 98 | + if err == nil { |
| 99 | + validateFrameworkConfiguration() |
| 100 | + } |
| 101 | + sf, _ := f.(ScanFlags) |
| 102 | + return posArgs, moduleType, sf, err |
| 103 | +} |
0 commit comments