mirror of
https://github.com/bettercap/bettercap
synced 2025-07-16 10:03:39 -07:00
fix: syn.scanner now uses a dedicated pcap handle to prevent deadlocks and improve performances
This commit is contained in:
parent
8257d25ff3
commit
cd249687da
4 changed files with 87 additions and 80 deletions
|
@ -3,7 +3,6 @@ package syn_scan
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -11,10 +10,10 @@ import (
|
||||||
"github.com/bettercap/bettercap/packets"
|
"github.com/bettercap/bettercap/packets"
|
||||||
"github.com/bettercap/bettercap/session"
|
"github.com/bettercap/bettercap/session"
|
||||||
|
|
||||||
"github.com/malfunkt/iprange"
|
|
||||||
|
|
||||||
"github.com/evilsocket/islazy/async"
|
"github.com/evilsocket/islazy/async"
|
||||||
"github.com/evilsocket/islazy/str"
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/pcap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const synSourcePort = 666
|
const synSourcePort = 666
|
||||||
|
@ -33,6 +32,8 @@ type SynScanner struct {
|
||||||
addresses []net.IP
|
addresses []net.IP
|
||||||
startPort int
|
startPort int
|
||||||
endPort int
|
endPort int
|
||||||
|
handle *pcap.Handle
|
||||||
|
packets chan gopacket.Packet
|
||||||
progressEvery time.Duration
|
progressEvery time.Duration
|
||||||
stats synScannerStats
|
stats synScannerStats
|
||||||
waitGroup *sync.WaitGroup
|
waitGroup *sync.WaitGroup
|
||||||
|
@ -97,44 +98,6 @@ func NewSynScanner(s *session.Session) *SynScanner {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *SynScanner) parseTargets(arg string) error {
|
|
||||||
if list, err := iprange.Parse(arg); err != nil {
|
|
||||||
return fmt.Errorf("error while parsing IP range '%s': %s", arg, err)
|
|
||||||
} else {
|
|
||||||
mod.addresses = list.Expand()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *SynScanner) parsePorts(args []string) (err error) {
|
|
||||||
argc := len(args)
|
|
||||||
mod.stats.totProbes = 0
|
|
||||||
mod.stats.doneProbes = 0
|
|
||||||
mod.startPort = 1
|
|
||||||
mod.endPort = 65535
|
|
||||||
|
|
||||||
if argc > 1 && str.Trim(args[1]) != "" {
|
|
||||||
if mod.startPort, err = strconv.Atoi(str.Trim(args[1])); err != nil {
|
|
||||||
return fmt.Errorf("invalid start port %s: %s", args[1], err)
|
|
||||||
} else if mod.startPort > 65535 {
|
|
||||||
mod.startPort = 65535
|
|
||||||
}
|
|
||||||
mod.endPort = mod.startPort
|
|
||||||
}
|
|
||||||
|
|
||||||
if argc > 2 && str.Trim(args[2]) != "" {
|
|
||||||
if mod.endPort, err = strconv.Atoi(str.Trim(args[2])); err != nil {
|
|
||||||
return fmt.Errorf("invalid end port %s: %s", args[2], err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if mod.endPort < mod.startPort {
|
|
||||||
return fmt.Errorf("end port %d is greater than start port %d", mod.endPort, mod.startPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *SynScanner) Name() string {
|
func (mod *SynScanner) Name() string {
|
||||||
return "syn.scan"
|
return "syn.scan"
|
||||||
}
|
}
|
||||||
|
@ -147,7 +110,14 @@ func (mod *SynScanner) Author() string {
|
||||||
return "Simone Margaritelli <evilsocket@gmail.com>"
|
return "Simone Margaritelli <evilsocket@gmail.com>"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *SynScanner) Configure() error {
|
func (mod *SynScanner) Configure() (err error) {
|
||||||
|
if mod.Running() {
|
||||||
|
return session.ErrAlreadyStarted(mod.Name())
|
||||||
|
} else if mod.handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = mod.handle.SetBPFFilter(fmt.Sprintf("tcp dst port %d", synSourcePort)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,10 +150,12 @@ func (mod *SynScanner) showProgress() error {
|
||||||
func (mod *SynScanner) Stop() error {
|
func (mod *SynScanner) Stop() error {
|
||||||
mod.Info("stopping ...")
|
mod.Info("stopping ...")
|
||||||
return mod.SetRunning(false, func() {
|
return mod.SetRunning(false, func() {
|
||||||
|
mod.packets <- nil
|
||||||
mod.waitGroup.Wait()
|
mod.waitGroup.Wait()
|
||||||
mod.showProgress()
|
mod.showProgress()
|
||||||
mod.addresses = []net.IP{}
|
mod.addresses = []net.IP{}
|
||||||
mod.State.Store("progress", 0.0)
|
mod.State.Store("progress", 0.0)
|
||||||
|
mod.State.Store("scanning", &mod.addresses)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,15 +191,22 @@ func (mod *SynScanner) scanWorker(job async.Job) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *SynScanner) synScan() error {
|
func (mod *SynScanner) synScan() error {
|
||||||
|
if err := mod.Configure(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
mod.SetRunning(true, func() {
|
mod.SetRunning(true, func() {
|
||||||
|
mod.waitGroup.Add(1)
|
||||||
|
defer mod.waitGroup.Done()
|
||||||
|
|
||||||
defer mod.SetRunning(false, func() {
|
defer mod.SetRunning(false, func() {
|
||||||
mod.addresses = []net.IP{}
|
mod.addresses = []net.IP{}
|
||||||
mod.State.Store("progress", 0.0)
|
mod.State.Store("progress", 0.0)
|
||||||
|
mod.State.Store("scanning", &mod.addresses)
|
||||||
|
mod.packets <- nil
|
||||||
|
mod.handle.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
mod.waitGroup.Add(1)
|
|
||||||
defer mod.waitGroup.Done()
|
|
||||||
|
|
||||||
mod.stats.openPorts = 0
|
mod.stats.openPorts = 0
|
||||||
mod.stats.numPorts = uint64(mod.endPort - mod.startPort + 1)
|
mod.stats.numPorts = uint64(mod.endPort - mod.startPort + 1)
|
||||||
mod.stats.started = time.Now()
|
mod.stats.started = time.Now()
|
||||||
|
@ -247,9 +226,20 @@ func (mod *SynScanner) synScan() error {
|
||||||
|
|
||||||
mod.State.Store("progress", 0.0)
|
mod.State.Store("progress", 0.0)
|
||||||
|
|
||||||
// set the collector
|
// start the collector
|
||||||
mod.Session.Queue.OnPacket(mod.onPacket)
|
go func() {
|
||||||
defer mod.Session.Queue.OnPacket(nil)
|
mod.waitGroup.Add(1)
|
||||||
|
defer mod.waitGroup.Done()
|
||||||
|
|
||||||
|
src := gopacket.NewPacketSource(mod.handle, mod.handle.LinkType())
|
||||||
|
mod.packets = src.Packets()
|
||||||
|
for packet := range mod.packets {
|
||||||
|
if !mod.Running() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mod.onPacket(packet)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// start to show progress every second
|
// start to show progress every second
|
||||||
go func() {
|
go func() {
|
||||||
|
|
47
modules/syn_scan/syn_scan_parsers.go
Normal file
47
modules/syn_scan/syn_scan_parsers.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package syn_scan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/evilsocket/islazy/str"
|
||||||
|
"github.com/malfunkt/iprange"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (mod *SynScanner) parseTargets(arg string) error {
|
||||||
|
if list, err := iprange.Parse(arg); err != nil {
|
||||||
|
return fmt.Errorf("error while parsing IP range '%s': %s", arg, err)
|
||||||
|
} else {
|
||||||
|
mod.addresses = list.Expand()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *SynScanner) parsePorts(args []string) (err error) {
|
||||||
|
argc := len(args)
|
||||||
|
mod.stats.totProbes = 0
|
||||||
|
mod.stats.doneProbes = 0
|
||||||
|
mod.startPort = 1
|
||||||
|
mod.endPort = 65535
|
||||||
|
|
||||||
|
if argc > 1 && str.Trim(args[1]) != "" {
|
||||||
|
if mod.startPort, err = strconv.Atoi(str.Trim(args[1])); err != nil {
|
||||||
|
return fmt.Errorf("invalid start port %s: %s", args[1], err)
|
||||||
|
} else if mod.startPort > 65535 {
|
||||||
|
mod.startPort = 65535
|
||||||
|
}
|
||||||
|
mod.endPort = mod.startPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if argc > 2 && str.Trim(args[2]) != "" {
|
||||||
|
if mod.endPort, err = strconv.Atoi(str.Trim(args[2])); err != nil {
|
||||||
|
return fmt.Errorf("invalid end port %s: %s", args[2], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mod.endPort < mod.startPort {
|
||||||
|
return fmt.Errorf("end port %d is greater than start port %d", mod.endPort, mod.startPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package syn_scan
|
package syn_scan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/network"
|
"github.com/bettercap/bettercap/network"
|
||||||
|
@ -19,15 +18,6 @@ type OpenPort struct {
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *SynScanner) isAddressInRange(ip net.IP) bool {
|
|
||||||
for _, a := range mod.addresses {
|
|
||||||
if a.Equal(ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
|
func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
|
||||||
var eth layers.Ethernet
|
var eth layers.Ethernet
|
||||||
var ip layers.IPv4
|
var ip layers.IPv4
|
||||||
|
@ -46,7 +36,7 @@ func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if mod.isAddressInRange(ip.SrcIP) && tcp.DstPort == synSourcePort && tcp.SYN && tcp.ACK {
|
if tcp.DstPort == synSourcePort && tcp.SYN && tcp.ACK {
|
||||||
atomic.AddUint64(&mod.stats.openPorts, 1)
|
atomic.AddUint64(&mod.stats.openPorts, 1)
|
||||||
|
|
||||||
from := ip.SrcIP.String()
|
from := ip.SrcIP.String()
|
||||||
|
|
|
@ -33,8 +33,6 @@ type Stats struct {
|
||||||
Errors uint64 `json:"errors"`
|
Errors uint64 `json:"errors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PacketCallback func(pkt gopacket.Packet)
|
|
||||||
|
|
||||||
type Queue struct {
|
type Queue struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
|
@ -49,7 +47,6 @@ type Queue struct {
|
||||||
source *gopacket.PacketSource
|
source *gopacket.PacketSource
|
||||||
srcChannel chan gopacket.Packet
|
srcChannel chan gopacket.Packet
|
||||||
writes *sync.WaitGroup
|
writes *sync.WaitGroup
|
||||||
pktCb PacketCallback
|
|
||||||
active bool
|
active bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +66,6 @@ func NewQueue(iface *network.Endpoint) (q *Queue, err error) {
|
||||||
writes: &sync.WaitGroup{},
|
writes: &sync.WaitGroup{},
|
||||||
iface: iface,
|
iface: iface,
|
||||||
active: !iface.IsMonitor(),
|
active: !iface.IsMonitor(),
|
||||||
pktCb: nil,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.active {
|
if q.active {
|
||||||
|
@ -107,21 +103,6 @@ func (q *Queue) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(doc)
|
return json.Marshal(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queue) OnPacket(cb PacketCallback) {
|
|
||||||
q.Lock()
|
|
||||||
defer q.Unlock()
|
|
||||||
q.pktCb = cb
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) onPacketCallback(pkt gopacket.Packet) {
|
|
||||||
q.RLock()
|
|
||||||
defer q.RUnlock()
|
|
||||||
|
|
||||||
if q.pktCb != nil {
|
|
||||||
q.pktCb(pkt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queue) trackProtocols(pkt gopacket.Packet) {
|
func (q *Queue) trackProtocols(pkt gopacket.Packet) {
|
||||||
// gather protocols stats
|
// gather protocols stats
|
||||||
pktLayers := pkt.Layers()
|
pktLayers := pkt.Layers()
|
||||||
|
@ -206,7 +187,6 @@ func (q *Queue) worker() {
|
||||||
pktSize := uint64(len(pkt.Data()))
|
pktSize := uint64(len(pkt.Data()))
|
||||||
|
|
||||||
q.TrackPacket(pktSize)
|
q.TrackPacket(pktSize)
|
||||||
q.onPacketCallback(pkt)
|
|
||||||
|
|
||||||
// decode eth and ipv4 layers
|
// decode eth and ipv4 layers
|
||||||
leth := pkt.Layer(layers.LayerTypeEthernet)
|
leth := pkt.Layer(layers.LayerTypeEthernet)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue