![justinbastress](/assets/img/avatar_default.png)
* Fix typo * Actually call init per sender for each goroutine * split out TLS handling * Rename tls_handshake; update docs * fix comments * format fixes * merge updates * fix path * refactor heartbleed logging (now the same as original zgrab) * add ScanStatus, update modules to return it * fix threaded for loop; fix styling of dict literal * fix compile errors, note un-bubbled handshake error * initial schema commit * fix comment * schema cleanup * comments * fix TODOs * first attempt at docker integration in travis; also add schema validation * add integration_tests.sh * need sudo? * try pip install --user * revert regression * add docker service again * chmod +x integration_tests.sh * fix path of binary * Dump output file to stdout * travis work * use jp's build-self-contained script * use go get/go build to get jp * fix jp path * switch from bogus regex to wildcard * do all mysql versions; fix version comparison * re-enable notifications; fix successful version check log message; comment TryGetScanStatus * move to conf.d layout for integration tests * update README * add missing scripts * add ./ to path
133 lines
3.6 KiB
Go
133 lines
3.6 KiB
Go
package zgrab2
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/ajholland/zflags"
|
|
)
|
|
|
|
var parser *flags.Parser
|
|
|
|
func init() {
|
|
parser = flags.NewParser(&config, flags.Default)
|
|
}
|
|
|
|
// NewIniParser creates and returns a ini parser initialized
|
|
// with the default parser
|
|
func NewIniParser() *flags.IniParser {
|
|
return flags.NewIniParser(parser)
|
|
}
|
|
|
|
// AddCommand adds a module to the parser and returns a pointer to
|
|
// a flags.command object or an error
|
|
func AddCommand(command string, shortDescription string, longDescription string, port int, m ScanModule) (*flags.Command, error) {
|
|
cmd, err := parser.AddCommand(command, shortDescription, longDescription, m)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cmd.FindOptionByLongName("port").Default = []string{strconv.FormatUint(uint64(port), 10)}
|
|
cmd.FindOptionByLongName("name").Default = []string{command}
|
|
modules[command] = &m
|
|
return cmd, nil
|
|
}
|
|
|
|
// ParseCommandLine parses the commands given on the command line
|
|
// and validates the framework configuration (global options)
|
|
// immediately after parsing
|
|
func ParseCommandLine(flags []string) ([]string, string, ScanFlags, error) {
|
|
posArgs, moduleType, f, err := parser.ParseCommandLine(flags)
|
|
if err == nil {
|
|
validateFrameworkConfiguration()
|
|
}
|
|
sf, _ := f.(ScanFlags)
|
|
return posArgs, moduleType, sf, err
|
|
}
|
|
|
|
// ParseTarget takes input as a string and parses it into either an IPNet
|
|
// (may have empty mask and just contain IP , domain name, or errors, may
|
|
// return both IPNet and domain name
|
|
func ParseTarget(s string) (*net.IPNet, string, error) {
|
|
i := strings.IndexByte(s, ',')
|
|
j := strings.IndexByte(s, '/')
|
|
|
|
switch {
|
|
case i == -1 && j == -1:
|
|
// just ip or domain
|
|
if ip := net.ParseIP(s); ip != nil {
|
|
return &net.IPNet{IP: ip}, "", nil
|
|
}
|
|
ips, err := net.LookupIP(s)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return &net.IPNet{IP: ips[0]}, s, nil // only return first IP after a lookup
|
|
case i == -1:
|
|
// cidr block
|
|
_, ipnet, err := net.ParseCIDR(s)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return ipnet, "", nil
|
|
case j == -1:
|
|
// ip,domain
|
|
str := strings.Split(s, ",")
|
|
if len(str) != 2 {
|
|
return nil, "", errors.New("malformed input")
|
|
}
|
|
d := strings.TrimSpace(str[1])
|
|
if ip := net.ParseIP(str[0]); ip != nil {
|
|
return &net.IPNet{IP: ip}, d, nil
|
|
}
|
|
return nil, d, nil
|
|
}
|
|
return nil, "", nil
|
|
}
|
|
|
|
func incrementIP(ip net.IP) {
|
|
for j := len(ip) - 1; j >= 0; j-- {
|
|
ip[j]++
|
|
if ip[j] > 0 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func duplicateIP(ip net.IP) net.IP {
|
|
dup := make(net.IP, len(ip))
|
|
copy(dup, ip)
|
|
return dup
|
|
}
|
|
|
|
// Given an error object thrown by a scan, attempt to get the appropriate ScanStatus enum value
|
|
func TryGetScanStatus(err error) ScanStatus {
|
|
if err == nil {
|
|
return SCAN_SUCCESS
|
|
}
|
|
switch e := err.(type) {
|
|
case *net.OpError:
|
|
switch e.Op {
|
|
case "dial":
|
|
// TODO: Distinguish connection timeout / connection refused
|
|
// Windows examples:
|
|
// "dial tcp 192.168.30.3:22: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."
|
|
// "dial tcp 127.0.0.1:22: connectex: No connection could be made because the target machine actively refused it."
|
|
return SCAN_CONNECTION_TIMEOUT
|
|
case "read":
|
|
// TODO: Distinguish connection reset vs timeout
|
|
return SCAN_IO_TIMEOUT
|
|
case "write":
|
|
// TODO: Distinguish connection reset vs timeout
|
|
return SCAN_IO_TIMEOUT
|
|
default:
|
|
// TODO: Do we need a generic network error?
|
|
return SCAN_UNKNOWN_ERROR
|
|
}
|
|
// TODO: More error types
|
|
default:
|
|
return SCAN_UNKNOWN_ERROR
|
|
}
|
|
}
|