new: aliases are now centralized and can be used for any type of device (closes #504)

This commit is contained in:
evilsocket 2019-03-21 19:39:08 +01:00
parent 96853e663b
commit 7e7f2ef645
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
11 changed files with 115 additions and 51 deletions

View file

@ -124,7 +124,7 @@ func (mod *WiFiModule) discoverClients(radiotap *layers.RadioTap, dot11 *layers.
freq := int(radiotap.ChannelFrequency) freq := int(radiotap.ChannelFrequency)
rssi := radiotap.DBMAntennaSignal 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{ mod.Session.Events.Add("wifi.client.new", ClientEvent{
AP: ap, AP: ap,
Client: station, Client: station,

View file

@ -36,7 +36,7 @@ func (mod *WiFiModule) discoverHandshakes(radiotap *layers.RadioTap, dot11 *laye
staIsUs := bytes.Equal(staMac, mod.iface.HW) staIsUs := bytes.Equal(staMac, mod.iface.HW)
station, found := ap.Get(staMac.String()) station, found := ap.Get(staMac.String())
if !found { 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) rawPMKID := []byte(nil)

View file

@ -9,6 +9,8 @@ import (
"time" "time"
"github.com/bettercap/gatt" "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})" 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 { type BLE struct {
sync.RWMutex sync.RWMutex
aliases *data.UnsortedKV
devices map[string]*BLEDevice devices map[string]*BLEDevice
newCb BLEDevNewCallback newCb BLEDevNewCallback
lostCb BLEDevLostCallback lostCb BLEDevLostCallback
@ -27,9 +30,10 @@ type bleJSON struct {
Devices []*BLEDevice `json:"devices"` Devices []*BLEDevice `json:"devices"`
} }
func NewBLE(newcb BLEDevNewCallback, lostcb BLEDevLostCallback) *BLE { func NewBLE(aliases *data.UnsortedKV, newcb BLEDevNewCallback, lostcb BLEDevLostCallback) *BLE {
return &BLE{ return &BLE{
devices: make(map[string]*BLEDevice), devices: make(map[string]*BLEDevice),
aliases: aliases,
newCb: newcb, newCb: newcb,
lostCb: lostcb, lostCb: lostcb,
} }
@ -55,14 +59,19 @@ func (b *BLE) AddIfNew(id string, p gatt.Peripheral, a *gatt.Advertisement, rssi
defer b.Unlock() defer b.Unlock()
id = NormalizeMac(id) id = NormalizeMac(id)
alias := b.aliases.GetOr(id, "")
if dev, found := b.devices[id]; found { if dev, found := b.devices[id]; found {
dev.LastSeen = time.Now() dev.LastSeen = time.Now()
dev.RSSI = rssi dev.RSSI = rssi
dev.Advertisement = a dev.Advertisement = a
if alias != "" {
dev.Alias = alias
}
return dev return dev
} }
newDev := NewBLEDevice(p, a, rssi) newDev := NewBLEDevice(p, a, rssi)
newDev.Alias = alias
b.devices[id] = newDev b.devices[id] = newDev
if b.newCb != nil { if b.newCb != nil {

View file

@ -27,6 +27,7 @@ type BLEService struct {
} }
type BLEDevice struct { type BLEDevice struct {
Alias string
LastSeen time.Time LastSeen time.Time
DeviceName string DeviceName string
Vendor string Vendor string
@ -40,6 +41,7 @@ type bleDeviceJSON struct {
LastSeen time.Time `json:"last_seen"` LastSeen time.Time `json:"last_seen"`
Name string `json:"name"` Name string `json:"name"`
MAC string `json:"mac"` MAC string `json:"mac"`
Alias string `json:"alias"`
Vendor string `json:"vendor"` Vendor string `json:"vendor"`
RSSI int `json:"rssi"` RSSI int `json:"rssi"`
Connectable bool `json:"connectable"` Connectable bool `json:"connectable"`
@ -81,6 +83,7 @@ func (d *BLEDevice) MarshalJSON() ([]byte, error) {
LastSeen: d.LastSeen, LastSeen: d.LastSeen,
Name: d.Name(), Name: d.Name(),
MAC: d.Device.ID(), MAC: d.Device.ID(),
Alias: d.Alias,
Vendor: d.Vendor, Vendor: d.Vendor,
RSSI: d.RSSI, RSSI: d.RSSI,
Connectable: d.Advertisement.Connectable, Connectable: d.Advertisement.Connectable,

View file

@ -4,6 +4,8 @@ import (
"encoding/json" "encoding/json"
"sync" "sync"
"time" "time"
"github.com/evilsocket/islazy/data"
) )
type HIDDevNewCallback func(dev *HIDDevice) type HIDDevNewCallback func(dev *HIDDevice)
@ -11,6 +13,7 @@ type HIDDevLostCallback func(dev *HIDDevice)
type HID struct { type HID struct {
sync.RWMutex sync.RWMutex
aliases *data.UnsortedKV
devices map[string]*HIDDevice devices map[string]*HIDDevice
newCb HIDDevNewCallback newCb HIDDevNewCallback
lostCb HIDDevLostCallback lostCb HIDDevLostCallback
@ -20,9 +23,10 @@ type hidJSON struct {
Devices []*HIDDevice `json:"devices"` Devices []*HIDDevice `json:"devices"`
} }
func NewHID(newcb HIDDevNewCallback, lostcb HIDDevLostCallback) *HID { func NewHID(aliases *data.UnsortedKV, newcb HIDDevNewCallback, lostcb HIDDevLostCallback) *HID {
return &HID{ return &HID{
devices: make(map[string]*HIDDevice), devices: make(map[string]*HIDDevice),
aliases: aliases,
newCb: newcb, newCb: newcb,
lostCb: lostcb, lostCb: lostcb,
} }
@ -52,14 +56,20 @@ func (b *HID) AddIfNew(address []byte, channel int, payload []byte) (bool, *HIDD
defer b.Unlock() defer b.Unlock()
id := HIDAddress(address) id := HIDAddress(address)
alias := b.aliases.GetOr(id, "")
if dev, found := b.devices[id]; found { if dev, found := b.devices[id]; found {
dev.LastSeen = time.Now() dev.LastSeen = time.Now()
dev.AddChannel(channel) dev.AddChannel(channel)
dev.AddPayload(payload) dev.AddPayload(payload)
if alias != "" {
dev.Alias = alias
}
return false, dev return false, dev
} }
newDev := NewHIDDevice(address, channel, payload) newDev := NewHIDDevice(address, channel, payload)
newDev.Alias = alias
b.devices[id] = newDev b.devices[id] = newDev
if b.newCb != nil { if b.newCb != nil {

View file

@ -42,6 +42,7 @@ type HIDDevice struct {
sync.Mutex sync.Mutex
LastSeen time.Time LastSeen time.Time
Type HIDType Type HIDType
Alias string
Address string Address string
RawAddress []byte RawAddress []byte
channels map[int]bool channels map[int]bool
@ -53,6 +54,7 @@ type hidDeviceJSON struct {
LastSeen time.Time `json:"last_seen"` LastSeen time.Time `json:"last_seen"`
Type string `json:"type"` Type string `json:"type"`
Address string `json:"address"` Address string `json:"address"`
Alias string `json:"alias"`
Channels []string `json:"channels"` Channels []string `json:"channels"`
Payloads []string `json:"payloads"` Payloads []string `json:"payloads"`
PayloadsSize uint64 `json:"payloads_size"` PayloadsSize uint64 `json:"payloads_size"`
@ -102,6 +104,7 @@ func (dev *HIDDevice) MarshalJSON() ([]byte, error) {
LastSeen: dev.LastSeen, LastSeen: dev.LastSeen,
Type: dev.Type.String(), Type: dev.Type.String(),
Address: dev.Address, Address: dev.Address,
Alias: dev.Alias,
Channels: dev.channelsListUnlocked(), Channels: dev.channelsListUnlocked(),
Payloads: make([]string, 0), Payloads: make([]string, 0),
PayloadsSize: dev.payloadsSz, PayloadsSize: dev.payloadsSz,

View file

@ -2,23 +2,18 @@ package network
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net" "net"
"strings" "strings"
"sync" "sync"
"github.com/evilsocket/islazy/data" "github.com/evilsocket/islazy/data"
"github.com/evilsocket/islazy/fs"
) )
const LANDefaultttl = 10 const LANDefaultttl = 10
const LANAliasesFile = "~/bettercap.aliases"
type EndpointNewCallback func(e *Endpoint) type EndpointNewCallback func(e *Endpoint)
type EndpointLostCallback func(e *Endpoint) type EndpointLostCallback func(e *Endpoint)
var aliasesFileName, _ = fs.Expand(LANAliasesFile)
type LAN struct { type LAN struct {
sync.Mutex sync.Mutex
hosts map[string]*Endpoint hosts map[string]*Endpoint
@ -34,12 +29,7 @@ type lanJSON struct {
Hosts []*Endpoint `json:"hosts"` Hosts []*Endpoint `json:"hosts"`
} }
func NewLAN(iface, gateway *Endpoint, newcb EndpointNewCallback, lostcb EndpointLostCallback) *LAN { func NewLAN(iface, gateway *Endpoint, aliases *data.UnsortedKV, newcb EndpointNewCallback, lostcb EndpointLostCallback) *LAN {
aliases, err := data.NewUnsortedKV(aliasesFileName, data.FlushOnEdit)
if err != nil {
fmt.Printf("error loading %s: %s", aliasesFileName, err)
}
return &LAN{ return &LAN{
iface: iface, iface: iface,
gateway: gateway, gateway: gateway,
@ -63,19 +53,6 @@ func (l *LAN) MarshalJSON() ([]byte, error) {
return json.Marshal(doc) 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) { func (lan *LAN) Get(mac string) (*Endpoint, bool) {
lan.Lock() lan.Lock()
defer lan.Unlock() defer lan.Unlock()

View file

@ -11,6 +11,7 @@ import (
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo" "github.com/google/gopacket/pcapgo"
"github.com/evilsocket/islazy/data"
"github.com/evilsocket/islazy/fs" "github.com/evilsocket/islazy/fs"
) )
@ -43,22 +44,24 @@ type APLostCallback func(ap *AccessPoint)
type WiFi struct { type WiFi struct {
sync.Mutex sync.Mutex
aps map[string]*AccessPoint aliases *data.UnsortedKV
iface *Endpoint aps map[string]*AccessPoint
newCb APNewCallback iface *Endpoint
lostCb APLostCallback newCb APNewCallback
lostCb APLostCallback
} }
type wifiJSON struct { type wifiJSON struct {
AccessPoints []*AccessPoint `json:"aps"` 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{ return &WiFi{
aps: make(map[string]*AccessPoint), aps: make(map[string]*AccessPoint),
iface: iface, aliases: aliases,
newCb: newcb, iface: iface,
lostCb: lostcb, newCb: newcb,
lostCb: lostcb,
} }
} }
@ -134,6 +137,7 @@ func (w *WiFi) AddIfNew(ssid, mac string, frequency int, rssi int8) (*AccessPoin
defer w.Unlock() defer w.Unlock()
mac = NormalizeMac(mac) mac = NormalizeMac(mac)
alias := w.aliases.GetOr(mac, "")
if ap, found := w.aps[mac]; found { if ap, found := w.aps[mac]; found {
ap.LastSeen = time.Now() ap.LastSeen = time.Now()
if rssi != 0 { if rssi != 0 {
@ -143,10 +147,15 @@ func (w *WiFi) AddIfNew(ssid, mac string, frequency int, rssi int8) (*AccessPoin
if !isBogusMacESSID(ssid) { if !isBogusMacESSID(ssid) {
ap.Hostname = ssid ap.Hostname = ssid
} }
if alias != "" {
ap.Alias = alias
}
return ap, false return ap, false
} }
newAp := NewAccessPoint(ssid, mac, frequency, rssi) newAp := NewAccessPoint(ssid, mac, frequency, rssi, w.aliases)
newAp.Alias = alias
w.aps[mac] = newAp w.aps[mac] = newAp
if w.newCb != nil { if w.newCb != nil {

View file

@ -12,6 +12,7 @@ type AccessPoint struct {
*Station *Station
sync.Mutex sync.Mutex
aliases *data.UnsortedKV
clients map[string]*Station clients map[string]*Station
withKeyMaterial bool withKeyMaterial bool
} }
@ -22,9 +23,10 @@ type apJSON struct {
Handshake bool `json:"handshake"` 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{ return &AccessPoint{
Station: NewStation(essid, bssid, frequency, rssi), Station: NewStation(essid, bssid, frequency, rssi),
aliases: aliases,
clients: make(map[string]*Station), 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() ap.Lock()
defer ap.Unlock() defer ap.Unlock()
bssid = NormalizeMac(bssid) bssid = NormalizeMac(bssid)
alias := ap.aliases.GetOr(bssid, "")
if s, found := ap.clients[bssid]; found { if s, found := ap.clients[bssid]; found {
// update // update
@ -79,17 +82,15 @@ func (ap *AccessPoint) AddClientIfNew(bssid string, frequency int, rssi int8, al
s.RSSI = rssi s.RSSI = rssi
s.LastSeen = time.Now() s.LastSeen = time.Now()
if aliases != nil { if alias != "" {
s.Alias = aliases.GetOr(bssid, "") s.Alias = alias
} }
return s, false return s, false
} }
s := NewStation("", bssid, frequency, rssi) s := NewStation("", bssid, frequency, rssi)
if aliases != nil { s.Alias = alias
s.Alias = aliases.GetOr(bssid, "")
}
ap.clients[bssid] = s ap.clients[bssid] = s
return s, true return s, true

View file

@ -20,6 +20,7 @@ import (
"github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/packets" "github.com/bettercap/bettercap/packets"
"github.com/evilsocket/islazy/data"
"github.com/evilsocket/islazy/fs" "github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/log" "github.com/evilsocket/islazy/log"
"github.com/evilsocket/islazy/ops" "github.com/evilsocket/islazy/ops"
@ -54,6 +55,10 @@ type GPS struct {
Separation float64 // Geoidal separation Separation float64 // Geoidal separation
} }
const AliasesFile = "~/bettercap.aliases"
var aliasesFileName, _ = fs.Expand(AliasesFile)
type Session struct { type Session struct {
Options core.Options Options core.Options
Interface *network.Endpoint Interface *network.Endpoint
@ -68,6 +73,7 @@ type Session struct {
Active bool Active bool
GPS GPS GPS GPS
Modules ModuleList Modules ModuleList
Aliases *data.UnsortedKV
Input *readline.Instance Input *readline.Instance
Prompt Prompt Prompt Prompt
@ -115,6 +121,10 @@ func New() (*Session, error) {
return nil, err 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.Events = NewEventPool(*s.Options.Debug, *s.Options.Silent)
s.registerCoreHandlers() s.registerCoreHandlers()
@ -235,25 +245,25 @@ func (s *Session) Start() error {
s.Firewall = firewall.Make(s.Interface) 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) s.Events.Add("hid.device.new", dev)
}, func(dev *network.HIDDevice) { }, func(dev *network.HIDDevice) {
s.Events.Add("hid.device.lost", dev) 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) s.Events.Add("ble.device.new", dev)
}, func(dev *network.BLEDevice) { }, func(dev *network.BLEDevice) {
s.Events.Add("ble.device.lost", dev) 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) s.Events.Add("wifi.ap.new", ap)
}, func(ap *network.AccessPoint) { }, func(ap *network.AccessPoint) {
s.Events.Add("wifi.ap.lost", ap) 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) s.Events.Add("endpoint.new", e)
}, func(e *network.Endpoint) { }, func(e *network.Endpoint) {
s.Events.Add("endpoint.lost", e) s.Events.Add("endpoint.lost", e)

View file

@ -271,13 +271,55 @@ func (s *Session) shHandler(args []string, sess *Session) error {
return err 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 { func (s *Session) aliasHandler(args []string, sess *Session) error {
mac := args[0] mac := args[0]
alias := str.Trim(args[1]) alias := str.Trim(args[1])
if alias == "\"\"" || alias == "''" { if alias == "\"\"" || alias == "''" {
alias = "" alias = ""
} }
s.Lan.SetAliasFor(mac, alias) s.propagateAlias(mac, alias)
return nil return nil
} }
@ -383,7 +425,7 @@ func (s *Session) registerCoreHandlers() {
readline.PcItem("!")) readline.PcItem("!"))
s.addHandler(NewCommandHandler("alias MAC NAME", 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.", "Assign an alias to a given endpoint given its MAC address.",
s.aliasHandler), s.aliasHandler),
readline.PcItem("alias", readline.PcItemDynamic(func(prefix string) []string { readline.PcItem("alias", readline.PcItemDynamic(func(prefix string) []string {