2017-08-01 23:13:28 +00:00
|
|
|
package zgrab2
|
2017-07-14 20:44:36 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2018-01-15 19:24:57 +00:00
|
|
|
"fmt"
|
2017-08-04 20:20:32 +00:00
|
|
|
"net"
|
2017-07-14 20:44:36 +00:00
|
|
|
"sync"
|
2017-08-03 19:55:15 +00:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
2018-03-30 20:28:24 +00:00
|
|
|
"github.com/zmap/zgrab2/lib/output"
|
2017-07-14 20:44:36 +00:00
|
|
|
)
|
|
|
|
|
2017-10-04 03:57:56 +00:00
|
|
|
// Grab contains all scan responses for a single host
|
2017-07-17 21:28:10 +00:00
|
|
|
type Grab struct {
|
2017-09-26 18:02:27 +00:00
|
|
|
IP string `json:"ip,omitempty"`
|
|
|
|
Domain string `json:"domain,omitempty"`
|
|
|
|
Data map[string]ScanResponse `json:"data,omitempty"`
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
|
2017-10-04 03:57:56 +00:00
|
|
|
// ScanTarget is the host that will be scanned
|
2017-09-26 18:02:27 +00:00
|
|
|
type ScanTarget struct {
|
2017-08-04 20:20:32 +00:00
|
|
|
IP net.IP
|
|
|
|
Domain string
|
2018-06-26 17:51:10 +00:00
|
|
|
Tag string
|
2019-08-21 18:53:56 +00:00
|
|
|
Port *uint
|
2017-08-04 20:20:32 +00:00
|
|
|
}
|
|
|
|
|
2018-02-07 17:25:46 +00:00
|
|
|
func (target ScanTarget) String() string {
|
|
|
|
if target.IP == nil && target.Domain == "" {
|
2018-01-31 15:14:52 +00:00
|
|
|
return "<empty target>"
|
2018-06-26 17:51:10 +00:00
|
|
|
}
|
|
|
|
res := ""
|
|
|
|
if target.IP != nil && target.Domain != "" {
|
|
|
|
res = target.Domain + "(" + target.IP.String() + ")"
|
2018-02-07 17:25:46 +00:00
|
|
|
} else if target.IP != nil {
|
2018-06-26 17:51:10 +00:00
|
|
|
res = target.IP.String()
|
|
|
|
} else {
|
|
|
|
res = target.Domain
|
2018-01-31 15:14:52 +00:00
|
|
|
}
|
2018-06-26 17:51:10 +00:00
|
|
|
if target.Tag != "" {
|
2018-06-28 11:35:06 +00:00
|
|
|
res += " tag:" + target.Tag
|
2018-06-26 17:51:10 +00:00
|
|
|
}
|
|
|
|
return res
|
2018-01-31 15:14:52 +00:00
|
|
|
}
|
|
|
|
|
2018-06-28 18:44:08 +00:00
|
|
|
// Host gets the host identifier as a string: the IP address if it is available,
|
|
|
|
// or the domain if not.
|
|
|
|
func (target *ScanTarget) Host() string {
|
|
|
|
if target.IP != nil {
|
|
|
|
return target.IP.String()
|
|
|
|
} else if target.Domain != "" {
|
|
|
|
return target.Domain
|
|
|
|
}
|
|
|
|
log.Fatalf("Bad target %s: no IP/Domain", target.String())
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
|
2018-02-07 17:25:46 +00:00
|
|
|
// Open connects to the ScanTarget using the configured flags, and returns a net.Conn that uses the configured timeouts for Read/Write operations.
|
|
|
|
func (target *ScanTarget) Open(flags *BaseFlags) (net.Conn, error) {
|
2019-08-21 18:53:56 +00:00
|
|
|
var port uint
|
|
|
|
// If the port is supplied in ScanTarget, let that override the cmdline option
|
|
|
|
if target.Port != nil {
|
|
|
|
port = *target.Port
|
|
|
|
} else {
|
|
|
|
port = flags.Port
|
|
|
|
}
|
|
|
|
|
|
|
|
address := net.JoinHostPort(target.Host(), fmt.Sprintf("%d", port))
|
2018-10-16 17:51:06 +00:00
|
|
|
return DialTimeoutConnection("tcp", address, flags.Timeout, flags.BytesReadLimit)
|
2018-01-15 19:24:57 +00:00
|
|
|
}
|
|
|
|
|
2018-07-05 18:34:17 +00:00
|
|
|
// OpenTLS connects to the ScanTarget using the configured flags, then performs
|
|
|
|
// the TLS handshake. On success error is nil, but the connection can be non-nil
|
|
|
|
// even if there is an error (this allows fetching the handshake log).
|
|
|
|
func (target *ScanTarget) OpenTLS(baseFlags *BaseFlags, tlsFlags *TLSFlags) (*TLSConnection, error) {
|
|
|
|
conn, err := tlsFlags.Connect(target, baseFlags)
|
|
|
|
if err != nil {
|
|
|
|
return conn, err
|
|
|
|
}
|
|
|
|
err = conn.Handshake()
|
|
|
|
return conn, err
|
|
|
|
}
|
|
|
|
|
2018-02-07 17:25:46 +00:00
|
|
|
// OpenUDP connects to the ScanTarget using the configured flags, and returns a net.Conn that uses the configured timeouts for Read/Write operations.
|
|
|
|
// Note that the UDP "connection" does not have an associated timeout.
|
|
|
|
func (target *ScanTarget) OpenUDP(flags *BaseFlags, udp *UDPFlags) (net.Conn, error) {
|
2019-08-21 18:53:56 +00:00
|
|
|
var port uint
|
|
|
|
// If the port is supplied in ScanTarget, let that override the cmdline option
|
|
|
|
if target.Port != nil {
|
|
|
|
port = *target.Port
|
|
|
|
} else {
|
|
|
|
port = flags.Port
|
|
|
|
}
|
|
|
|
address := net.JoinHostPort(target.Host(), fmt.Sprintf("%d", port))
|
2018-02-07 17:25:46 +00:00
|
|
|
var local *net.UDPAddr
|
|
|
|
if udp != nil && (udp.LocalAddress != "" || udp.LocalPort != 0) {
|
|
|
|
local = &net.UDPAddr{}
|
|
|
|
if udp.LocalAddress != "" && udp.LocalAddress != "*" {
|
|
|
|
local.IP = net.ParseIP(udp.LocalAddress)
|
|
|
|
}
|
|
|
|
if udp.LocalPort != 0 {
|
|
|
|
local.Port = int(udp.LocalPort)
|
2018-01-15 19:24:57 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-07 17:25:46 +00:00
|
|
|
remote, err := net.ResolveUDPAddr("udp", address)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
conn, err := net.DialUDP("udp", local, remote)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-16 17:51:06 +00:00
|
|
|
return NewTimeoutConnection(nil, conn, flags.Timeout, 0, 0, flags.BytesReadLimit), nil
|
2018-01-15 19:24:57 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 19:39:25 +00:00
|
|
|
// grabTarget calls handler for each action
|
2017-09-26 18:02:27 +00:00
|
|
|
func grabTarget(input ScanTarget, m *Monitor) []byte {
|
|
|
|
moduleResult := make(map[string]ScanResponse)
|
2017-08-01 23:13:28 +00:00
|
|
|
|
2017-09-26 18:02:27 +00:00
|
|
|
for _, scannerName := range orderedScanners {
|
2018-06-26 17:51:10 +00:00
|
|
|
scanner := scanners[scannerName]
|
|
|
|
trigger := (*scanner).GetTrigger()
|
2018-06-27 18:07:07 +00:00
|
|
|
if input.Tag != trigger {
|
2018-06-26 17:51:10 +00:00
|
|
|
continue
|
|
|
|
}
|
2018-01-31 15:14:52 +00:00
|
|
|
defer func(name string) {
|
|
|
|
if e := recover(); e != nil {
|
2018-05-11 14:57:27 +00:00
|
|
|
log.Errorf("Panic on scanner %s when scanning target %s: %#v", scannerName, input.String(), e)
|
2018-01-31 15:14:52 +00:00
|
|
|
// Bubble out original error (with original stack) in lieu of explicitly logging the stack / error
|
|
|
|
panic(e)
|
|
|
|
}
|
|
|
|
}(scannerName)
|
2017-10-04 15:32:42 +00:00
|
|
|
name, res := RunScanner(*scanner, m, input)
|
2017-08-09 20:13:18 +00:00
|
|
|
moduleResult[name] = res
|
2017-08-09 18:56:05 +00:00
|
|
|
if res.Error != nil && !config.Multiple.ContinueOnError {
|
2017-08-01 23:13:28 +00:00
|
|
|
break
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
2020-02-04 00:45:08 +00:00
|
|
|
if res.Status == SCAN_SUCCESS && config.Multiple.BreakOnSuccess {
|
|
|
|
break
|
|
|
|
}
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 19:39:25 +00:00
|
|
|
var ipstr string
|
|
|
|
if input.IP == nil {
|
|
|
|
ipstr = ""
|
2017-08-04 20:20:32 +00:00
|
|
|
} else {
|
|
|
|
s := input.IP.String()
|
2017-08-30 19:39:25 +00:00
|
|
|
ipstr = s
|
2017-08-04 20:20:32 +00:00
|
|
|
}
|
|
|
|
|
2018-04-03 21:15:20 +00:00
|
|
|
raw := Grab{IP: ipstr, Domain: input.Domain, Data: moduleResult}
|
|
|
|
|
2018-06-18 19:18:25 +00:00
|
|
|
var outputData interface{} = raw
|
|
|
|
|
|
|
|
if !includeDebugOutput() {
|
|
|
|
// If the caller doesn't explicitly request debug data, strip it out.
|
|
|
|
// Take advantage of the fact that we can skip the (expensive) call to
|
|
|
|
// process if debug output is included (TODO: until Process does anything else)
|
|
|
|
processor := output.Processor{Verbose: false}
|
|
|
|
stripped, err := processor.Process(raw)
|
|
|
|
if err != nil {
|
|
|
|
log.Debugf("Error processing results: %v", err)
|
|
|
|
stripped = raw
|
|
|
|
}
|
|
|
|
outputData = stripped
|
2018-04-03 21:15:20 +00:00
|
|
|
}
|
2018-03-30 20:28:24 +00:00
|
|
|
|
2018-06-18 19:18:25 +00:00
|
|
|
result, err := json.Marshal(outputData)
|
2017-08-04 20:20:32 +00:00
|
|
|
if err != nil {
|
2017-08-30 19:39:25 +00:00
|
|
|
log.Fatalf("unable to marshal data: %s", err)
|
2017-08-04 20:20:32 +00:00
|
|
|
}
|
2017-07-14 20:44:36 +00:00
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2018-07-05 16:41:34 +00:00
|
|
|
// Process sets up an output encoder, input reader, and starts grab workers.
|
2017-08-16 16:09:20 +00:00
|
|
|
func Process(mon *Monitor) {
|
2017-08-03 19:55:15 +00:00
|
|
|
workers := config.Senders
|
2017-09-26 18:02:27 +00:00
|
|
|
processQueue := make(chan ScanTarget, workers*4)
|
2017-08-16 16:09:20 +00:00
|
|
|
outputQueue := make(chan []byte, workers*4)
|
2017-07-14 20:44:36 +00:00
|
|
|
|
|
|
|
//Create wait groups
|
|
|
|
var workerDone sync.WaitGroup
|
|
|
|
var outputDone sync.WaitGroup
|
|
|
|
workerDone.Add(int(workers))
|
|
|
|
outputDone.Add(1)
|
|
|
|
|
|
|
|
// Start the output encoder
|
|
|
|
go func() {
|
2017-08-31 21:24:05 +00:00
|
|
|
defer outputDone.Done()
|
2018-07-05 16:41:34 +00:00
|
|
|
if err := config.outputResults(outputQueue); err != nil {
|
|
|
|
log.Fatal(err)
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
//Start all the workers
|
2017-07-17 21:28:10 +00:00
|
|
|
for i := 0; i < workers; i++ {
|
2017-12-15 14:25:17 +00:00
|
|
|
go func(i int) {
|
|
|
|
for _, scannerName := range orderedScanners {
|
|
|
|
scanner := *scanners[scannerName]
|
|
|
|
scanner.InitPerSender(i)
|
|
|
|
}
|
2017-07-14 20:44:36 +00:00
|
|
|
for obj := range processQueue {
|
2017-09-05 02:31:44 +00:00
|
|
|
for run := uint(0); run < uint(config.ConnectionsPerHost); run++ {
|
2017-09-04 22:44:58 +00:00
|
|
|
result := grabTarget(obj, mon)
|
|
|
|
outputQueue <- result
|
|
|
|
}
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
workerDone.Done()
|
2017-12-15 14:25:17 +00:00
|
|
|
}(i)
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
|
2018-07-05 16:41:34 +00:00
|
|
|
if err := config.inputTargets(processQueue); err != nil {
|
2018-06-28 11:35:06 +00:00
|
|
|
log.Fatal(err)
|
2017-07-14 20:44:36 +00:00
|
|
|
}
|
|
|
|
close(processQueue)
|
|
|
|
workerDone.Wait()
|
|
|
|
close(outputQueue)
|
|
|
|
outputDone.Wait()
|
|
|
|
}
|