mirror of
https://github.com/bettercap/bettercap
synced 2025-07-06 13:02:12 -07:00
220 lines
4.4 KiB
Go
220 lines
4.4 KiB
Go
package network
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/evilsocket/islazy/str"
|
|
)
|
|
|
|
type HIDType int
|
|
|
|
const (
|
|
HIDTypeUnknown HIDType = 0
|
|
HIDTypeLogitech HIDType = 1
|
|
HIDTypeAmazon HIDType = 2
|
|
HIDTypeMicrosoft HIDType = 3
|
|
HIDTypeDell HIDType = 4
|
|
)
|
|
|
|
func (t HIDType) String() string {
|
|
switch t {
|
|
case HIDTypeLogitech:
|
|
return "Logitech"
|
|
case HIDTypeAmazon:
|
|
return "Amazon"
|
|
case HIDTypeMicrosoft:
|
|
return "Microsoft"
|
|
case HIDTypeDell:
|
|
return "Dell"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
type HIDPayload []byte
|
|
|
|
type HIDDevice struct {
|
|
sync.Mutex
|
|
LastSeen time.Time
|
|
Type HIDType
|
|
Alias string
|
|
Address string
|
|
RawAddress []byte
|
|
channels map[int]bool
|
|
payloads []HIDPayload
|
|
payloadsSz uint64
|
|
}
|
|
|
|
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"`
|
|
}
|
|
|
|
func NormalizeHIDAddress(address string) string {
|
|
parts := strings.Split(address, ":")
|
|
for i, p := range parts {
|
|
if len(p) < 2 {
|
|
parts[i] = "0" + p
|
|
}
|
|
}
|
|
return strings.ToLower(strings.Join(parts, ":"))
|
|
|
|
}
|
|
|
|
func HIDAddress(address []byte) string {
|
|
octects := []string{}
|
|
for _, b := range address {
|
|
octects = append(octects, fmt.Sprintf("%02x", b))
|
|
}
|
|
return strings.ToLower(strings.Join(octects, ":"))
|
|
}
|
|
|
|
func NewHIDDevice(address []byte, channel int, payload []byte) *HIDDevice {
|
|
dev := &HIDDevice{
|
|
LastSeen: time.Now(),
|
|
Type: HIDTypeUnknown,
|
|
RawAddress: address,
|
|
Address: HIDAddress(address),
|
|
channels: make(map[int]bool),
|
|
payloads: make([]HIDPayload, 0),
|
|
payloadsSz: 0,
|
|
}
|
|
|
|
dev.AddChannel(channel)
|
|
dev.AddPayload(payload)
|
|
|
|
return dev
|
|
}
|
|
|
|
func (dev *HIDDevice) MarshalJSON() ([]byte, error) {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
|
|
doc := hidDeviceJSON{
|
|
LastSeen: dev.LastSeen,
|
|
Type: dev.Type.String(),
|
|
Address: dev.Address,
|
|
Alias: dev.Alias,
|
|
Channels: dev.channelsListUnlocked(),
|
|
Payloads: make([]string, 0),
|
|
PayloadsSize: dev.payloadsSz,
|
|
}
|
|
|
|
// get the latest 50 payloads
|
|
for i := len(dev.payloads) - 1; i >= 0; i-- {
|
|
data := str.Trim(hex.Dump(dev.payloads[i]))
|
|
doc.Payloads = append([]string{data}, doc.Payloads...)
|
|
if len(doc.Payloads) == 50 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return json.Marshal(doc)
|
|
}
|
|
|
|
func (dev *HIDDevice) AddChannel(ch int) {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
|
|
dev.channels[ch] = true
|
|
}
|
|
|
|
func (dev *HIDDevice) channelsListUnlocked() []string {
|
|
chans := []string{}
|
|
for ch := range dev.channels {
|
|
chans = append(chans, fmt.Sprintf("%d", ch))
|
|
}
|
|
|
|
sort.Strings(chans)
|
|
|
|
return chans
|
|
}
|
|
func (dev *HIDDevice) ChannelsList() []string {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
return dev.channelsListUnlocked()
|
|
}
|
|
|
|
func (dev *HIDDevice) Channels() string {
|
|
return strings.Join(dev.ChannelsList(), ",")
|
|
}
|
|
|
|
// credits to https://github.com/insecurityofthings/jackit/tree/master/jackit/plugins
|
|
func (dev *HIDDevice) onEventFrame(p []byte, sz int) {
|
|
// return if type has been already determined
|
|
if dev.Type != HIDTypeUnknown {
|
|
return
|
|
}
|
|
|
|
if sz == 6 {
|
|
dev.Type = HIDTypeAmazon
|
|
return
|
|
}
|
|
|
|
if sz == 10 && p[0] == 0x00 && p[1] == 0xc2 {
|
|
dev.Type = HIDTypeLogitech // mouse movement
|
|
return
|
|
} else if sz == 22 && p[0] == 0x00 && p[1] == 0xd3 {
|
|
dev.Type = HIDTypeLogitech // keystroke
|
|
return
|
|
} else if sz == 5 && p[0] == 0x00 && p[1] == 0x40 {
|
|
dev.Type = HIDTypeLogitech // keepalive
|
|
return
|
|
// TODO: review this condition
|
|
} else if sz == 10 && p[0] == 0x00 { //&& p[0] == 0x4f {
|
|
dev.Type = HIDTypeLogitech // sleep timer
|
|
return
|
|
}
|
|
|
|
if sz == 19 && (p[0] == 0x08 || p[0] == 0x0c) && p[6] == 0x40 {
|
|
dev.Type = HIDTypeMicrosoft
|
|
return
|
|
}
|
|
|
|
// TODO: Dell
|
|
}
|
|
|
|
func (dev *HIDDevice) AddPayload(payload []byte) {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
|
|
sz := len(payload)
|
|
if payload != nil && sz > 0 {
|
|
dev.payloads = append(dev.payloads, payload)
|
|
dev.payloadsSz += uint64(sz)
|
|
dev.onEventFrame(payload, sz)
|
|
}
|
|
}
|
|
|
|
func (dev *HIDDevice) EachPayload(cb func([]byte) bool) {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
|
|
for _, payload := range dev.payloads {
|
|
if done := cb(payload); done {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dev *HIDDevice) NumPayloads() int {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
return len(dev.payloads)
|
|
}
|
|
|
|
func (dev *HIDDevice) PayloadsSize() uint64 {
|
|
dev.Lock()
|
|
defer dev.Unlock()
|
|
return dev.payloadsSz
|
|
}
|