mirror of
https://github.com/bettercap/bettercap
synced 2025-07-16 10:03:39 -07:00
misc: small fix or general refactoring i did not bother commenting
This commit is contained in:
parent
2966153adf
commit
26c532316a
21 changed files with 355 additions and 75 deletions
|
@ -134,8 +134,8 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) {
|
||||||
mod.viewUpdateEvent(output, e)
|
mod.viewUpdateEvent(output, e)
|
||||||
} else if e.Tag == "gateway.change" {
|
} else if e.Tag == "gateway.change" {
|
||||||
mod.viewGatewayEvent(output, e)
|
mod.viewGatewayEvent(output, e)
|
||||||
} else if e.Tag == "mdns.service" {
|
} else if strings.HasPrefix(e.Tag, "zeroconf.") {
|
||||||
mod.viewMDNSEvent(output, e)
|
mod.viewZeroConfEvent(output, e)
|
||||||
} else if e.Tag != "tick" && e.Tag != "session.started" && e.Tag != "session.stopped" {
|
} else if e.Tag != "tick" && e.Tag != "session.started" && e.Tag != "session.stopped" {
|
||||||
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package events_stream
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/modules/zerogod"
|
|
||||||
"github.com/bettercap/bettercap/v2/session"
|
|
||||||
"github.com/evilsocket/islazy/tui"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (mod *EventsStream) viewMDNSEvent(output io.Writer, e session.Event) {
|
|
||||||
event := e.Data.(zerogod.ServiceDiscoveryEvent)
|
|
||||||
fmt.Fprintf(output, "[%s] [%s] service %s detected for %s (%s):%d with %d records\n",
|
|
||||||
e.Time.Format(mod.timeFormat),
|
|
||||||
tui.Green(e.Tag),
|
|
||||||
tui.Bold(event.Service.ServiceInstanceName()),
|
|
||||||
event.Service.AddrIPv4,
|
|
||||||
tui.Dim(event.Service.HostName),
|
|
||||||
event.Service.Port,
|
|
||||||
len(event.Service.Text),
|
|
||||||
)
|
|
||||||
}
|
|
62
modules/events_stream/events_view_zeroconf.go
Normal file
62
modules/events_stream/events_view_zeroconf.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package events_stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/v2/modules/zerogod"
|
||||||
|
"github.com/bettercap/bettercap/v2/session"
|
||||||
|
"github.com/evilsocket/islazy/tui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (mod *EventsStream) viewZeroConfEvent(output io.Writer, e session.Event) {
|
||||||
|
if e.Tag == "zeroconf.service" {
|
||||||
|
event := e.Data.(zerogod.ServiceDiscoveryEvent)
|
||||||
|
fmt.Fprintf(output, "[%s] [%s] service %s detected for %s (%s):%d with %d records\n",
|
||||||
|
e.Time.Format(mod.timeFormat),
|
||||||
|
tui.Green(e.Tag),
|
||||||
|
tui.Bold(event.Service.ServiceInstanceName()),
|
||||||
|
event.Service.AddrIPv4,
|
||||||
|
tui.Dim(event.Service.HostName),
|
||||||
|
event.Service.Port,
|
||||||
|
len(event.Service.Text),
|
||||||
|
)
|
||||||
|
} else if e.Tag == "zeroconf.browsing" {
|
||||||
|
event := e.Data.(zerogod.BrowsingEvent)
|
||||||
|
source := event.Source
|
||||||
|
if event.Endpoint != nil {
|
||||||
|
source = event.Endpoint.ShortString()
|
||||||
|
}
|
||||||
|
|
||||||
|
services := make([]string, 0)
|
||||||
|
for _, q := range event.Query.Questions {
|
||||||
|
services = append(services, tui.Yellow(string(q.Name)))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
instances := make([]string, 0)
|
||||||
|
answers := append(event.Query.Answers, event.Query.Additionals...)
|
||||||
|
for _, answer := range answers {
|
||||||
|
if answer.Class == layers.DNSClassIN && answer.Type == layers.DNSTypePTR {
|
||||||
|
instances = append(instances, tui.Green(string(answer.PTR)))
|
||||||
|
} else {
|
||||||
|
instances = append(instances, tui.Green(answer.String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
advPart := ""
|
||||||
|
if len(instances) > 0 {
|
||||||
|
advPart = fmt.Sprintf(" and advertising %s", strings.Join(instances, ", "))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fmt.Fprintf(output, "[%s] [%s] %s is browsing for services %s\n",
|
||||||
|
e.Time.Format(mod.timeFormat),
|
||||||
|
tui.Green(e.Tag),
|
||||||
|
source,
|
||||||
|
strings.Join(services, ", "),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,14 @@ package zerogod
|
||||||
import (
|
import (
|
||||||
"github.com/bettercap/bettercap/v2/session"
|
"github.com/bettercap/bettercap/v2/session"
|
||||||
"github.com/bettercap/bettercap/v2/tls"
|
"github.com/bettercap/bettercap/v2/tls"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/pcap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZeroGod struct {
|
type ZeroGod struct {
|
||||||
session.SessionModule
|
session.SessionModule
|
||||||
|
sniffer *pcap.Handle
|
||||||
|
snifferCh chan gopacket.Packet
|
||||||
browser *Browser
|
browser *Browser
|
||||||
advertiser *Advertiser
|
advertiser *Advertiser
|
||||||
}
|
}
|
||||||
|
@ -14,8 +18,6 @@ type ZeroGod struct {
|
||||||
func NewZeroGod(s *session.Session) *ZeroGod {
|
func NewZeroGod(s *session.Session) *ZeroGod {
|
||||||
mod := &ZeroGod{
|
mod := &ZeroGod{
|
||||||
SessionModule: session.NewSessionModule("zerogod", s),
|
SessionModule: session.NewSessionModule("zerogod", s),
|
||||||
browser: nil,
|
|
||||||
advertiser: nil,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.SessionModule.Requires("net.recon")
|
mod.SessionModule.Requires("net.recon")
|
||||||
|
@ -115,12 +117,6 @@ func (mod *ZeroGod) Configure() (err error) {
|
||||||
return session.ErrAlreadyStarted(mod.Name())
|
return session.ErrAlreadyStarted(mod.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
if mod.browser != nil {
|
|
||||||
mod.browser.Stop(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
mod.browser = NewBrowser()
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +126,7 @@ func (mod *ZeroGod) Start() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the root discovery
|
// start the root discovery
|
||||||
if err = mod.startResolver(DNSSD_DISCOVERY_SERVICE); err != nil {
|
if err = mod.startDiscovery(DNSSD_DISCOVERY_SERVICE); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,14 +140,6 @@ func (mod *ZeroGod) Start() (err error) {
|
||||||
func (mod *ZeroGod) Stop() error {
|
func (mod *ZeroGod) Stop() error {
|
||||||
return mod.SetRunning(false, func() {
|
return mod.SetRunning(false, func() {
|
||||||
mod.stopAdvertiser()
|
mod.stopAdvertiser()
|
||||||
if mod.browser != nil {
|
mod.stopDiscovery()
|
||||||
mod.Debug("stopping discovery")
|
|
||||||
|
|
||||||
mod.browser.Stop(true)
|
|
||||||
|
|
||||||
mod.Debug("stopped")
|
|
||||||
|
|
||||||
mod.browser = nil
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/evilsocket/islazy/ops"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,10 +31,12 @@ var TCP_HANDLERS = map[string]Handler{
|
||||||
type Acceptor struct {
|
type Acceptor struct {
|
||||||
mod *ZeroGod
|
mod *ZeroGod
|
||||||
srvHost string
|
srvHost string
|
||||||
|
proto string
|
||||||
port uint16
|
port uint16
|
||||||
service string
|
service string
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tls.Config
|
||||||
listener net.Listener
|
tcpListener net.Listener
|
||||||
|
udpListener *net.UDPConn
|
||||||
running bool
|
running bool
|
||||||
context context.Context
|
context context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
|
@ -53,9 +56,12 @@ type HandlerContext struct {
|
||||||
|
|
||||||
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config, ippAttributes map[string]string) *Acceptor {
|
func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsConfig *tls.Config, ippAttributes map[string]string) *Acceptor {
|
||||||
context, ctcCancel := context.WithCancel(context.Background())
|
context, ctcCancel := context.WithCancel(context.Background())
|
||||||
|
proto := ops.Ternary(strings.Contains(service, "_tcp"), "tcp", "udp").(string)
|
||||||
|
|
||||||
acceptor := Acceptor{
|
acceptor := Acceptor{
|
||||||
mod: mod,
|
mod: mod,
|
||||||
port: port,
|
port: port,
|
||||||
|
proto: proto,
|
||||||
service: service,
|
service: service,
|
||||||
context: context,
|
context: context,
|
||||||
ctxCancel: ctcCancel,
|
ctxCancel: ctcCancel,
|
||||||
|
@ -72,36 +78,34 @@ func NewAcceptor(mod *ZeroGod, service string, srvHost string, port uint16, tlsC
|
||||||
}
|
}
|
||||||
|
|
||||||
if acceptor.handler.Handle == nil {
|
if acceptor.handler.Handle == nil {
|
||||||
mod.Warning("no protocol handler found for service %s, using generic dump handler", tui.Yellow(service))
|
mod.Warning("no protocol handler found for service %s, using generic %s dump handler", tui.Yellow(service), proto)
|
||||||
acceptor.handler.Handle = handleGenericTCP
|
acceptor.handler.Handle = handleGenericTCP
|
||||||
} else {
|
} else {
|
||||||
mod.Info("found %s protocol handler", tui.Green(service))
|
mod.Info("found %s %s protocol handler", proto, tui.Green(service))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acceptor
|
return &acceptor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Acceptor) Start() (err error) {
|
func (a *Acceptor) startTCP() (err error) {
|
||||||
var lc net.ListenConfig
|
var lc net.ListenConfig
|
||||||
|
if a.tcpListener, err = lc.Listen(a.context, "tcp", fmt.Sprintf("0.0.0.0:%d", a.port)); err != nil {
|
||||||
if a.listener, err = lc.Listen(a.context, "tcp", fmt.Sprintf("0.0.0.0:%d", a.port)); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.tlsConfig != nil {
|
if a.tlsConfig != nil {
|
||||||
a.listener = tls.NewListener(a.listener, a.tlsConfig)
|
a.tcpListener = tls.NewListener(a.tcpListener, a.tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.running = true
|
a.running = true
|
||||||
go func() {
|
go func() {
|
||||||
a.mod.Debug("tcp listener for port %d (%s) started", a.port, tui.Green(a.service))
|
a.mod.Debug("%s listener for port %d (%s) started", a.proto, a.port, tui.Green(a.service))
|
||||||
for a.running {
|
for a.running {
|
||||||
if conn, err := a.listener.Accept(); err != nil {
|
if conn, err := a.tcpListener.Accept(); err != nil {
|
||||||
if a.running {
|
if a.running {
|
||||||
a.mod.Error("%v", err)
|
a.mod.Error("%v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.mod.Debug("accepted connection for service %s (port %d): %v", tui.Green(a.service), a.port, conn.RemoteAddr())
|
a.mod.Debug("accepted %s connection for service %s (port %d): %v", a.proto, tui.Green(a.service), a.port, conn.RemoteAddr())
|
||||||
go a.handler.Handle(&HandlerContext{
|
go a.handler.Handle(&HandlerContext{
|
||||||
service: a.service,
|
service: a.service,
|
||||||
mod: a.mod,
|
mod: a.mod,
|
||||||
|
@ -113,17 +117,60 @@ func (a *Acceptor) Start() (err error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.mod.Debug("tcp listener for port %d (%s) stopped", a.port, tui.Green(a.service))
|
a.mod.Debug("%s listener for port %d (%s) stopped", a.proto, a.port, tui.Green(a.service))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Acceptor) Stop() {
|
func (a *Acceptor) startUDP() (err error) {
|
||||||
a.mod.Debug("stopping tcp listener for port %d", a.port)
|
if udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("0.0.0.0:%d", a.port)); err != nil {
|
||||||
a.running = false
|
return err
|
||||||
a.ctxCancel()
|
} else if a.udpListener, err = net.ListenUDP("udp", udpAddr); err != nil {
|
||||||
<-a.context.Done()
|
return err
|
||||||
a.listener.Close()
|
} else {
|
||||||
a.mod.Debug("tcp listener for port %d stopped", a.port)
|
a.running = true
|
||||||
|
go func() {
|
||||||
|
var buffer [4096]byte
|
||||||
|
|
||||||
|
a.mod.Info("%s listener for port %d (%s) started", a.proto, a.port, tui.Green(a.service))
|
||||||
|
|
||||||
|
for a.running {
|
||||||
|
if n, addr, err := a.udpListener.ReadFromUDP(buffer[0:]); err != nil {
|
||||||
|
a.mod.Warning("error reading udp packet: %v", err)
|
||||||
|
} else if n <= 0 {
|
||||||
|
a.mod.Info("empty read")
|
||||||
|
} else {
|
||||||
|
a.mod.Info("%v:\n%s", addr, Dump(buffer[0:n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.mod.Info("%s listener for port %d (%s) stopped", a.proto, a.port, tui.Green(a.service))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acceptor) Start() (err error) {
|
||||||
|
if a.proto == "tcp" {
|
||||||
|
return a.startTCP()
|
||||||
|
} else {
|
||||||
|
return a.startUDP()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acceptor) Stop() {
|
||||||
|
a.mod.Debug("stopping %s listener for port %d", a.proto, a.port)
|
||||||
|
a.running = false
|
||||||
|
|
||||||
|
if a.proto == "tcp" {
|
||||||
|
a.ctxCancel()
|
||||||
|
<-a.context.Done()
|
||||||
|
a.tcpListener.Close()
|
||||||
|
} else {
|
||||||
|
a.udpListener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
a.mod.Debug("%s listener for port %d stopped", a.proto, a.port)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -20,6 +22,27 @@ type Advertiser struct {
|
||||||
Acceptors []*Acceptor
|
Acceptors []*Acceptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPortAvailable(port int) bool {
|
||||||
|
address := fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
|
if conn, err := net.DialTimeout("tcp", address, 10*time.Millisecond); err != nil {
|
||||||
|
return true
|
||||||
|
} else if conn == nil {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
conn.Close()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPortRequested(svc *ServiceData, services []*ServiceData) bool {
|
||||||
|
for _, other := range services {
|
||||||
|
if svc != other && svc.Port == other.Port {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *ZeroGod) loadTLSConfig() (*tls.Config, error) {
|
func (mod *ZeroGod) loadTLSConfig() (*tls.Config, error) {
|
||||||
var certFile string
|
var certFile string
|
||||||
var keyFile string
|
var keyFile string
|
||||||
|
@ -104,6 +127,21 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
||||||
Acceptors: make([]*Acceptor, 0),
|
Acceptors: make([]*Acceptor, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fix ports
|
||||||
|
for _, svc := range advertiser.Services {
|
||||||
|
// if no external responder has been specified, check if port is available
|
||||||
|
if svc.Responder == "" {
|
||||||
|
for svc.Port == 0 || !isPortAvailable(svc.Port) || isPortRequested(svc, services) {
|
||||||
|
newPort := (rand.Intn(65535-1024) + 1024)
|
||||||
|
mod.Warning("port %d for service %s is not avaialble, trying %d ...",
|
||||||
|
svc.Port,
|
||||||
|
svc.FullName(),
|
||||||
|
newPort)
|
||||||
|
svc.Port = newPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// paralleize initialization
|
// paralleize initialization
|
||||||
svcChan := make(chan error, numServices)
|
svcChan := make(chan error, numServices)
|
||||||
for _, svc := range advertiser.Services {
|
for _, svc := range advertiser.Services {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
package zerogod
|
package zerogod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/bettercap/bettercap/v2/network"
|
"github.com/bettercap/bettercap/v2/network"
|
||||||
"github.com/bettercap/bettercap/v2/session"
|
"github.com/bettercap/bettercap/v2/session"
|
||||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// a service has been discovered
|
||||||
type ServiceDiscoveryEvent struct {
|
type ServiceDiscoveryEvent struct {
|
||||||
Service zeroconf.ServiceEntry `json:"service"`
|
Service zeroconf.ServiceEntry `json:"service"`
|
||||||
Endpoint *network.Endpoint `json:"endpoint"`
|
Endpoint *network.Endpoint `json:"endpoint"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an endpoint is browsing for specific services
|
||||||
|
type BrowsingEvent struct {
|
||||||
|
Source string `json:"source"`
|
||||||
|
Query layers.DNS `json:"service"`
|
||||||
|
Endpoint *network.Endpoint `json:"endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
||||||
mod.Debug("%++v", *svc)
|
mod.Debug("%++v", *svc)
|
||||||
|
|
||||||
|
@ -21,8 +33,15 @@ func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
||||||
svcName := strings.Replace(svc.Instance, ".local", "", 1)
|
svcName := strings.Replace(svc.Instance, ".local", "", 1)
|
||||||
if !mod.browser.HasResolverFor(svcName) {
|
if !mod.browser.HasResolverFor(svcName) {
|
||||||
mod.Debug("discovered service %s", tui.Green(svcName))
|
mod.Debug("discovered service %s", tui.Green(svcName))
|
||||||
if err := mod.startResolver(svcName); err != nil {
|
if ch, err := mod.browser.StartBrowsing(svcName, "local.", mod); err != nil {
|
||||||
mod.Error("%v", err)
|
mod.Error("%v", err)
|
||||||
|
} else {
|
||||||
|
// start listening on this channel
|
||||||
|
go func() {
|
||||||
|
for entry := range ch {
|
||||||
|
mod.onServiceDiscovered(entry)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -58,17 +77,116 @@ func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
||||||
mod.Debug("got mdns entry for unknown ip: %++v", *svc)
|
mod.Debug("got mdns entry for unknown ip: %++v", *svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.I.Events.Add("mdns.service", event)
|
session.I.Events.Add("zeroconf.service", event)
|
||||||
session.I.Refresh()
|
session.I.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *ZeroGod) startResolver(service string) error {
|
func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
|
mod.Debug("%++v", pkt)
|
||||||
|
|
||||||
|
netLayer := pkt.NetworkLayer()
|
||||||
|
if netLayer == nil {
|
||||||
|
mod.Warning("not network layer in packet %+v", pkt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var srcIP net.IP
|
||||||
|
// var dstIP net.IP
|
||||||
|
switch netLayer.LayerType() {
|
||||||
|
case layers.LayerTypeIPv4:
|
||||||
|
ip := netLayer.(*layers.IPv4)
|
||||||
|
srcIP = ip.SrcIP
|
||||||
|
// dstIP = ip.DstIP
|
||||||
|
case layers.LayerTypeIPv6:
|
||||||
|
ip := netLayer.(*layers.IPv6)
|
||||||
|
srcIP = ip.SrcIP
|
||||||
|
// dstIP = ip.DstIP
|
||||||
|
default:
|
||||||
|
mod.Warning("unexpected network layer type %v in packet %+v", netLayer.LayerType(), pkt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// not interested in packet generated by us
|
||||||
|
if srcIP.Equal(mod.Session.Interface.IP) || srcIP.Equal(mod.Session.Interface.IPv6) {
|
||||||
|
mod.Debug("skipping local packet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
udp := pkt.Layer(layers.LayerTypeUDP)
|
||||||
|
if udp == nil {
|
||||||
|
mod.Warning("not udp layer in packet %+v", pkt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dns := layers.DNS{}
|
||||||
|
if err := dns.DecodeFromBytes(udp.LayerPayload(), gopacket.NilDecodeFeedback); err != nil {
|
||||||
|
mod.Warning("could not decode DNS (%v) in packet %+v", err, pkt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// since the browser is already checking for these, we are only interested in queries
|
||||||
|
numQs := len(dns.Questions)
|
||||||
|
if numQs == 0 {
|
||||||
|
mod.Debug("skipping answers only packet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event := BrowsingEvent{
|
||||||
|
Source: srcIP.String(),
|
||||||
|
Query: dns,
|
||||||
|
Endpoint: mod.Session.Lan.GetByIp(srcIP.String()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Endpoint == nil {
|
||||||
|
// TODO: if nil, this is probably an IPv6 only record, try to somehow check which known IPv4 it is
|
||||||
|
// TODO: make configurable?
|
||||||
|
mod.Debug("got mdns packet from unknown ip %s: %++v", srcIP, dns)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session.I.Events.Add("zeroconf.browsing", event)
|
||||||
|
session.I.Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *ZeroGod) startDiscovery(service string) (err error) {
|
||||||
mod.Debug("starting resolver for service %s", tui.Yellow(service))
|
mod.Debug("starting resolver for service %s", tui.Yellow(service))
|
||||||
|
|
||||||
|
// create passive sniffer
|
||||||
|
if mod.sniffer != nil {
|
||||||
|
mod.sniffer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
readTimeout := 500 * time.Millisecond
|
||||||
|
if mod.sniffer, err = network.CaptureWithTimeout(mod.Session.Interface.Name(), readTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = mod.sniffer.SetBPFFilter("udp and port 5353"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// prepare source and start listening for packets
|
||||||
|
src := gopacket.NewPacketSource(mod.sniffer, mod.sniffer.LinkType())
|
||||||
|
mod.snifferCh = src.Packets()
|
||||||
|
// start listening for new packets
|
||||||
|
go func() {
|
||||||
|
mod.Debug("sniffer started")
|
||||||
|
for pkt := range mod.snifferCh {
|
||||||
|
if !mod.Running() {
|
||||||
|
mod.Debug("end pkt loop (pkt=%v)", pkt)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mod.onPacket(pkt)
|
||||||
|
}
|
||||||
|
mod.Debug("sniffer stopped")
|
||||||
|
}()
|
||||||
|
|
||||||
|
// create service browser
|
||||||
|
if mod.browser != nil {
|
||||||
|
mod.browser.Stop(false)
|
||||||
|
}
|
||||||
|
mod.browser = NewBrowser()
|
||||||
|
// start active browsing
|
||||||
if ch, err := mod.browser.StartBrowsing(service, "local.", mod); err != nil {
|
if ch, err := mod.browser.StartBrowsing(service, "local.", mod); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
// start listening
|
// start listening for new services
|
||||||
go func() {
|
go func() {
|
||||||
for entry := range ch {
|
for entry := range ch {
|
||||||
mod.onServiceDiscovered(entry)
|
mod.onServiceDiscovered(entry)
|
||||||
|
@ -78,3 +196,21 @@ func (mod *ZeroGod) startResolver(service string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *ZeroGod) stopDiscovery() {
|
||||||
|
if mod.browser != nil {
|
||||||
|
mod.Debug("stopping discovery")
|
||||||
|
mod.browser.Stop(true)
|
||||||
|
mod.browser = nil
|
||||||
|
mod.Debug("discovery stopped")
|
||||||
|
}
|
||||||
|
|
||||||
|
if mod.sniffer != nil {
|
||||||
|
mod.Debug("stopping sniffer")
|
||||||
|
mod.snifferCh <- nil
|
||||||
|
mod.sniffer.Close()
|
||||||
|
mod.sniffer = nil
|
||||||
|
mod.snifferCh = nil
|
||||||
|
mod.Debug("sniffer stopped")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/modules/syn_scan"
|
"github.com/bettercap/bettercap/v2/modules/syn_scan"
|
||||||
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/bettercap/bettercap/v2/network"
|
"github.com/bettercap/bettercap/v2/network"
|
||||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
|
||||||
"github.com/evilsocket/islazy/str"
|
"github.com/evilsocket/islazy/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ func ippClientHandler(ctx *HandlerContext) {
|
||||||
read, err := ctx.client.Read(buf)
|
read, err := ctx.client.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
|
ctx.mod.Debug("EOF, client %s disconnected", clientIP)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.mod.Warning("error while reading from %v: %v", clientIP, err)
|
ctx.mod.Warning("error while reading from %v: %v", clientIP, err)
|
||||||
|
@ -67,12 +68,12 @@ func ippClientHandler(ctx *HandlerContext) {
|
||||||
reader := bufio.NewReader(bytes.NewReader(raw_req))
|
reader := bufio.NewReader(bytes.NewReader(raw_req))
|
||||||
http_req, err := http.ReadRequest(reader)
|
http_req, err := http.ReadRequest(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.mod.Error("error while parsing http request from %v: %v", clientIP, err)
|
ctx.mod.Error("error while parsing http request from %v: %v\n%s", clientIP, err, Dump(raw_req))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clientUA := http_req.UserAgent()
|
clientUA := http_req.UserAgent()
|
||||||
ctx.mod.Debug("%v -> %s", clientIP, tui.Green(clientUA))
|
ctx.mod.Info("%v -> %s", clientIP, tui.Green(clientUA))
|
||||||
|
|
||||||
ipp_body, err := ippReadRequestBody(ctx, http_req)
|
ipp_body, err := ippReadRequestBody(ctx, http_req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,8 +93,14 @@ func ippClientHandler(ctx *HandlerContext) {
|
||||||
ipp_op_name = name
|
ipp_op_name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.mod.Info("%s <- %s (%s) %s",
|
reqUsername := tui.Dim("<unknown>")
|
||||||
|
if value, found := ipp_req.OperationAttributes["requesting-user-name"]; found {
|
||||||
|
reqUsername = tui.Blue(value.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.mod.Info("%s <- %s@%s (%s) %s",
|
||||||
tui.Yellow(ctx.service),
|
tui.Yellow(ctx.service),
|
||||||
|
reqUsername,
|
||||||
clientIP,
|
clientIP,
|
||||||
tui.Green(clientUA),
|
tui.Green(clientUA),
|
||||||
tui.Bold(ipp_op_name))
|
tui.Bold(ipp_op_name))
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/evilsocket/islazy/str"
|
"github.com/evilsocket/islazy/str"
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/zeroconf"
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/evilsocket/islazy/ops"
|
||||||
"github.com/evilsocket/islazy/str"
|
"github.com/evilsocket/islazy/str"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +21,10 @@ func (mod *ZeroGod) show(filter string, withData bool) error {
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if endpoint := mod.Session.Lan.GetByIp(entry.Address); endpoint != nil {
|
if endpoint := mod.Session.Lan.GetByIp(entry.Address); endpoint != nil {
|
||||||
fmt.Fprintf(mod.Session.Events.Stdout, "* %s (%s)\n", tui.Bold(endpoint.IpAddress), tui.Dim(endpoint.Vendor))
|
fmt.Fprintf(mod.Session.Events.Stdout, "* %s (%s)%s\n",
|
||||||
|
tui.Bold(endpoint.IpAddress),
|
||||||
|
tui.Dim(endpoint.Vendor),
|
||||||
|
ops.Ternary(endpoint.Hostname == "", "", " "+tui.Bold(endpoint.Hostname)))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(mod.Session.Events.Stdout, "* %s\n", tui.Bold(entry.Address))
|
fmt.Fprintf(mod.Session.Events.Stdout, "* %s\n", tui.Bold(entry.Address))
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,27 @@ func (t *Endpoint) String() string {
|
||||||
return fmt.Sprintf("%s%s (%s) - %s", ipPart, t.HwAddress, t.Vendor, tui.Bold(name))
|
return fmt.Sprintf("%s%s (%s) - %s", ipPart, t.HwAddress, t.Vendor, tui.Bold(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Endpoint) ShortString() string {
|
||||||
|
parts := []string{
|
||||||
|
t.IpAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Vendor != "" {
|
||||||
|
parts = append(parts, tui.Dim(fmt.Sprintf("(%s)", t.Vendor)))
|
||||||
|
}
|
||||||
|
|
||||||
|
name := t.Hostname
|
||||||
|
if t.Alias != "" {
|
||||||
|
name = t.Alias
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
parts = append(parts, tui.Bold(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, " ")
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Endpoint) OnMeta(meta map[string]string) {
|
func (t *Endpoint) OnMeta(meta map[string]string) {
|
||||||
host := ""
|
host := ""
|
||||||
for k, v := range meta {
|
for k, v := range meta {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue