diff --git a/core/swag.go b/core/swag.go index 8f6a603d..02923ab3 100644 --- a/core/swag.go +++ b/core/swag.go @@ -9,28 +9,42 @@ const ( GREEN = "\033[32m" YELLOW = "\033[33m" + FG_BLACK = "\033[30m" + FG_WHITE = "\033[97m" + + BG_DGRAY = "\033[100m" + BG_RED = "\033[41m" + BG_GREEN = "\033[42m" + BG_YELLOW = "\033[43m" + BG_LBLUE = "\033[104m" + RESET = "\033[0m" ) const ON = GREEN + "✔" + RESET const OFF = RED + "✘" + RESET +// W for Wrap +func W(e, s string) string { + return e + s + RESET +} + func Bold(s string) string { - return BOLD + s + RESET + return W(BOLD, s) } func Dim(s string) string { - return DIM + s + RESET + return W(DIM, s) } func Red(s string) string { - return RED + s + RESET + return W(RED, s) } func Green(s string) string { - return GREEN + s + RESET + return W(GREEN, s) } func Yellow(s string) string { - return YELLOW + s + RESET + return W(YELLOW, s) } diff --git a/modules/net_sniff.go b/modules/net_sniff.go index 4cfee105..782091d0 100644 --- a/modules/net_sniff.go +++ b/modules/net_sniff.go @@ -121,19 +121,9 @@ func (s *Sniffer) onPacketMatched(pkt gopacket.Packet) { return } - dumped := false - for _, parser := range PacketParsers { - if parser(pkt) == true { - dumped = true - break - } + if mainParser(pkt) == true { + s.Stats.NumDumped++ } - - if dumped == false { - noParser(pkt) - } - - s.Stats.NumDumped++ } func (s *Sniffer) Start() error { diff --git a/modules/net_sniff_parsers.go b/modules/net_sniff_parsers.go index b8e71840..c9fbc521 100644 --- a/modules/net_sniff_parsers.go +++ b/modules/net_sniff_parsers.go @@ -2,15 +2,80 @@ package modules import ( "fmt" - // "github.com/evilsocket/bettercap-ng/session" + + "github.com/evilsocket/bettercap-ng/core" + "github.com/evilsocket/bettercap-ng/log" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" ) -type SnifferPacketParser func(pkt gopacket.Packet) bool +func tcpParser(ip *layers.IPv4, pkt gopacket.Packet) { + tcp := pkt.Layer(layers.LayerTypeTCP).(*layers.TCP) -var PacketParsers = []SnifferPacketParser{} + if sniParser(ip, pkt, tcp) { + return + } + + fmt.Printf("[%s] %s %s:%s > %s:%s %s\n", + vTime(pkt.Metadata().Timestamp), + core.W(core.BG_LBLUE+core.FG_BLACK, "tcp"), + vIP(ip.SrcIP), + vPort(tcp.SrcPort), + vIP(ip.DstIP), + vPort(tcp.DstPort), + core.Dim(fmt.Sprintf("%d bytes", len(ip.Payload)))) +} + +func udpParser(ip *layers.IPv4, pkt gopacket.Packet) { + udp := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP) + + fmt.Printf("[%s] %s %s:%s > %s:%s %s\n", + vTime(pkt.Metadata().Timestamp), + core.W(core.BG_DGRAY+core.FG_WHITE, "udp"), + vIP(ip.SrcIP), + vPort(udp.SrcPort), + vIP(ip.DstIP), + vPort(udp.DstPort), + core.Dim(fmt.Sprintf("%d bytes", len(ip.Payload)))) +} + +func unkParser(ip *layers.IPv4, pkt gopacket.Packet) { + fmt.Printf("[%s] [%s] %s > %s (%d bytes)\n", + vTime(pkt.Metadata().Timestamp), + pkt.TransportLayer().LayerType(), + vIP(ip.SrcIP), + vIP(ip.DstIP), + len(ip.Payload)) +} + +func mainParser(pkt gopacket.Packet) bool { + nlayer := pkt.NetworkLayer() + if nlayer == nil { + log.Warning("Missing network layer skipping packet.") + return false + } + + if nlayer.LayerType() != layers.LayerTypeIPv4 { + log.Warning("Unexpected layer type %s, skipping packet.", nlayer.LayerType()) + return false + } + + ip := nlayer.(*layers.IPv4) + + tlayer := pkt.TransportLayer() + if tlayer == nil { + log.Warning("Missing transport layer skipping packet.") + return false + } + + if tlayer.LayerType() == layers.LayerTypeTCP { + tcpParser(ip, pkt) + } else if tlayer.LayerType() == layers.LayerTypeUDP { + udpParser(ip, pkt) + } else { + unkParser(ip, pkt) + } -func noParser(pkt gopacket.Packet) bool { - fmt.Println(pkt.Dump()) return true } diff --git a/modules/net_sniff_sni.go b/modules/net_sniff_sni.go new file mode 100644 index 00000000..3a316e50 --- /dev/null +++ b/modules/net_sniff_sni.go @@ -0,0 +1,41 @@ +package modules + +import ( + "fmt" + + "github.com/evilsocket/bettercap-ng/core" + "regexp" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" +) + +// poor man's TLS Client Hello with SNI extension parser :P +var sniRe = regexp.MustCompile("\x00\x00.{4}\x00.{2}([a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6})\x00") + +func sniParser(ip *layers.IPv4, pkt gopacket.Packet, tcp *layers.TCP) bool { + data := tcp.Payload + dataSize := len(data) + + if dataSize < 2 || data[0] != 0x16 || data[1] != 0x03 { + return false + } + + m := sniRe.FindSubmatch(data) + if len(m) < 2 { + return false + } + + domain := string(m[1]) + if tcp.DstPort != 443 { + domain = fmt.Sprintf("%s:%d", domain, tcp.DstPort) + } + + fmt.Printf("[%s] %s %s > %s\n", + vTime(pkt.Metadata().Timestamp), + core.W(core.BG_YELLOW+core.FG_WHITE, "sni"), + vIP(ip.SrcIP), + core.Yellow("https://"+domain)) + + return true +} diff --git a/modules/net_sniff_views.go b/modules/net_sniff_views.go new file mode 100644 index 00000000..27db0407 --- /dev/null +++ b/modules/net_sniff_views.go @@ -0,0 +1,50 @@ +package modules + +import ( + "fmt" + "net" + "time" + + "github.com/google/gopacket/layers" + + "github.com/evilsocket/bettercap-ng/core" + "github.com/evilsocket/bettercap-ng/session" +) + +func vTime(t time.Time) string { + return t.Format("15:04:05") +} + +func vIP(ip net.IP) string { + if session.I.Interface.IP.Equal(ip) { + return core.Dim("-") + } else if session.I.Gateway.IP.Equal(ip) { + return "gateway" + } + + address := ip.String() + host, found := session.I.Targets.Targets[address] + + if found == true { + if host.Hostname != "" { + return host.Hostname + } + } + + return address +} + +func vPort(p interface{}) string { + sp := fmt.Sprintf("%d", p) + if tcp, ok := p.(layers.TCPPort); ok { + if name, found := layers.TCPPortNames[tcp]; found { + sp = core.Yellow(name) + } + } else if udp, ok := p.(layers.UDPPort); ok { + if name, found := layers.UDPPortNames[udp]; found { + sp = core.Yellow(name) + } + } + + return sp +}