From 7e7f2ef6453d9c13058f22e8a58a22145233b48b Mon Sep 17 00:00:00 2001 From: evilsocket Date: Thu, 21 Mar 2019 19:39:08 +0100 Subject: [PATCH] new: aliases are now centralized and can be used for any type of device (closes #504) --- modules/wifi/wifi_recon.go | 2 +- modules/wifi/wifi_recon_handshakes.go | 2 +- network/ble.go | 11 ++++++- network/ble_device.go | 3 ++ network/hid.go | 12 ++++++- network/hid_device.go | 3 ++ network/lan.go | 25 +-------------- network/wifi.go | 29 +++++++++++------ network/wifi_ap.go | 15 +++++---- session/session.go | 18 ++++++++--- session/session_core_handlers.go | 46 +++++++++++++++++++++++++-- 11 files changed, 115 insertions(+), 51 deletions(-) diff --git a/modules/wifi/wifi_recon.go b/modules/wifi/wifi_recon.go index dab0360b..6e62d0d9 100644 --- a/modules/wifi/wifi_recon.go +++ b/modules/wifi/wifi_recon.go @@ -124,7 +124,7 @@ func (mod *WiFiModule) discoverClients(radiotap *layers.RadioTap, dot11 *layers. freq := int(radiotap.ChannelFrequency) rssi := radiotap.DBMAntennaSignal - if station, isNew := ap.AddClientIfNew(bssid, freq, rssi, mod.Session.Lan.Aliases()); isNew { + if station, isNew := ap.AddClientIfNew(bssid, freq, rssi); isNew { mod.Session.Events.Add("wifi.client.new", ClientEvent{ AP: ap, Client: station, diff --git a/modules/wifi/wifi_recon_handshakes.go b/modules/wifi/wifi_recon_handshakes.go index 7c5045a5..a8eb676e 100644 --- a/modules/wifi/wifi_recon_handshakes.go +++ b/modules/wifi/wifi_recon_handshakes.go @@ -36,7 +36,7 @@ func (mod *WiFiModule) discoverHandshakes(radiotap *layers.RadioTap, dot11 *laye staIsUs := bytes.Equal(staMac, mod.iface.HW) station, found := ap.Get(staMac.String()) if !found { - station, _ = ap.AddClientIfNew(staMac.String(), ap.Frequency, ap.RSSI, mod.Session.Lan.Aliases()) + station, _ = ap.AddClientIfNew(staMac.String(), ap.Frequency, ap.RSSI) } rawPMKID := []byte(nil) diff --git a/network/ble.go b/network/ble.go index c167ae17..0b492194 100644 --- a/network/ble.go +++ b/network/ble.go @@ -9,6 +9,8 @@ import ( "time" "github.com/bettercap/gatt" + + "github.com/evilsocket/islazy/data" ) const BLEMacValidator = "([a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2})" @@ -18,6 +20,7 @@ type BLEDevLostCallback func(dev *BLEDevice) type BLE struct { sync.RWMutex + aliases *data.UnsortedKV devices map[string]*BLEDevice newCb BLEDevNewCallback lostCb BLEDevLostCallback @@ -27,9 +30,10 @@ type bleJSON struct { Devices []*BLEDevice `json:"devices"` } -func NewBLE(newcb BLEDevNewCallback, lostcb BLEDevLostCallback) *BLE { +func NewBLE(aliases *data.UnsortedKV, newcb BLEDevNewCallback, lostcb BLEDevLostCallback) *BLE { return &BLE{ devices: make(map[string]*BLEDevice), + aliases: aliases, newCb: newcb, lostCb: lostcb, } @@ -55,14 +59,19 @@ func (b *BLE) AddIfNew(id string, p gatt.Peripheral, a *gatt.Advertisement, rssi defer b.Unlock() id = NormalizeMac(id) + alias := b.aliases.GetOr(id, "") if dev, found := b.devices[id]; found { dev.LastSeen = time.Now() dev.RSSI = rssi dev.Advertisement = a + if alias != "" { + dev.Alias = alias + } return dev } newDev := NewBLEDevice(p, a, rssi) + newDev.Alias = alias b.devices[id] = newDev if b.newCb != nil { diff --git a/network/ble_device.go b/network/ble_device.go index 3cb115aa..0b1ef7bb 100644 --- a/network/ble_device.go +++ b/network/ble_device.go @@ -27,6 +27,7 @@ type BLEService struct { } type BLEDevice struct { + Alias string LastSeen time.Time DeviceName string Vendor string @@ -40,6 +41,7 @@ type bleDeviceJSON struct { LastSeen time.Time `json:"last_seen"` Name string `json:"name"` MAC string `json:"mac"` + Alias string `json:"alias"` Vendor string `json:"vendor"` RSSI int `json:"rssi"` Connectable bool `json:"connectable"` @@ -81,6 +83,7 @@ func (d *BLEDevice) MarshalJSON() ([]byte, error) { LastSeen: d.LastSeen, Name: d.Name(), MAC: d.Device.ID(), + Alias: d.Alias, Vendor: d.Vendor, RSSI: d.RSSI, Connectable: d.Advertisement.Connectable, diff --git a/network/hid.go b/network/hid.go index bb8e3605..ed332381 100644 --- a/network/hid.go +++ b/network/hid.go @@ -4,6 +4,8 @@ import ( "encoding/json" "sync" "time" + + "github.com/evilsocket/islazy/data" ) type HIDDevNewCallback func(dev *HIDDevice) @@ -11,6 +13,7 @@ type HIDDevLostCallback func(dev *HIDDevice) type HID struct { sync.RWMutex + aliases *data.UnsortedKV devices map[string]*HIDDevice newCb HIDDevNewCallback lostCb HIDDevLostCallback @@ -20,9 +23,10 @@ type hidJSON struct { Devices []*HIDDevice `json:"devices"` } -func NewHID(newcb HIDDevNewCallback, lostcb HIDDevLostCallback) *HID { +func NewHID(aliases *data.UnsortedKV, newcb HIDDevNewCallback, lostcb HIDDevLostCallback) *HID { return &HID{ devices: make(map[string]*HIDDevice), + aliases: aliases, newCb: newcb, lostCb: lostcb, } @@ -52,14 +56,20 @@ func (b *HID) AddIfNew(address []byte, channel int, payload []byte) (bool, *HIDD defer b.Unlock() id := HIDAddress(address) + alias := b.aliases.GetOr(id, "") + if dev, found := b.devices[id]; found { dev.LastSeen = time.Now() dev.AddChannel(channel) dev.AddPayload(payload) + if alias != "" { + dev.Alias = alias + } return false, dev } newDev := NewHIDDevice(address, channel, payload) + newDev.Alias = alias b.devices[id] = newDev if b.newCb != nil { diff --git a/network/hid_device.go b/network/hid_device.go index 8104bd6b..16dac6f1 100644 --- a/network/hid_device.go +++ b/network/hid_device.go @@ -42,6 +42,7 @@ type HIDDevice struct { sync.Mutex LastSeen time.Time Type HIDType + Alias string Address string RawAddress []byte channels map[int]bool @@ -53,6 +54,7 @@ type hidDeviceJSON struct { LastSeen time.Time `json:"last_seen"` Type string `json:"type"` Address string `json:"address"` + Alias string `json:"alias"` Channels []string `json:"channels"` Payloads []string `json:"payloads"` PayloadsSize uint64 `json:"payloads_size"` @@ -102,6 +104,7 @@ func (dev *HIDDevice) MarshalJSON() ([]byte, error) { LastSeen: dev.LastSeen, Type: dev.Type.String(), Address: dev.Address, + Alias: dev.Alias, Channels: dev.channelsListUnlocked(), Payloads: make([]string, 0), PayloadsSize: dev.payloadsSz, diff --git a/network/lan.go b/network/lan.go index 9363c0ba..0c2bef8f 100644 --- a/network/lan.go +++ b/network/lan.go @@ -2,23 +2,18 @@ package network import ( "encoding/json" - "fmt" "net" "strings" "sync" "github.com/evilsocket/islazy/data" - "github.com/evilsocket/islazy/fs" ) const LANDefaultttl = 10 -const LANAliasesFile = "~/bettercap.aliases" type EndpointNewCallback func(e *Endpoint) type EndpointLostCallback func(e *Endpoint) -var aliasesFileName, _ = fs.Expand(LANAliasesFile) - type LAN struct { sync.Mutex hosts map[string]*Endpoint @@ -34,12 +29,7 @@ type lanJSON struct { Hosts []*Endpoint `json:"hosts"` } -func NewLAN(iface, gateway *Endpoint, newcb EndpointNewCallback, lostcb EndpointLostCallback) *LAN { - aliases, err := data.NewUnsortedKV(aliasesFileName, data.FlushOnEdit) - if err != nil { - fmt.Printf("error loading %s: %s", aliasesFileName, err) - } - +func NewLAN(iface, gateway *Endpoint, aliases *data.UnsortedKV, newcb EndpointNewCallback, lostcb EndpointLostCallback) *LAN { return &LAN{ iface: iface, gateway: gateway, @@ -63,19 +53,6 @@ func (l *LAN) MarshalJSON() ([]byte, error) { return json.Marshal(doc) } -func (lan *LAN) SetAliasFor(mac, alias string) bool { - lan.Lock() - defer lan.Unlock() - - mac = NormalizeMac(mac) - lan.aliases.Set(mac, alias) - if e, found := lan.hosts[mac]; found { - e.Alias = alias - return true - } - return false -} - func (lan *LAN) Get(mac string) (*Endpoint, bool) { lan.Lock() defer lan.Unlock() diff --git a/network/wifi.go b/network/wifi.go index 9d991652..db416c32 100644 --- a/network/wifi.go +++ b/network/wifi.go @@ -11,6 +11,7 @@ import ( "github.com/google/gopacket/layers" "github.com/google/gopacket/pcapgo" + "github.com/evilsocket/islazy/data" "github.com/evilsocket/islazy/fs" ) @@ -43,22 +44,24 @@ type APLostCallback func(ap *AccessPoint) type WiFi struct { sync.Mutex - aps map[string]*AccessPoint - iface *Endpoint - newCb APNewCallback - lostCb APLostCallback + aliases *data.UnsortedKV + aps map[string]*AccessPoint + iface *Endpoint + newCb APNewCallback + lostCb APLostCallback } type wifiJSON struct { AccessPoints []*AccessPoint `json:"aps"` } -func NewWiFi(iface *Endpoint, newcb APNewCallback, lostcb APLostCallback) *WiFi { +func NewWiFi(iface *Endpoint, aliases *data.UnsortedKV, newcb APNewCallback, lostcb APLostCallback) *WiFi { return &WiFi{ - aps: make(map[string]*AccessPoint), - iface: iface, - newCb: newcb, - lostCb: lostcb, + aps: make(map[string]*AccessPoint), + aliases: aliases, + iface: iface, + newCb: newcb, + lostCb: lostcb, } } @@ -134,6 +137,7 @@ func (w *WiFi) AddIfNew(ssid, mac string, frequency int, rssi int8) (*AccessPoin defer w.Unlock() mac = NormalizeMac(mac) + alias := w.aliases.GetOr(mac, "") if ap, found := w.aps[mac]; found { ap.LastSeen = time.Now() if rssi != 0 { @@ -143,10 +147,15 @@ func (w *WiFi) AddIfNew(ssid, mac string, frequency int, rssi int8) (*AccessPoin if !isBogusMacESSID(ssid) { ap.Hostname = ssid } + + if alias != "" { + ap.Alias = alias + } return ap, false } - newAp := NewAccessPoint(ssid, mac, frequency, rssi) + newAp := NewAccessPoint(ssid, mac, frequency, rssi, w.aliases) + newAp.Alias = alias w.aps[mac] = newAp if w.newCb != nil { diff --git a/network/wifi_ap.go b/network/wifi_ap.go index ec864916..58143cc0 100644 --- a/network/wifi_ap.go +++ b/network/wifi_ap.go @@ -12,6 +12,7 @@ type AccessPoint struct { *Station sync.Mutex + aliases *data.UnsortedKV clients map[string]*Station withKeyMaterial bool } @@ -22,9 +23,10 @@ type apJSON struct { Handshake bool `json:"handshake"` } -func NewAccessPoint(essid, bssid string, frequency int, rssi int8) *AccessPoint { +func NewAccessPoint(essid, bssid string, frequency int, rssi int8, aliases *data.UnsortedKV) *AccessPoint { return &AccessPoint{ Station: NewStation(essid, bssid, frequency, rssi), + aliases: aliases, clients: make(map[string]*Station), } } @@ -67,11 +69,12 @@ func (ap *AccessPoint) RemoveClient(mac string) { } } -func (ap *AccessPoint) AddClientIfNew(bssid string, frequency int, rssi int8, aliases *data.UnsortedKV) (*Station, bool) { +func (ap *AccessPoint) AddClientIfNew(bssid string, frequency int, rssi int8) (*Station, bool) { ap.Lock() defer ap.Unlock() bssid = NormalizeMac(bssid) + alias := ap.aliases.GetOr(bssid, "") if s, found := ap.clients[bssid]; found { // update @@ -79,17 +82,15 @@ func (ap *AccessPoint) AddClientIfNew(bssid string, frequency int, rssi int8, al s.RSSI = rssi s.LastSeen = time.Now() - if aliases != nil { - s.Alias = aliases.GetOr(bssid, "") + if alias != "" { + s.Alias = alias } return s, false } s := NewStation("", bssid, frequency, rssi) - if aliases != nil { - s.Alias = aliases.GetOr(bssid, "") - } + s.Alias = alias ap.clients[bssid] = s return s, true diff --git a/session/session.go b/session/session.go index 2dd8a04f..ba49a03d 100644 --- a/session/session.go +++ b/session/session.go @@ -20,6 +20,7 @@ import ( "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" + "github.com/evilsocket/islazy/data" "github.com/evilsocket/islazy/fs" "github.com/evilsocket/islazy/log" "github.com/evilsocket/islazy/ops" @@ -54,6 +55,10 @@ type GPS struct { Separation float64 // Geoidal separation } +const AliasesFile = "~/bettercap.aliases" + +var aliasesFileName, _ = fs.Expand(AliasesFile) + type Session struct { Options core.Options Interface *network.Endpoint @@ -68,6 +73,7 @@ type Session struct { Active bool GPS GPS Modules ModuleList + Aliases *data.UnsortedKV Input *readline.Instance Prompt Prompt @@ -115,6 +121,10 @@ func New() (*Session, error) { return nil, err } + if s.Aliases, err = data.NewUnsortedKV(aliasesFileName, data.FlushOnEdit); err != nil { + return nil, err + } + s.Events = NewEventPool(*s.Options.Debug, *s.Options.Silent) s.registerCoreHandlers() @@ -235,25 +245,25 @@ func (s *Session) Start() error { s.Firewall = firewall.Make(s.Interface) - s.HID = network.NewHID(func(dev *network.HIDDevice) { + s.HID = network.NewHID(s.Aliases, func(dev *network.HIDDevice) { s.Events.Add("hid.device.new", dev) }, func(dev *network.HIDDevice) { s.Events.Add("hid.device.lost", dev) }) - s.BLE = network.NewBLE(func(dev *network.BLEDevice) { + s.BLE = network.NewBLE(s.Aliases, func(dev *network.BLEDevice) { s.Events.Add("ble.device.new", dev) }, func(dev *network.BLEDevice) { s.Events.Add("ble.device.lost", dev) }) - s.WiFi = network.NewWiFi(s.Interface, func(ap *network.AccessPoint) { + s.WiFi = network.NewWiFi(s.Interface, s.Aliases, func(ap *network.AccessPoint) { s.Events.Add("wifi.ap.new", ap) }, func(ap *network.AccessPoint) { s.Events.Add("wifi.ap.lost", ap) }) - s.Lan = network.NewLAN(s.Interface, s.Gateway, func(e *network.Endpoint) { + s.Lan = network.NewLAN(s.Interface, s.Gateway, s.Aliases, func(e *network.Endpoint) { s.Events.Add("endpoint.new", e) }, func(e *network.Endpoint) { s.Events.Add("endpoint.lost", e) diff --git a/session/session_core_handlers.go b/session/session_core_handlers.go index 13f48419..09da1776 100644 --- a/session/session_core_handlers.go +++ b/session/session_core_handlers.go @@ -271,13 +271,55 @@ func (s *Session) shHandler(args []string, sess *Session) error { return err } +func normalizeMac(mac string) string { + var parts []string + if strings.ContainsRune(mac, '-') { + parts = strings.Split(mac, "-") + } else { + parts = strings.Split(mac, ":") + } + + for i, p := range parts { + if len(p) < 2 { + parts[i] = "0" + p + } + } + return strings.ToLower(strings.Join(parts, ":")) +} + +func (s *Session) propagateAlias(mac, alias string) { + mac = normalizeMac(mac) + + s.Aliases.Set(mac, alias) + + if dev, found := s.BLE.Get(mac); found { + dev.Alias = alias + } + + if dev, found := s.HID.Get(mac); found { + dev.Alias = alias + } + + if ap, found := s.WiFi.Get(mac); found { + ap.Alias = alias + } + + if sta, found := s.WiFi.GetClient(mac); found { + sta.Alias = alias + } + + if host, found := s.Lan.Get(mac); found { + host.Alias = alias + } +} + func (s *Session) aliasHandler(args []string, sess *Session) error { mac := args[0] alias := str.Trim(args[1]) if alias == "\"\"" || alias == "''" { alias = "" } - s.Lan.SetAliasFor(mac, alias) + s.propagateAlias(mac, alias) return nil } @@ -383,7 +425,7 @@ func (s *Session) registerCoreHandlers() { readline.PcItem("!")) s.addHandler(NewCommandHandler("alias MAC NAME", - "^alias\\s+([a-fA-F0-9:]{17})\\s*(.*)", + "^alias\\s+([a-fA-F0-9:]{14,17})\\s*(.*)", "Assign an alias to a given endpoint given its MAC address.", s.aliasHandler), readline.PcItem("alias", readline.PcItemDynamic(func(prefix string) []string {