diff --git a/caplets/local-sniffer.cap b/caplets/local-sniffer.cap new file mode 100644 index 00000000..e99d8ca6 --- /dev/null +++ b/caplets/local-sniffer.cap @@ -0,0 +1,9 @@ +events.stream off +events.clear +set events.stream.filter net.sniff +events.stream on + +set net.sniffer.verbose true +set net.sniffer.local true + +net.sniffer on diff --git a/modules/net_sniff.go b/modules/net_sniff.go index 34b7c458..4cfee105 100644 --- a/modules/net_sniff.go +++ b/modules/net_sniff.go @@ -3,111 +3,14 @@ package modules import ( "fmt" "net" - "os" - "regexp" "time" - "github.com/evilsocket/bettercap-ng/core" - "github.com/evilsocket/bettercap-ng/log" "github.com/evilsocket/bettercap-ng/session" "github.com/google/gopacket" "github.com/google/gopacket/layers" - "github.com/google/gopacket/pcap" - "github.com/google/gopacket/pcapgo" ) -type SnifferContext struct { - Handle *pcap.Handle - DumpLocal bool - Verbose bool - Filter string - Expression string - Compiled *regexp.Regexp - Output string - OutputFile *os.File - OutputWriter *pcapgo.Writer -} - -func NewSnifferContext() *SnifferContext { - return &SnifferContext{ - Handle: nil, - DumpLocal: false, - Verbose: true, - Filter: "", - Expression: "", - Compiled: nil, - Output: "", - OutputFile: nil, - OutputWriter: nil, - } -} - -var ( - no = core.Red("no") - yes = core.Green("yes") -) - -func (c *SnifferContext) Log(sess *session.Session) { - if c.DumpLocal { - log.Info("Skip local packets : %s", no) - } else { - log.Info("Skip local packets : %s", yes) - } - - if c.Verbose { - log.Info("Verbose : %s", yes) - } else { - log.Info("Verbose : %s", no) - } - - if c.Filter != "" { - log.Info("BPF Filter : '%s'", core.Yellow(c.Filter)) - } - - if c.Expression != "" { - log.Info("Regular expression : '%s'", core.Yellow(c.Expression)) - } - - if c.Output != "" { - log.Info("File output : '%s'", core.Yellow(c.Output)) - } -} - -func (c *SnifferContext) Close() { - if c.Handle != nil { - c.Handle.Close() - c.Handle = nil - } - - if c.OutputFile != nil { - c.OutputFile.Close() - c.OutputFile = nil - } -} - -type SnifferStats struct { - NumLocal uint64 - NumMatched uint64 - NumDumped uint64 - NumWrote uint64 - Started time.Time - FirstPacket time.Time - LastPacket time.Time -} - -func NewSnifferStats() *SnifferStats { - return &SnifferStats{ - NumLocal: 0, - NumMatched: 0, - NumDumped: 0, - NumWrote: 0, - Started: time.Now(), - FirstPacket: time.Time{}, - LastPacket: time.Time{}, - } -} - type Sniffer struct { session.SessionModule Stats *SnifferStats @@ -146,7 +49,12 @@ func NewSniffer(s *session.Session) *Sniffer { sniff.AddHandler(session.NewModuleHandler("net.sniffer stats", "", "Print sniffer session configuration and statistics.", func(args []string) error { - return sniff.PrintStats() + sniff.Ctx.Log(sniff.Session) + + if sniff.Stats == nil { + return fmt.Errorf("No stats yet.") + } + return sniff.Stats.Print() })) sniff.AddHandler(session.NewModuleHandler("net.sniffer on", "", @@ -208,91 +116,24 @@ func (s Sniffer) isLocalPacket(packet gopacket.Packet) bool { return false } -func (s *Sniffer) GetContext() (error, *SnifferContext) { - var err error - - ctx := NewSnifferContext() - - if ctx.Handle, err = pcap.OpenLive(s.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { - return err, ctx +func (s *Sniffer) onPacketMatched(pkt gopacket.Packet) { + if s.Ctx.Verbose == false { + return } - if err, v := s.Param("net.sniffer.verbose").Get(s.Session); err != nil { - return err, ctx - } else { - ctx.Verbose = v.(bool) - } - - if err, v := s.Param("net.sniffer.local").Get(s.Session); err != nil { - return err, ctx - } else { - ctx.DumpLocal = v.(bool) - } - - if err, v := s.Param("net.sniffer.filter").Get(s.Session); err != nil { - return err, ctx - } else { - if ctx.Filter = v.(string); ctx.Filter != "" { - err = ctx.Handle.SetBPFFilter(ctx.Filter) - if err != nil { - return err, ctx - } + dumped := false + for _, parser := range PacketParsers { + if parser(pkt) == true { + dumped = true + break } } - if err, v := s.Param("net.sniffer.regexp").Get(s.Session); err != nil { - return err, ctx - } else { - if ctx.Expression = v.(string); ctx.Expression != "" { - if ctx.Compiled, err = regexp.Compile(ctx.Expression); err != nil { - return err, ctx - } - } + if dumped == false { + noParser(pkt) } - if err, v := s.Param("net.sniffer.output").Get(s.Session); err != nil { - return err, ctx - } else { - if ctx.Output = v.(string); ctx.Output != "" { - if ctx.OutputFile, err = os.Create(ctx.Output); err != nil { - return err, ctx - } - - ctx.OutputWriter = pcapgo.NewWriter(ctx.OutputFile) - ctx.OutputWriter.WriteFileHeader(65536, layers.LinkTypeEthernet) - } - } - - return nil, ctx -} - -func (s *Sniffer) PrintStats() error { - if s.Stats == nil { - return fmt.Errorf("No stats yet.") - } - - s.Ctx.Log(s.Session) - - first := "never" - last := "never" - - if s.Stats.FirstPacket.IsZero() == false { - first = s.Stats.FirstPacket.String() - } - - if s.Stats.LastPacket.IsZero() == false { - last = s.Stats.LastPacket.String() - } - - log.Info("Sniffer Started : %s", s.Stats.Started) - log.Info("First Packet Seen : %s", first) - log.Info("Last Packet Seen : %s", last) - log.Info("Local Packets : %d", s.Stats.NumLocal) - log.Info("Matched Packets : %d", s.Stats.NumMatched) - log.Info("Dumped Packets : %d", s.Stats.NumDumped) - log.Info("Wrote Packets : %d", s.Stats.NumWrote) - - return nil + s.Stats.NumDumped++ } func (s *Sniffer) Start() error { @@ -336,10 +177,7 @@ func (s *Sniffer) Start() error { if s.Ctx.Compiled == nil || s.Ctx.Compiled.Match(data) == true { s.Stats.NumMatched++ - if s.Ctx.Verbose { - fmt.Println(packet.Dump()) - s.Stats.NumDumped++ - } + s.onPacketMatched(packet) if s.Ctx.OutputWriter != nil { s.Ctx.OutputWriter.WritePacket(packet.Metadata().CaptureInfo, data) diff --git a/modules/net_sniff_context.go b/modules/net_sniff_context.go new file mode 100644 index 00000000..37235b80 --- /dev/null +++ b/modules/net_sniff_context.go @@ -0,0 +1,141 @@ +package modules + +import ( + "os" + "regexp" + + "github.com/evilsocket/bettercap-ng/core" + "github.com/evilsocket/bettercap-ng/log" + "github.com/evilsocket/bettercap-ng/session" + + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcap" + "github.com/google/gopacket/pcapgo" +) + +type SnifferContext struct { + Handle *pcap.Handle + DumpLocal bool + Verbose bool + Filter string + Expression string + Compiled *regexp.Regexp + Output string + OutputFile *os.File + OutputWriter *pcapgo.Writer +} + +func (s *Sniffer) GetContext() (error, *SnifferContext) { + var err error + + ctx := NewSnifferContext() + + if ctx.Handle, err = pcap.OpenLive(s.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil { + return err, ctx + } + + if err, v := s.Param("net.sniffer.verbose").Get(s.Session); err != nil { + return err, ctx + } else { + ctx.Verbose = v.(bool) + } + + if err, v := s.Param("net.sniffer.local").Get(s.Session); err != nil { + return err, ctx + } else { + ctx.DumpLocal = v.(bool) + } + + if err, v := s.Param("net.sniffer.filter").Get(s.Session); err != nil { + return err, ctx + } else { + if ctx.Filter = v.(string); ctx.Filter != "" { + err = ctx.Handle.SetBPFFilter(ctx.Filter) + if err != nil { + return err, ctx + } + } + } + + if err, v := s.Param("net.sniffer.regexp").Get(s.Session); err != nil { + return err, ctx + } else { + if ctx.Expression = v.(string); ctx.Expression != "" { + if ctx.Compiled, err = regexp.Compile(ctx.Expression); err != nil { + return err, ctx + } + } + } + + if err, v := s.Param("net.sniffer.output").Get(s.Session); err != nil { + return err, ctx + } else { + if ctx.Output = v.(string); ctx.Output != "" { + if ctx.OutputFile, err = os.Create(ctx.Output); err != nil { + return err, ctx + } + + ctx.OutputWriter = pcapgo.NewWriter(ctx.OutputFile) + ctx.OutputWriter.WriteFileHeader(65536, layers.LinkTypeEthernet) + } + } + + return nil, ctx +} + +func NewSnifferContext() *SnifferContext { + return &SnifferContext{ + Handle: nil, + DumpLocal: false, + Verbose: true, + Filter: "", + Expression: "", + Compiled: nil, + Output: "", + OutputFile: nil, + OutputWriter: nil, + } +} + +var ( + no = core.Red("no") + yes = core.Green("yes") +) + +func (c *SnifferContext) Log(sess *session.Session) { + if c.DumpLocal { + log.Info("Skip local packets : %s", no) + } else { + log.Info("Skip local packets : %s", yes) + } + + if c.Verbose { + log.Info("Verbose : %s", yes) + } else { + log.Info("Verbose : %s", no) + } + + if c.Filter != "" { + log.Info("BPF Filter : '%s'", core.Yellow(c.Filter)) + } + + if c.Expression != "" { + log.Info("Regular expression : '%s'", core.Yellow(c.Expression)) + } + + if c.Output != "" { + log.Info("File output : '%s'", core.Yellow(c.Output)) + } +} + +func (c *SnifferContext) Close() { + if c.Handle != nil { + c.Handle.Close() + c.Handle = nil + } + + if c.OutputFile != nil { + c.OutputFile.Close() + c.OutputFile = nil + } +} diff --git a/modules/net_sniff_parsers.go b/modules/net_sniff_parsers.go new file mode 100644 index 00000000..b8e71840 --- /dev/null +++ b/modules/net_sniff_parsers.go @@ -0,0 +1,16 @@ +package modules + +import ( + "fmt" + // "github.com/evilsocket/bettercap-ng/session" + "github.com/google/gopacket" +) + +type SnifferPacketParser func(pkt gopacket.Packet) bool + +var PacketParsers = []SnifferPacketParser{} + +func noParser(pkt gopacket.Packet) bool { + fmt.Println(pkt.Dump()) + return true +} diff --git a/modules/net_sniff_stats.go b/modules/net_sniff_stats.go new file mode 100644 index 00000000..c0b5a3fe --- /dev/null +++ b/modules/net_sniff_stats.go @@ -0,0 +1,51 @@ +package modules + +import ( + "github.com/evilsocket/bettercap-ng/log" + "time" +) + +type SnifferStats struct { + NumLocal uint64 + NumMatched uint64 + NumDumped uint64 + NumWrote uint64 + Started time.Time + FirstPacket time.Time + LastPacket time.Time +} + +func NewSnifferStats() *SnifferStats { + return &SnifferStats{ + NumLocal: 0, + NumMatched: 0, + NumDumped: 0, + NumWrote: 0, + Started: time.Now(), + FirstPacket: time.Time{}, + LastPacket: time.Time{}, + } +} + +func (s *SnifferStats) Print() error { + first := "never" + last := "never" + + if s.FirstPacket.IsZero() == false { + first = s.FirstPacket.String() + } + + if s.LastPacket.IsZero() == false { + last = s.LastPacket.String() + } + + log.Info("Sniffer Started : %s", s.Started) + log.Info("First Packet Seen : %s", first) + log.Info("Last Packet Seen : %s", last) + log.Info("Local Packets : %d", s.NumLocal) + log.Info("Matched Packets : %d", s.NumMatched) + log.Info("Dumped Packets : %d", s.NumDumped) + log.Info("Wrote Packets : %d", s.NumWrote) + + return nil +}