mirror of
https://github.com/bettercap/bettercap
synced 2025-08-14 10:46:57 -07:00
misc: small fix or general refactoring i did not bother commenting
This commit is contained in:
parent
bf3671465b
commit
4eead7eafa
58 changed files with 2052 additions and 2052 deletions
118
modules/net_recon/net_recon.go
Normal file
118
modules/net_recon/net_recon.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
package net_recon
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/modules/utils"
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
)
|
||||
|
||||
type Discovery struct {
|
||||
session.SessionModule
|
||||
selector *utils.ViewSelector
|
||||
}
|
||||
|
||||
func NewDiscovery(s *session.Session) *Discovery {
|
||||
mod := &Discovery{
|
||||
SessionModule: session.NewSessionModule("net.recon", s),
|
||||
}
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("net.recon on", "",
|
||||
"Start network hosts discovery.",
|
||||
func(args []string) error {
|
||||
return mod.Start()
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("net.recon off", "",
|
||||
"Stop network hosts discovery.",
|
||||
func(args []string) error {
|
||||
return mod.Stop()
|
||||
}))
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("net.show.meta",
|
||||
"false",
|
||||
"If true, the net.show command will show all metadata collected about each endpoint."))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("net.show", "",
|
||||
"Show cache hosts list (default sorting by ip).",
|
||||
func(args []string) error {
|
||||
return mod.Show("")
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("net.show ADDRESS1, ADDRESS2", `net.show (.+)`,
|
||||
"Show information about a specific list of addresses (by IP or MAC).",
|
||||
func(args []string) error {
|
||||
return mod.Show(args[0])
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("net.show.meta ADDRESS1, ADDRESS2", `net\.show\.meta (.+)`,
|
||||
"Show meta information about a specific list of addresses (by IP or MAC).",
|
||||
func(args []string) error {
|
||||
return mod.showMeta(args[0])
|
||||
}))
|
||||
|
||||
mod.selector = utils.ViewSelectorFor(&mod.SessionModule, "net.show", []string{"ip", "mac", "seen", "sent", "rcvd"},
|
||||
"ip asc")
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
func (mod Discovery) Name() string {
|
||||
return "net.recon"
|
||||
}
|
||||
|
||||
func (mod Discovery) Description() string {
|
||||
return "Read periodically the ARP cache in order to monitor for new hosts on the network."
|
||||
}
|
||||
|
||||
func (mod Discovery) Author() string {
|
||||
return "Simone Margaritelli <evilsocket@gmail.com>"
|
||||
}
|
||||
|
||||
func (mod *Discovery) runDiff(cache network.ArpTable) {
|
||||
// check for endpoints who disappeared
|
||||
var rem network.ArpTable = make(network.ArpTable)
|
||||
|
||||
mod.Session.Lan.EachHost(func(mac string, e *network.Endpoint) {
|
||||
if _, found := cache[mac]; !found {
|
||||
rem[mac] = e.IpAddress
|
||||
}
|
||||
})
|
||||
|
||||
for mac, ip := range rem {
|
||||
mod.Session.Lan.Remove(ip, mac)
|
||||
}
|
||||
|
||||
// now check for new friends ^_^
|
||||
for ip, mac := range cache {
|
||||
mod.Session.Lan.AddIfNew(ip, mac)
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *Discovery) Configure() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mod *Discovery) Start() error {
|
||||
if err := mod.Configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mod.SetRunning(true, func() {
|
||||
every := time.Duration(1) * time.Second
|
||||
iface := mod.Session.Interface.Name()
|
||||
for mod.Running() {
|
||||
if table, err := network.ArpUpdate(iface); err != nil {
|
||||
mod.Error("%s", err)
|
||||
} else {
|
||||
mod.runDiff(table)
|
||||
}
|
||||
time.Sleep(every)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (mod *Discovery) Stop() error {
|
||||
return mod.SetRunning(false, nil)
|
||||
}
|
310
modules/net_recon/net_show.go
Normal file
310
modules/net_recon/net_show.go
Normal file
|
@ -0,0 +1,310 @@
|
|||
package net_recon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
var (
|
||||
AliveTimeInterval = time.Duration(10) * time.Second
|
||||
PresentTimeInterval = time.Duration(1) * time.Minute
|
||||
JustJoinedTimeInterval = time.Duration(10) * time.Second
|
||||
)
|
||||
|
||||
type ProtoPair struct {
|
||||
Protocol string
|
||||
Hits uint64
|
||||
}
|
||||
|
||||
type ProtoPairList []ProtoPair
|
||||
|
||||
func (p ProtoPairList) Len() int { return len(p) }
|
||||
func (p ProtoPairList) Less(i, j int) bool { return p[i].Hits < p[j].Hits }
|
||||
func (p ProtoPairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
|
||||
func (mod *Discovery) getRow(e *network.Endpoint, withMeta bool) [][]string {
|
||||
sinceStarted := time.Since(mod.Session.StartedAt)
|
||||
sinceFirstSeen := time.Since(e.FirstSeen)
|
||||
|
||||
addr := e.IpAddress
|
||||
mac := e.HwAddress
|
||||
if mod.Session.Lan.WasMissed(e.HwAddress) {
|
||||
// if endpoint was not found in ARP at least once
|
||||
addr = tui.Dim(addr)
|
||||
mac = tui.Dim(mac)
|
||||
} else if sinceStarted > (JustJoinedTimeInterval*2) && sinceFirstSeen <= JustJoinedTimeInterval {
|
||||
// if endpoint was first seen in the last 10 seconds
|
||||
addr = tui.Bold(addr)
|
||||
mac = tui.Bold(mac)
|
||||
}
|
||||
|
||||
name := ""
|
||||
if e == mod.Session.Interface {
|
||||
name = e.Name()
|
||||
} else if e == mod.Session.Gateway {
|
||||
name = "gateway"
|
||||
} else if e.Alias != "" {
|
||||
name = tui.Green(e.Alias)
|
||||
} else if e.Hostname != "" {
|
||||
name = tui.Yellow(e.Hostname)
|
||||
}
|
||||
|
||||
var traffic *packets.Traffic
|
||||
var found bool
|
||||
if traffic, found = mod.Session.Queue.Traffic[e.IpAddress]; !found {
|
||||
traffic = &packets.Traffic{}
|
||||
}
|
||||
|
||||
seen := e.LastSeen.Format("15:04:05")
|
||||
sinceLastSeen := time.Since(e.LastSeen)
|
||||
if sinceStarted > AliveTimeInterval && sinceLastSeen <= AliveTimeInterval {
|
||||
// if endpoint seen in the last 10 seconds
|
||||
seen = tui.Bold(seen)
|
||||
} else if sinceLastSeen <= PresentTimeInterval {
|
||||
// if endpoint seen in the last 60 seconds
|
||||
} else {
|
||||
// not seen in a while
|
||||
seen = tui.Dim(seen)
|
||||
}
|
||||
|
||||
row := []string{
|
||||
addr,
|
||||
mac,
|
||||
name,
|
||||
tui.Dim(e.Vendor),
|
||||
humanize.Bytes(traffic.Sent),
|
||||
humanize.Bytes(traffic.Received),
|
||||
seen,
|
||||
}
|
||||
|
||||
if !withMeta {
|
||||
return [][]string{row}
|
||||
} else if e.Meta.Empty() {
|
||||
return [][]string{append(row, tui.Dim("-"))}
|
||||
}
|
||||
|
||||
metas := []string{}
|
||||
e.Meta.Each(func(name string, value interface{}) {
|
||||
metas = append(metas, fmt.Sprintf("%s:%s", tui.Green(name), tui.Yellow(value.(string))))
|
||||
})
|
||||
sort.Strings(metas)
|
||||
|
||||
rows := [][]string{}
|
||||
for i, m := range metas {
|
||||
if i == 0 {
|
||||
rows = append(rows, append(row, m))
|
||||
} else {
|
||||
rows = append(rows, []string{"", "", "", "", "", "", "", m})
|
||||
}
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
func (mod *Discovery) doFilter(target *network.Endpoint) bool {
|
||||
if mod.selector.Expression == nil {
|
||||
return true
|
||||
}
|
||||
return mod.selector.Expression.MatchString(target.IpAddress) ||
|
||||
mod.selector.Expression.MatchString(target.Ip6Address) ||
|
||||
mod.selector.Expression.MatchString(target.HwAddress) ||
|
||||
mod.selector.Expression.MatchString(target.Hostname) ||
|
||||
mod.selector.Expression.MatchString(target.Alias) ||
|
||||
mod.selector.Expression.MatchString(target.Vendor)
|
||||
}
|
||||
|
||||
func (mod *Discovery) doSelection(arg string) (err error, targets []*network.Endpoint) {
|
||||
if err = mod.selector.Update(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if arg != "" {
|
||||
if targets, err = network.ParseEndpoints(arg, mod.Session.Lan); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
targets = mod.Session.Lan.List()
|
||||
}
|
||||
|
||||
filtered := []*network.Endpoint{}
|
||||
for _, target := range targets {
|
||||
if mod.doFilter(target) {
|
||||
filtered = append(filtered, target)
|
||||
}
|
||||
}
|
||||
targets = filtered
|
||||
|
||||
switch mod.selector.SortField {
|
||||
case "ip":
|
||||
sort.Sort(ByIpSorter(targets))
|
||||
case "mac":
|
||||
sort.Sort(ByMacSorter(targets))
|
||||
case "seen":
|
||||
sort.Sort(BySeenSorter(targets))
|
||||
case "sent":
|
||||
sort.Sort(BySentSorter(targets))
|
||||
case "rcvd":
|
||||
sort.Sort(ByRcvdSorter(targets))
|
||||
default:
|
||||
sort.Sort(ByAddressSorter(targets))
|
||||
}
|
||||
|
||||
// default is asc
|
||||
if mod.selector.Sort == "desc" {
|
||||
// from https://github.com/golang/go/wiki/SliceTricks
|
||||
for i := len(targets)/2 - 1; i >= 0; i-- {
|
||||
opp := len(targets) - 1 - i
|
||||
targets[i], targets[opp] = targets[opp], targets[i]
|
||||
}
|
||||
}
|
||||
|
||||
if mod.selector.Limit > 0 {
|
||||
limit := mod.selector.Limit
|
||||
max := len(targets)
|
||||
if limit > max {
|
||||
limit = max
|
||||
}
|
||||
targets = targets[0:limit]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (mod *Discovery) colNames(hasMeta bool) []string {
|
||||
colNames := []string{"IP", "MAC", "Name", "Vendor", "Sent", "Recvd", "Seen"}
|
||||
if hasMeta {
|
||||
colNames = append(colNames, "Meta")
|
||||
}
|
||||
|
||||
switch mod.selector.SortField {
|
||||
case "mac":
|
||||
colNames[1] += " " + mod.selector.SortSymbol
|
||||
case "sent":
|
||||
colNames[4] += " " + mod.selector.SortSymbol
|
||||
case "rcvd":
|
||||
colNames[5] += " " + mod.selector.SortSymbol
|
||||
case "seen":
|
||||
colNames[6] += " " + mod.selector.SortSymbol
|
||||
case "ip":
|
||||
colNames[0] += " " + mod.selector.SortSymbol
|
||||
}
|
||||
|
||||
return colNames
|
||||
}
|
||||
|
||||
func (mod *Discovery) showStatusBar() {
|
||||
mod.Session.Queue.Stats.RLock()
|
||||
defer mod.Session.Queue.Stats.RUnlock()
|
||||
|
||||
parts := []string{
|
||||
fmt.Sprintf("%s %s", tui.Red("↑"), humanize.Bytes(mod.Session.Queue.Stats.Sent)),
|
||||
fmt.Sprintf("%s %s", tui.Green("↓"), humanize.Bytes(mod.Session.Queue.Stats.Received)),
|
||||
fmt.Sprintf("%d pkts", mod.Session.Queue.Stats.PktReceived),
|
||||
}
|
||||
|
||||
if nErrors := mod.Session.Queue.Stats.Errors; nErrors > 0 {
|
||||
parts = append(parts, fmt.Sprintf("%d errs", nErrors))
|
||||
}
|
||||
|
||||
fmt.Printf("\n%s\n\n", strings.Join(parts, " / "))
|
||||
}
|
||||
|
||||
func (mod *Discovery) Show(arg string) (err error) {
|
||||
var targets []*network.Endpoint
|
||||
if err, targets = mod.doSelection(arg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pad := 1
|
||||
if mod.Session.Interface.HwAddress == mod.Session.Gateway.HwAddress {
|
||||
pad = 0
|
||||
targets = append([]*network.Endpoint{mod.Session.Interface}, targets...)
|
||||
} else {
|
||||
targets = append([]*network.Endpoint{mod.Session.Interface, mod.Session.Gateway}, targets...)
|
||||
}
|
||||
|
||||
hasMeta := false
|
||||
if err, showMeta := mod.BoolParam("net.show.meta"); err != nil {
|
||||
return err
|
||||
} else if showMeta {
|
||||
for _, t := range targets {
|
||||
if !t.Meta.Empty() {
|
||||
hasMeta = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
colNames := mod.colNames(hasMeta)
|
||||
padCols := make([]string, len(colNames))
|
||||
|
||||
rows := make([][]string, 0)
|
||||
for i, t := range targets {
|
||||
rows = append(rows, mod.getRow(t, hasMeta)...)
|
||||
if i == pad {
|
||||
rows = append(rows, padCols)
|
||||
}
|
||||
}
|
||||
|
||||
tui.Table(os.Stdout, colNames, rows)
|
||||
|
||||
mod.showStatusBar()
|
||||
|
||||
mod.Session.Refresh()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mod *Discovery) showMeta(arg string) (err error) {
|
||||
var targets []*network.Endpoint
|
||||
if err, targets = mod.doSelection(arg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
colNames := []string{"Name", "Value"}
|
||||
any := false
|
||||
|
||||
for _, t := range targets {
|
||||
keys := []string{}
|
||||
|
||||
t.Meta.Each(func(name string, value interface{}) {
|
||||
keys = append(keys, name)
|
||||
})
|
||||
|
||||
if len(keys) > 0 {
|
||||
sort.Strings(keys)
|
||||
rows := [][]string{
|
||||
[]string{
|
||||
tui.Green("address"),
|
||||
t.IP.String(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, k := range keys {
|
||||
rows = append(rows, []string{
|
||||
tui.Green(k),
|
||||
tui.Yellow(t.Meta.Get(k).(string)),
|
||||
})
|
||||
}
|
||||
|
||||
any = true
|
||||
tui.Table(os.Stdout, colNames, rows)
|
||||
}
|
||||
}
|
||||
|
||||
if any {
|
||||
mod.Session.Refresh()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
86
modules/net_recon/net_show_sort.go
Normal file
86
modules/net_recon/net_show_sort.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package net_recon
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
)
|
||||
|
||||
type ByAddressSorter []*network.Endpoint
|
||||
|
||||
func (a ByAddressSorter) Len() int { return len(a) }
|
||||
func (a ByAddressSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByAddressSorter) Less(i, j int) bool {
|
||||
if a[i].IpAddressUint32 == a[j].IpAddressUint32 {
|
||||
return a[i].HwAddress < a[j].HwAddress
|
||||
}
|
||||
return a[i].IpAddressUint32 < a[j].IpAddressUint32
|
||||
}
|
||||
|
||||
type ByIpSorter []*network.Endpoint
|
||||
|
||||
func (a ByIpSorter) Len() int { return len(a) }
|
||||
func (a ByIpSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByIpSorter) Less(i, j int) bool {
|
||||
return a[i].IpAddressUint32 < a[j].IpAddressUint32
|
||||
}
|
||||
|
||||
type ByMacSorter []*network.Endpoint
|
||||
|
||||
func (a ByMacSorter) Len() int { return len(a) }
|
||||
func (a ByMacSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByMacSorter) Less(i, j int) bool {
|
||||
return a[i].HwAddress < a[j].HwAddress
|
||||
}
|
||||
|
||||
type BySeenSorter []*network.Endpoint
|
||||
|
||||
func (a BySeenSorter) Len() int { return len(a) }
|
||||
func (a BySeenSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a BySeenSorter) Less(i, j int) bool { return a[i].LastSeen.Before(a[j].LastSeen) }
|
||||
|
||||
type BySentSorter []*network.Endpoint
|
||||
|
||||
func (a BySentSorter) Len() int { return len(a) }
|
||||
func (a BySentSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a BySentSorter) Less(i, j int) bool {
|
||||
session.I.Queue.Lock()
|
||||
defer session.I.Queue.Unlock()
|
||||
|
||||
var found bool = false
|
||||
var aTraffic *packets.Traffic = nil
|
||||
var bTraffic *packets.Traffic = nil
|
||||
|
||||
if aTraffic, found = session.I.Queue.Traffic[a[i].IpAddress]; !found {
|
||||
aTraffic = &packets.Traffic{}
|
||||
}
|
||||
|
||||
if bTraffic, found = session.I.Queue.Traffic[a[j].IpAddress]; !found {
|
||||
bTraffic = &packets.Traffic{}
|
||||
}
|
||||
|
||||
return bTraffic.Sent > aTraffic.Sent
|
||||
}
|
||||
|
||||
type ByRcvdSorter []*network.Endpoint
|
||||
|
||||
func (a ByRcvdSorter) Len() int { return len(a) }
|
||||
func (a ByRcvdSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByRcvdSorter) Less(i, j int) bool {
|
||||
session.I.Queue.Lock()
|
||||
defer session.I.Queue.Unlock()
|
||||
|
||||
var found bool = false
|
||||
var aTraffic *packets.Traffic = nil
|
||||
var bTraffic *packets.Traffic = nil
|
||||
|
||||
if aTraffic, found = session.I.Queue.Traffic[a[i].IpAddress]; !found {
|
||||
aTraffic = &packets.Traffic{}
|
||||
}
|
||||
|
||||
if bTraffic, found = session.I.Queue.Traffic[a[j].IpAddress]; !found {
|
||||
bTraffic = &packets.Traffic{}
|
||||
}
|
||||
|
||||
return bTraffic.Received > aTraffic.Received
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue