Commit a7ae742c authored by Sophie Brun's avatar Sophie Brun

Update upstream source from tag 'upstream/2.13'

Update to upstream version '2.13'
with Debian dir 83342315f95baf4fb0e4ce365bcd6bbc2d1da95d
parents 9250e297 eeeb3db8
......@@ -56,8 +56,12 @@ func Load(name string) (error, *Caplet) {
name += Suffix
}
for _, path := range LoadPaths {
names = append(names, filepath.Join(path, name))
if name[0] != '/' {
for _, path := range LoadPaths {
names = append(names, filepath.Join(path, name))
}
} else {
names = append(names, name)
}
for _, filename := range names {
......
......@@ -2,7 +2,7 @@ package core
const (
Name = "bettercap"
Version = "2.12"
Version = "2.13"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
......@@ -226,8 +226,6 @@ func (s *EventsStream) Start() error {
if !s.ignoreList.Ignored(e) {
s.View(e, true)
} else {
log.Debug("skipping ignored event %v", e)
}
case <-s.quit:
......
......@@ -10,6 +10,7 @@ import (
type Discovery struct {
session.SessionModule
selector *ViewSelector
}
func NewDiscovery(s *session.Session) *Discovery {
......@@ -36,33 +37,17 @@ func NewDiscovery(s *session.Session) *Discovery {
d.AddHandler(session.NewModuleHandler("net.show", "",
"Show cache hosts list (default sorting by ip).",
func(args []string) error {
return d.Show("address", "")
}))
d.AddHandler(session.NewModuleHandler("net.show by seen", "",
"Show cache hosts list (sort by last seen).",
func(args []string) error {
return d.Show("seen", "")
}))
d.AddHandler(session.NewModuleHandler("net.show by sent", "",
"Show cache hosts list (sort by sent packets).",
func(args []string) error {
return d.Show("sent", "")
}))
d.AddHandler(session.NewModuleHandler("net.show by rcvd", "",
"Show cache hosts list (sort by received packets).",
func(args []string) error {
return d.Show("rcvd", "")
return d.Show("")
}))
d.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 d.Show("address", args[0])
return d.Show(args[0])
}))
d.selector = ViewSelectorFor(&d.SessionModule, "net.show", []string{"ip", "mac", "seen", "sent", "rcvd"}, "ip asc")
return d
}
......
......@@ -110,16 +110,44 @@ func (d *Discovery) getRow(e *network.Endpoint, withMeta bool) [][]string {
return rows
}
func (d *Discovery) Show(by string, expr string) (err error) {
var targets []*network.Endpoint
if expr != "" {
if targets, err = network.ParseEndpoints(expr, d.Session.Lan); err != nil {
return err
func (d *Discovery) doFilter(target *network.Endpoint) bool {
if d.selector.Expression == nil {
return true
}
return d.selector.Expression.MatchString(target.IpAddress) ||
d.selector.Expression.MatchString(target.Ip6Address) ||
d.selector.Expression.MatchString(target.HwAddress) ||
d.selector.Expression.MatchString(target.Hostname) ||
d.selector.Expression.MatchString(target.Alias) ||
d.selector.Expression.MatchString(target.Vendor)
}
func (d *Discovery) doSelection(arg string) (err error, targets []*network.Endpoint) {
if err = d.selector.Update(); err != nil {
return
}
if arg != "" {
if targets, err = network.ParseEndpoints(arg, d.Session.Lan); err != nil {
return
}
} else {
targets = d.Session.Lan.List()
}
switch by {
filtered := []*network.Endpoint{}
for _, target := range targets {
if d.doFilter(target) {
filtered = append(filtered, target)
}
}
targets = filtered
switch d.selector.SortField {
case "ip":
sort.Sort(ByIpSorter(targets))
case "mac":
sort.Sort(ByMacSorter(targets))
case "seen":
sort.Sort(BySeenSorter(targets))
case "sent":
......@@ -130,6 +158,55 @@ func (d *Discovery) Show(by string, expr string) (err error) {
sort.Sort(ByAddressSorter(targets))
}
// default is asc
if d.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 d.selector.Limit > 0 {
limit := d.selector.Limit
max := len(targets)
if limit > max {
limit = max
}
targets = targets[0:limit]
}
return
}
func (d *Discovery) colNames(hasMeta bool) []string {
colNames := []string{"IP", "MAC", "Name", "Vendor", "Sent", "Recvd", "Last Seen"}
if hasMeta {
colNames = append(colNames, "Meta")
}
switch d.selector.SortField {
case "mac":
colNames[1] += " " + d.selector.SortSymbol
case "sent":
colNames[4] += " " + d.selector.SortSymbol
case "rcvd":
colNames[5] += " " + d.selector.SortSymbol
case "seen":
colNames[6] += " " + d.selector.SortSymbol
case "ip":
colNames[0] += " " + d.selector.SortSymbol
}
return colNames
}
func (d *Discovery) Show(arg string) (err error) {
var targets []*network.Endpoint
if err, targets = d.doSelection(arg); err != nil {
return
}
pad := 1
if d.Session.Interface.HwAddress == d.Session.Gateway.HwAddress {
pad = 0
......@@ -150,12 +227,8 @@ func (d *Discovery) Show(by string, expr string) (err error) {
}
}
padCols := []string{"", "", "", "", "", "", ""}
colNames := []string{"IP", "MAC", "Name", "Vendor", "Sent", "Recvd", "Last Seen"}
if hasMeta {
padCols = append(padCols, "")
colNames = append(colNames, "Meta")
}
colNames := d.colNames(hasMeta)
padCols := make([]string, len(colNames))
rows := make([][]string, 0)
for i, t := range targets {
......
......@@ -17,11 +17,27 @@ func (a ByAddressSorter) Less(i, j int) bool {
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.After(a[j].LastSeen) }
func (a BySeenSorter) Less(i, j int) bool { return a[i].LastSeen.Before(a[j].LastSeen) }
type BySentSorter []*network.Endpoint
......@@ -43,7 +59,7 @@ func (a BySentSorter) Less(i, j int) bool {
bTraffic = &packets.Traffic{}
}
return bTraffic.Sent < aTraffic.Sent
return bTraffic.Sent > aTraffic.Sent
}
type ByRcvdSorter []*network.Endpoint
......@@ -66,5 +82,5 @@ func (a ByRcvdSorter) Less(i, j int) bool {
bTraffic = &packets.Traffic{}
}
return bTraffic.Received < aTraffic.Received
return bTraffic.Received > aTraffic.Received
}
......@@ -15,6 +15,12 @@ type Sniffer struct {
Stats *SnifferStats
Ctx *SnifferContext
pktSourceChan chan gopacket.Packet
fuzzActive bool
fuzzSilent bool
fuzzLayers []string
fuzzRate float64
fuzzRatio float64
}
func NewSniffer(s *session.Session) *Sniffer {
......@@ -75,6 +81,35 @@ func NewSniffer(s *session.Session) *Sniffer {
return sniff.Stop()
}))
sniff.AddHandler(session.NewModuleHandler("net.fuzz on", "",
"Enable fuzzing for every sniffed packet containing the sapecified layers.",
func(args []string) error {
return sniff.StartFuzzing()
}))
sniff.AddHandler(session.NewModuleHandler("net.fuzz off", "",
"Disable fuzzing",
func(args []string) error {
return sniff.StopFuzzing()
}))
sniff.AddParam(session.NewStringParameter("net.fuzz.layers",
"Payload",
"",
"Types of layer to fuzz."))
sniff.AddParam(session.NewDecimalParameter("net.fuzz.rate",
"1.0",
"Rate in the [0.0,1.0] interval of packets to fuzz."))
sniff.AddParam(session.NewDecimalParameter("net.fuzz.ratio",
"0.4",
"Rate in the [0.0,1.0] interval of bytes to fuzz for each packet."))
sniff.AddParam(session.NewBoolParameter("net.fuzz.silent",
"false",
"If true it will not report fuzzed packets."))
return sniff
}
......@@ -149,6 +184,10 @@ func (s *Sniffer) Start() error {
s.Stats.NumLocal++
}
if s.fuzzActive {
s.doFuzzing(packet)
}
if s.Ctx.DumpLocal || !isLocal {
data := packet.Data()
if s.Ctx.Compiled == nil || s.Ctx.Compiled.Match(data) {
......
package modules
import (
"math/rand"
"strings"
"github.com/google/gopacket"
"github.com/bettercap/bettercap/log"
"github.com/evilsocket/islazy/str"
"github.com/evilsocket/islazy/tui"
)
var mutators = []func(byte) byte{
func(b byte) byte {
return byte(rand.Intn(256) & 0xff)
},
func(b byte) byte {
return byte(b << uint(rand.Intn(9)))
},
func(b byte) byte {
return byte(b >> uint(rand.Intn(9)))
},
}
func (s *Sniffer) fuzz(data []byte) int {
changes := 0
for off, b := range data {
if rand.Float64() > s.fuzzRatio {
continue
}
data[off] = mutators[rand.Intn(len(mutators))](b)
changes++
}
return changes
}
func (s *Sniffer) doFuzzing(pkt gopacket.Packet) {
if rand.Float64() > s.fuzzRate {
return
}
layersChanged := 0
bytesChanged := 0
for _, fuzzLayerType := range s.fuzzLayers {
for _, layer := range pkt.Layers() {
if layer.LayerType().String() == fuzzLayerType {
fuzzData := layer.LayerContents()
changes := s.fuzz(fuzzData)
if changes > 0 {
layersChanged++
bytesChanged += changes
}
}
}
}
if bytesChanged > 0 {
logFn := log.Info
if s.fuzzSilent {
logFn = log.Debug
}
logFn("[%s] changed %d bytes in %d layers.", tui.Green("net.fuzz"), bytesChanged, layersChanged)
if err := s.Session.Queue.Send(pkt.Data()); err != nil {
log.Error("error sending fuzzed packet: %s", err)
}
}
}
func (s *Sniffer) configureFuzzing() (err error) {
layers := ""
if err, layers = s.StringParam("net.fuzz.layers"); err != nil {
return
} else {
s.fuzzLayers = str.Comma(layers)
}
if err, s.fuzzRate = s.DecParam("net.fuzz.rate"); err != nil {
return
}
if err, s.fuzzRatio = s.DecParam("net.fuzz.ratio"); err != nil {
return
}
if err, s.fuzzSilent = s.BoolParam("net.fuzz.silent"); err != nil {
return
}
return
}
func (s *Sniffer) StartFuzzing() error {
if s.fuzzActive {
return nil
}
if err := s.configureFuzzing(); err != nil {
return err
} else if !s.Running() {
if err := s.Start(); err != nil {
return err
}
}
s.fuzzActive = true
log.Info("[%s] active on layer types %s (rate:%f ratio:%f)", tui.Green("net.fuzz"), strings.Join(s.fuzzLayers, ","), s.fuzzRate, s.fuzzRatio)
return nil
}
func (s *Sniffer) StopFuzzing() error {
s.fuzzActive = false
return nil
}
package modules
import (
"fmt"
"regexp"
"strings"
"github.com/bettercap/bettercap/session"
"github.com/evilsocket/islazy/tui"
)
type ViewSelector struct {
owner *session.SessionModule
Filter string
filterName string
filterPrev string
Expression *regexp.Regexp
SortField string
Sort string
SortSymbol string
sortFields map[string]bool
sortName string
sortParser string
sortParse *regexp.Regexp
Limit int
limitName string
}
func ViewSelectorFor(m *session.SessionModule, prefix string, sortFields []string, defExpression string) *ViewSelector {
parser := "(" + strings.Join(sortFields, "|") + ") (desc|asc)"
s := &ViewSelector{
owner: m,
filterName: prefix + ".filter",
sortName: prefix + ".sort",
sortParser: parser,
sortParse: regexp.MustCompile(parser),
limitName: prefix + ".limit",
}
m.AddParam(session.NewStringParameter(s.filterName, "", "", "Defines a regular expression filter for "+prefix))
m.AddParam(session.NewStringParameter(
s.sortName,
defExpression,
s.sortParser,
"Defines sorting field ("+strings.Join(sortFields, ", ")+") and direction (asc or desc) for "+prefix))
m.AddParam(session.NewIntParameter(s.limitName, "0", "Defines limit for "+prefix))
s.parseSorting()
return s
}
func (s *ViewSelector) parseFilter() (err error) {
if err, s.Filter = s.owner.StringParam(s.filterName); err != nil {
return
}
if s.Filter != "" {
if s.Filter != s.filterPrev {
if s.Expression, err = regexp.Compile(s.Filter); err != nil {
return
}
}
} else {
s.Expression = nil
}
s.filterPrev = s.Filter
return
}
func (s *ViewSelector) parseSorting() (err error) {
expr := ""
if err, expr = s.owner.StringParam(s.sortName); err != nil {
return
}
tokens := s.sortParse.FindAllStringSubmatch(expr, -1)
if tokens == nil {
return fmt.Errorf("expression '%s' doesn't parse", expr)
}
s.SortField = tokens[0][1]
s.Sort = tokens[0][2]
s.SortSymbol = tui.Blue("▾")
if s.Sort == "asc" {
s.SortSymbol = tui.Blue("▴")
}
return
}
func (s *ViewSelector) Update() (err error) {
if err = s.parseFilter(); err != nil {
return
} else if err = s.parseSorting(); err != nil {
return
} else if err, s.Limit = s.owner.IntParam(s.limitName); err != nil {
return
}
return
}
......@@ -40,6 +40,7 @@ type WiFiModule struct {
writes *sync.WaitGroup
reads *sync.WaitGroup
chanLock *sync.Mutex
selector *ViewSelector
}
func NewWiFiModule(s *session.Session) *WiFiModule {
......@@ -140,12 +141,21 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
"true",
"If true, the fake access point will use WPA2, otherwise it'll result as an open AP."))
w.AddHandler(session.NewModuleHandler("wifi.show.wps BSSID", "wifi.show.wps ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))",
"Show WPS information about a given station.",
func(args []string) error {
return w.ShowWPS(args[0])
}))
w.AddHandler(session.NewModuleHandler("wifi.show", "",
"Show current wireless stations list (default sorting by essid).",
func(args []string) error {
return w.Show("rssi")
return w.Show()
}))
w.selector = ViewSelectorFor(&w.SessionModule, "wifi.show",
[]string{"rssi", "bssid", "essid", "channel", "encryption", "clients", "seen", "sent", "rcvd"}, "rssi asc")
w.AddHandler(session.NewModuleHandler("wifi.recon.channel", `wifi\.recon\.channel[\s]+([0-9]+(?:[, ]+[0-9]+)*|clear)`,
"WiFi channels (comma separated) or 'clear' for channel hopping.",
func(args []string) error {
......@@ -262,6 +272,25 @@ func (w *WiFiModule) Configure() error {
return nil
}
func (w *WiFiModule) updateInfo(dot11 *layers.Dot11, packet gopacket.Packet) {
if ok, enc, cipher, auth := packets.Dot11ParseEncryption(packet, dot11); ok {
bssid := dot11.Address3.String()
if station, found := w.Session.WiFi.Get(bssid); found {
station.Encryption = enc
station.Cipher = cipher
station.Authentication = auth
}
}
if ok, bssid, info := packets.Dot11ParseWPS(packet, dot11); ok {
if station, found := w.Session.WiFi.Get(bssid.String()); found {
for name, value := range info {
station.WPS[name] = value
}
}
}
}
func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
// collect stats from data frames
if dot11.Type.MainType() == layers.Dot11TypeData {
......@@ -277,15 +306,6 @@ func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
station.Sent += bytes
}
}
if ok, enc, cipher, auth := packets.Dot11ParseEncryption(packet, dot11); ok {
bssid := dot11.Address3.String()
if station, found := w.Session.WiFi.Get(bssid); found {
station.Encryption = enc
station.Cipher = cipher
station.Authentication = auth
}
}
}
func (w *WiFiModule) Start() error {
......@@ -327,6 +347,7 @@ func (w *WiFiModule) Start() error {
w.discoverProbes(radiotap, dot11, packet)
w.discoverAccessPoints(radiotap, dot11, packet)
w.discoverClients(radiotap, dot11, packet)
w.updateInfo(dot11, packet)
w.updateStats(dot11, packet)
}
}
......
......@@ -78,7 +78,6 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
return []string{
fmt.Sprintf("%d dBm", station.RSSI),
bssid,
/* station.Vendor, */
strconv.Itoa(station.Channel()),
sent,
recvd,
......@@ -95,12 +94,29 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
}
}
wps := ""
if station.HasWPS() {
if ver, found := station.WPS["Version"]; found {
wps = ver
} else {
wps = "✔"
}
if state, found := station.WPS["State"]; found {
if state == "Not Configured" {
wps += " (not configured)"
}
}
wps = tui.Dim(tui.Yellow(wps))
}
return []string{
fmt.Sprintf("%d dBm", station.RSSI),
bssid,
ssid,
/* station.Vendor, */
encryption,
wps,
strconv.Itoa(station.Channel()),
clients,
sent,
......@@ -110,52 +126,156 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
}
}
func (w *WiFiModule) Show(by string) error {
var stations []*network.Station
func (w *WiFiModule) doFilter(station *network.Station) bool {
if w.selector.Expression == nil {
return true
}
return w.selector.Expression.MatchString(station.BSSID()) ||
w.selector.Expression.MatchString(station.ESSID()) ||
w.selector.Expression.MatchString(station.Alias) ||
w.selector.Expression.MatchString(station.Vendor) ||
w.selector.Expression.MatchString(station.Encryption)
}
func (w *WiFiModule) doSelection() (err error, stations []*network.Station) {
if err = w.selector.Update(); err != nil {
return
}
apSelected := w.isApSelected()
if apSelected {
if ap, found := w.Session.WiFi.Get(w.ap.HwAddress); found {
stations = ap.Clients()
} else {
return fmt.Errorf("Could not find station %s", w.ap.HwAddress)
err = fmt.Errorf("Could not find station %s", w.ap.HwAddress)
return
}
} else {
stations = w.Session.WiFi.Stations()
}
switch by {
filtered := []*network.Station{}
for _, station := range stations {
if w.doFilter(station) {
filtered = append(filtered, station)
}
}
stations = filtered
switch w.selector.SortField {
case "seen":