Merge branch 'development'

This commit is contained in:
kayos@tcp.direct 2023-11-02 18:05:27 -07:00
commit 3cd5c6b617
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
21 changed files with 4968 additions and 336 deletions

22
Makefile Normal file
View File

@ -0,0 +1,22 @@
.DEFAULT_GOAL := protomolecule
.PHONY = fmt vet all clean deps benchmark
all: main
protomolecule:
go build -ldflags="-s -w -X main.GitVersion=git-$(shell git rev-list --count HEAD)-$(shell git rev-parse --short HEAD) -X main.BuildDate=$(shell date -u +%Y-%m-%dT%H:%M:%S%Z)"
install:
cp protomolecule /usr/local/bin/
uninstall:
rm /usr/local/bin/protomolecule
benchmark:
go test -bench=.
deps:
go mod tidy -v
fmt:
find . -name "*.go" -exec gofmt -s -w {} \;
vet:
go vet ./
clean:
rm protomolecule

View File

@ -49,6 +49,8 @@ Cross platform BLE scanner and logger with teeth
- ### GATT fuzzing
- ### Advertisment fuzzing / flooding
- ### Sweyntooth
- ### Search for DFU

324
cmd.go Normal file
View File

@ -0,0 +1,324 @@
package main
import (
"fmt"
"os"
"strconv"
"strings"
cli "git.tcp.direct/Mirrors/go-prompt"
. "github.com/logrusorgru/aurora"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"protomolecule/src/eros"
// "protomolecule/src/wrath"
projVars "protomolecule/src/config"
"protomolecule/src/deimos"
)
var suggestions = []cli.Suggest{
// Main Commands
// {"scan",
// "Start and stop scans"},
{"scan start",
"Start default scan"},
{"scan start attack",
"Start scan that also attempts to connect to all discovered BLE devices"},
{"scan start tracking",
"Start continuous RSSI tracking of all BLE devices within range"},
{"eros recall mac",
"Retrieve device info from database by MAC address"},
{"eros recall all",
"Retrieve info on all devices"},
{"eros backup",
"Backup all databases to the supplied directory"},
{"arboghast start",
"Start entropic fuzzing via advertising"},
/*
{"wrath",
"attack by address"},
*/
{"exit",
"Exit ProtoMolecule"},
{"debug",
"Toggle debug messages"},
{"help",
"in-app documentation"},
}
func completer(in cli.Document) []cli.Suggest {
c := in.CurrentLineBeforeCursor()
if c == "" {
return []cli.Suggest{}
}
return cli.FilterHasPrefix(suggestions, c, true)
}
// Interpret is where we will actuall define our commands
func executor(cmd string) {
cmd = strings.TrimSpace(cmd)
var args []string
args = strings.Split(cmd, " ")
getArgs := func(args []string) string {
var ret string
for i, a := range args {
if i == 0 {
ret = a
continue
}
ret = ret + " " + a
if i != len(args)-1 {
ret = ret + " "
}
}
return ret
}
switch args[0] {
case "exit":
fallthrough
case "quit":
eros.Slumber()
os.Exit(0)
case "debug":
switch log.Logger.GetLevel() {
case zerolog.DebugLevel:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
log.Info().
Msg("Debug mode turned " + Sprintf(BrightRed("OFF\n").Bold()))
case zerolog.InfoLevel:
zerolog.SetGlobalLevel(zerolog.DebugLevel)
log.Debug().
Msg("Debug mode turned " + Sprintf(BrightGreen("ON\n").Bold()))
default:
return
}
case "eros":
if len(args) < 2 {
getHelp("eros")
return
}
switch args[1] {
case "recall":
if len(args) < 3 {
getHelp("eros recall")
return
}
switch args[2] {
case "mac":
if len(args) < 4 {
getHelp("eros recall")
return
}
fromEros, err := eros.Recall(args[3])
if err != nil {
log.Error().Err(err).Str("target", args[3]).
Msg("Failed to recall MAC")
println()
return
}
log.Info().
Str("Name", fromEros.Name).
Str("Addr", fromEros.Addr).
Str("ManuF", fromEros.Manufacturer). // needs to be changed back to fromEros.Manufacturer
Int16("Current_RSSI", fromEros.RSSIlast).
Int("Service_Count", len(fromEros.Services)).
Msg("EROS_RECALL")
case "backup":
if len(args) < 3 {
getHelp("eros backup")
return
}
if err := eros.Backup(args[3]); err != nil {
log.Error().Err(err).Msg("Failed to backup databases!")
}
}
}
case "help":
if len(args) < 2 {
getHelp("meta")
return
}
getHelp(getArgs(args))
case "loadnames":
if len(args) < 2 {
log.Error().Msg("missing argument: path to json file with manufacturer UUIDs")
println()
}
projVars.GlobalConfig.ManuFile = args[1]
eros.ManufLoad()
case "adapter":
if len(args) > 1 {
switch args[1] {
case "list":
deimos.PrintBlueDevices()
case "sniff":
var (
err error
devint int
)
if len(args) < 2 {
log.Error().Msg("not enough parameters, missing adapter ID")
println()
return
}
if devint, err = strconv.Atoi(args[2]); err != nil {
log.Error().Msg("invalid parameter, must be integer of adapter ID")
println()
return
}
deimos.Sniff(devint)
default:
log.Error().Msg("unknown sub-command: " + args[1])
println()
}
} else {
getHelp(getArgs(args))
}
case "scan":
if len(args) > 1 {
switch args[1] {
case "list":
fallthrough
case "status":
fmt.Println(getArgs(args) + ": start new default BLE scan")
case "start":
if len(args) > 2 {
switch args[2] {
case "tracking":
*projVars.GlobalConfig.CooleanFlags.Tracking = true
*projVars.GlobalConfig.CooleanFlags.Attack = false
case "attack":
*projVars.GlobalConfig.CooleanFlags.Tracking = false
*projVars.GlobalConfig.CooleanFlags.Attack = true
default:
// getHelp(getArgs(args))
log.Error().Msg("unknown sub command: " + args[2])
println()
}
}
bleScan()
}
} else {
getHelp(getArgs(args))
}
case "rpc":
if len(args) > 1 {
switch args[1] {
case "status":
fmt.Println(getArgs(args) + ": ")
case "server":
fmt.Println(getArgs(args) + ": ")
case "client":
fmt.Println(getArgs(args) + ": ")
}
} else {
getHelp(getArgs(args))
}
/*
case "wrath":
if len(args) < 2 {
getHelp("wrath")
return
}
wrath(args[1])
*/
case "clear":
print("\033[H\033[2J")
// termenv.ClearScreen()
default:
log.Error().Msg("unknown command: " + cmd)
println()
}
}
func getHelp(target string) {
fmt.Println("pRaNkeD! (help not available just yet.)")
fmt.Println()
return
/*
var lines []string
lines = append(lines, "help: "+target)
switch target {
case "meta":
var list string
for _, cmd := range cmds {
list = list + cmd + ", "
}
fmt.Println("Enabled commands: ")
list = strings.TrimSuffix(list, ", ")
fmt.Println(list)
fmt.Println()
default:
log.Error().Msg("Help entry not found!")
fmt.Println()
}
*/
}
func StartCLI() {
var hist []string
p := cli.New(
executor,
completer,
cli.OptionPrefix("ProtoMolecule"+"> "),
// cli.OptionPrefixBackgroundColor(cli.Black),
cli.OptionPrefixTextColor(cli.Cyan),
cli.OptionHistory(hist),
cli.OptionSuggestionBGColor(cli.Black),
cli.OptionSuggestionTextColor(cli.White),
cli.OptionSelectedSuggestionBGColor(cli.Black),
cli.OptionSelectedSuggestionTextColor(cli.Cyan),
// prompt.OptionLivePrefix
cli.OptionTitle("ProtoMolecule"),
)
p.Run()
}

41
go.mod
View File

@ -1,16 +1,37 @@
module protomolecule
go 1.16
go 1.19
require (
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 // indirect
git.tcp.direct/Mirrors/go-prompt v0.3.0
git.tcp.direct/kayos/prototooth v0.5.1
github.com/google/gopacket v1.1.19
github.com/json-iterator/go v1.1.12
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/prologic/bitcask v0.3.10
github.com/rs/zerolog v1.21.0
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
github.com/rs/zerolog v1.27.0
tinygo.org/x/bluetooth v0.5.0
)
require (
github.com/JuulLabs-OSS/cbgo v0.0.2 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-tty v0.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/term v1.1.0 // indirect
github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
)

104
go.sum
View File

@ -11,8 +11,10 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af h1:+J2MfTQvW1DmX1HYIQUsrCd5l0Il9JMYTOowIs8ju1Y=
git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af/go.mod h1:kk4oyPgWq6Rijn30Js4ITQC5DFwmpyzWL3+8V6q9wdM=
git.tcp.direct/Mirrors/go-prompt v0.3.0 h1:4IXTCPeuMfoemcJ+riSuKQhAx1rJo5hTtuSkr/IFq+A=
git.tcp.direct/Mirrors/go-prompt v0.3.0/go.mod h1:x8Gs5SGQbFzTglOjiK16geOcdw1dVZas3HYkfx0o6ls=
git.tcp.direct/kayos/prototooth v0.5.1 h1:j/WOekGSZLGCt1gqLFAedWEooprTyxYEIyQKei4kcew=
git.tcp.direct/kayos/prototooth v0.5.1/go.mod h1:sRAZ69v83VhnR037/DylbPPBwKb5UCoqEurDFNum0fM=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/JuulLabs-OSS/cbgo v0.0.2 h1:gCDyT0+EPuI8GOFyvAksFcVD2vF4CXBAVwT6uVnD9oo=
@ -27,6 +29,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bgould/http v0.0.0-20190627042742-d268792bdee7/go.mod h1:BTqvVegvwifopl4KTEDth6Zezs9eR+lCWhvGKvkxJHE=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@ -36,6 +39,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -56,12 +60,13 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -77,6 +82,9 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -113,23 +121,38 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@ -140,11 +163,15 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/muka/go-bluetooth v0.0.0-20200619025933-f6113f7141c5/go.mod h1:yV39+EVOWdnoTe75NyKdo9iuyI3Slyh4t7eQvElUbWE=
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 h1:p3srutpE8TpQmOUQ5Qw94jYFUdoG2jBbILeYLroQNoI=
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c h1:CTU9zYG49RMMVTZwRcC78uBJ5gGmvLSgQXCDn1n4jJY=
github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@ -156,6 +183,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/plar/go-adaptive-radix-tree v1.0.4 h1:Ucd8R6RH2E7RW8ZtDKrsWyOD3paG2qqJO0I20WQ8oWQ=
github.com/plar/go-adaptive-radix-tree v1.0.4/go.mod h1:Ot8d28EII3i7Lv4PSvBlF8ejiD/CtRYDuPsySJbSaK8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -172,11 +201,13 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM=
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@ -185,8 +216,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@ -208,7 +239,6 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -219,6 +249,7 @@ github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0
github.com/tidwall/redcon v1.4.0/go.mod h1:IGzxyoKE3Ea5AWIXo/ZHP+hzY8sWXaMKr7KlFgcWSZU=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -235,6 +266,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -251,6 +284,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@ -274,7 +308,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -284,7 +319,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -292,6 +326,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -301,20 +336,27 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 h1:g9s1Ppvvun/fI+BptTMj909BBIcGrzQ32k9FNlcevOE=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -335,9 +377,9 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -376,14 +418,20 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
tinygo.org/x/bluetooth v0.5.0 h1:UftQTmx/snuTbeoS/R6+ZixmxSl5d6BvyfxlmD8eDng=
tinygo.org/x/bluetooth v0.5.0/go.mod h1:3rm7IKtmhP7aU2XRJI/Ods3J9Lqc3BAPPTNZmTtb42Q=
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.20.0/go.mod h1:uJD/l1qWzxzLx+vcxaW0eY464N5RAgFi1zTVzASFdqI=
tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM=
tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20=
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=

76
main.go
View File

@ -4,19 +4,22 @@ import (
"flag"
"os"
"os/signal"
"syscall"
"time"
projVars "protomolecule/src/config"
"protomolecule/src/dust"
"protomolecule/src/eros"
"protomolecule/src/protogen"
projVars "protomolecule/src/vars"
"syscall"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
var (
manufLoad bool
manufLoad bool
GitVersion string
BuildDate string
)
func loginit() {
@ -48,56 +51,57 @@ func loginit() {
func cliFlags() {
flag.Parse()
if *projVars.AFlag {
projVars.AttackMode = true
}
if *projVars.DFlag {
if *projVars.GlobalConfig.CooleanFlags.Debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
if *projVars.TFlag {
projVars.TrackingMode = true
}
if *projVars.MFlag != "0" {
projVars.ManuFile = *projVars.MFlag
manufLoad = true
}
manufLoad = *projVars.GlobalConfig.StringFlags.MACVendorFile != ""
}
func sigHandler() {
c := make(chan os.Signal)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
log.Warn().Msg("Interrupt detected, shutting down gracefully...")
eros.Slumber()
os.Exit(0)
}()
for {
select {
case <-c:
log.Warn().
Msg("Interrupt detected, stopping scan...")
for _, scan := range protogen.ScanMgr.Scans {
for _, dev := range scan.Device {
if dev.Connected {
_ = dev.Conn.Disconnect()
}
}
_ = scan.Stop()
}
}
}
}
func init() {
// Initializing an instance of our scan manager to keep track of concurrent scans
// NOTE: Devices are kept track of per Scan via a nested map of eros.Device instances
//
// TODO: Get all of this management stuff into its own package (structs and maps and initialization of the former)
// TODO: Name these structs and maps and instances more uniformly and idiomatically
dust.PrintBanner()
protogen.ScanMgr = &protogen.Meta{
Count: 0,
Scans: make(map[int]*protogen.Scan),
Mailbox: make(chan protogen.Postcard),
}
loginit()
cliFlags()
sigHandler()
go sigHandler()
log.Debug().Msg("Logging initialized")
if len(GitVersion) > 0 {
log.Info().
Str("Version", GitVersion).
Str("Built", BuildDate).
Msg("Initializing protomolecule")
}
// see ./src/eros
log.Debug().Msg("Initializing database engine")
@ -126,10 +130,9 @@ func earToTheWire() {
}
}
for {
select {
case postcard := <- protogen.ScanMgr.Mailbox:
case postcard := <-protogen.ScanMgr.Mailbox:
sublog = log.With().Int("scan_id", postcard.From).Logger()
interpret(postcard)
}
@ -137,8 +140,7 @@ func earToTheWire() {
}
}
func main() {
defer eros.Slumber()
func bleScan() {
var scan *protogen.Scan
// Note: the tinygo bluetooth (prototooth here) library does already have a channel system for starting and stopping scans
@ -149,7 +151,11 @@ func main() {
scan = protogen.ScanMgr.NewScan()
//time.Sleep(30 * time.Millisecond)
// time.Sleep(30 * time.Millisecond)
go dust.Must("Scan", scan.Start())
}
func main() {
defer eros.Slumber()
StartCLI()
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,54 @@
// arboghast is a package focused on fuzzing BLE devices
package arboghast
import (
"sync"
bluetooth "git.tcp.direct/kayos/prototooth"
projVars "protomolecule/src/config"
)
type Circus struct {
Trick map[int]*Fuzzy
uuid_pool []bluetooth.UUID
mu *sync.Mutex
}
type Fuzzy struct {
config *bluetooth.AdvertisementOptions
ad *bluetooth.Advertisement
mu *sync.Mutex
}
var circus *Circus
func Awaken() {
circus = &Circus{
Trick: make(map[int]*Fuzzy),
uuid_pool: []bluetooth.UUID{},
mu: &sync.Mutex{},
}
}
func NewEntropicFuzzer() *Fuzzy {
options := &bluetooth.AdvertisementOptions{
LocalName: RandomAlpha(16),
// Interval:
}
mutex := &sync.Mutex{}
ad := projVars.GlobalConfig.GetScanAdapter().DefaultAdvertisement()
ad.Configure(*options)
return &Fuzzy{
config: options,
ad: ad,
mu: mutex,
}
}
func (f *Fuzzy) StartAd() {
f.ad.Start()
}

34
src/arboghast/entropy.go Normal file
View File

@ -0,0 +1,34 @@
package arboghast
import (
"math/rand"
"time"
"unsafe"
)
var src = rand.NewSource(time.Now().UnixNano())
const (
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
func RandomAlpha(n int) string {
b := make([]byte, n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return *(*string)(unsafe.Pointer(&b))
}

View File

@ -2,19 +2,15 @@ package blueStuff
import "git.tcp.direct/kayos/prototooth"
//controls connections to found devices to get service characteristics
//TODO: disable the scan adapter, enable the attack adapter (this step pmight not be needed)
// controls connections to found devices to get service characteristics
// TODO: disable the scan adapter, enable the attack adapter (this step pmight not be needed)
// use the result.LocalName passed from scanStuff to start connection
// once connected, for list of service characteristics and check for read / write for each
// loog all of this to eros
func pathways(target bluetooth.ScanResult) {
println("Discovery")
//device, err := projVars.ScanAdapter.Connect(bluetooth.ScanResult.Address, bluetooth.ConnectionParams{})
//srvcs, err := projVars.ScanAdapter.
// device, err := projVars.GlobalConfig.GetScanAdapter().Connect(bluetooth.ScanResult.Address, bluetooth.ConnectionParams{})
// srvcs, err := projVars.GlobalConfig.GetScanAdapter().
}

99
src/config/config.go Normal file
View File

@ -0,0 +1,99 @@
package common
import (
"flag"
bluetooth "git.tcp.direct/kayos/prototooth"
)
type Mode uint32
const (
ModeNone Mode = iota
ModeScan
ModeTrack
ModeAttack
)
func (m Mode) String() string {
return [...]string{"None", "Track", "Attack"}[m]
}
// Tooth is a bluetooth adapter.
type Tooth struct {
ID int
Usecase Mode
*bluetooth.Adapter
}
type Config struct {
// ManuFile is a place holder for a file with list of all known Manufacturers
// this is actually stored by eros and likely deprecated.
ManuFile string
Teeth []*Tooth
CooleanFlags struct {
Debug *bool
Attack *bool
Tracking *bool
}
StringFlags struct {
MACVendorFile *string
MACTarget *string
}
}
func (c *Config) GetScanAdapter() *bluetooth.Adapter {
if len(c.Teeth) == 1 {
return c.Teeth[0].Adapter
}
var choice *bluetooth.Adapter
for _, v := range c.Teeth {
if v.Usecase == ModeScan || v.Usecase == ModeTrack {
choice = v.Adapter
break
}
}
return choice
}
var DefaultConfig = Config{
ManuFile: DefManuFile,
Teeth: []*Tooth{
&Tooth{
ID: 0,
Usecase: ModeNone,
Adapter: bluetooth.DefaultAdapter,
},
},
CooleanFlags: struct {
Debug *bool
Attack *bool
Tracking *bool
}{
Debug: flag.Bool("d", false, "global debug logging and pretty printing"),
Attack: flag.Bool("a", false, "attack mode"),
Tracking: flag.Bool("t", false, "device tracking mode"),
},
StringFlags: struct {
MACVendorFile *string
MACTarget *string
}{
MACVendorFile: flag.String("m", DefManuFile, "json file with manufacturer identifying data to preload into eros"),
MACTarget: flag.String("w", "00:00:00:00:00:00", "MAC address of target"),
},
}
const DefManuFile = "./ManufUUID.json"
// Service UUIDs for testing
var (
SonosScanTest = bluetooth.New16BitUUID(0xfe07)
AppleScanTest = bluetooth.New16BitUUID(0x004c)
GlobalConfig *Config
)
func init() {
GlobalConfig = &DefaultConfig
}

34
src/cortazar/cortazar.go Normal file
View File

@ -0,0 +1,34 @@
package cortazar
//Intended to be used as the target analysis package
//for example
/*
1. attempt bonding (LTK exchange) with target, while in aggressive attack mode
2. store current LTK associated with target to device in eros
3. disconnect and forget target
4. recconect to target, pair, bond, store LTK, disconnect, forget -- repeatTK
5. compare LTKs for entropy
** could also be used for link key which is the pin established during pairing
*/
//---------
/*
device metrics
- location and device type/manufacturer/etc...
- when and where a device is seen over time
*/
//-----------
/*
*/

77
src/deimos/main.go Normal file
View File

@ -0,0 +1,77 @@
package deimos
import (
"errors"
"fmt"
"github.com/google/gopacket/dumpcommand"
"github.com/google/gopacket/pcap"
"github.com/rs/zerolog/log"
"strconv"
"strings"
)
type DevMap map[int]pcap.Interface
var Devices DevMap
var Interface *pcap.Handle
func init() {
Devices = make(map[int]pcap.Interface)
}
func getInterfaces() []pcap.Interface {
devices, err := pcap.FindAllDevs()
if err != nil {
log.Error().Err(err).Msg("failed to get network interfaces")
return nil
}
return devices
}
func getBlueDevices() []pcap.Interface {
var blues []pcap.Interface
devices := getInterfaces()
for n, device := range devices {
if strings.Contains(strings.ToLower(device.Name), "bluetooth") {
Devices[n] = device
blues = append(blues, device)
}
if strings.Contains(strings.ToLower(device.Name), "hci") {
Devices[n] = device
blues = append(blues, device)
}
}
return blues
}
func PrintBlueDevices() {
getBlueDevices()
for n := range Devices {
devid := strconv.Itoa(n)
fmt.Println("[" + devid + "] " + Devices[n].Name)
}
}
func Sniff(dev int) error {
var (
err error
d pcap.Interface
preInterface *pcap.InactiveHandle
ok bool
)
if d, ok = Devices[dev]; !ok {
return errors.New("adapter ID does not exist")
}
if preInterface, err = pcap.NewInactiveHandle(d.Name); err != nil {
return err
}
defer preInterface.CleanUp()
if err = preInterface.SetPromisc(true); err != nil {
return err
}
if Interface, err = preInterface.Activate(); err != nil {
return err
}
go dumpcommand.Run(Interface)
return nil
}

View File

@ -9,7 +9,12 @@ import (
func Must(action string, err error) {
if err != nil {
log.Fatal().Err(err).Str("action", action).Msg("FATAL_ERROR")
switch err.Error() {
case "AdapterExists: Launch helper exited with unknown return code 1":
log.Error().Msg("Is your bluetooth adapter enabled? Linux: is bluetoothd started?")
default:
log.Fatal().Err(err).Str("action", action).Msg("FATAL_ERROR")
}
}
}

View File

@ -1,5 +1,3 @@
package eros
// Eros controls the Bitcask db that holds the devices captured during scanning
//
// Addr (Key)
@ -7,19 +5,22 @@ package eros
// Raw Advertisement Packet (Advertisement)
// Services UUIDs (Services)
// TODO:
// Output to report
// TODO:
//
// Output to report
package eros
import (
"bufio"
"encoding/json"
"os"
"strconv"
"strings"
"sync"
"time"
projVars "protomolecule/src/vars"
jsoniter "github.com/json-iterator/go"
projVars "protomolecule/src/config"
bluetooth "git.tcp.direct/kayos/prototooth"
"github.com/prologic/bitcask"
@ -27,23 +28,27 @@ import (
)
var (
// deviceDb will hold details about devices discovered
deviceDb *bitcask.Bitcask
// attackDb will hold details about exploits to be used against BLE devices
attackDb *bitcask.Bitcask
// serviceDb will hold definitions of various bluetook services and will ultimately be updated via an HTTP repository
serviceDb *bitcask.Bitcask
json = jsoniter.ConfigCompatibleWithStandardLibrary
dbs = []string{
"devices", // details about devices discovered
"exploits", // details about exploits to be used against BLE devices
"services", // definitions of various bluetooth services and will ultimately be updated via an HTTP repository
"manufacturers", // manufacturer to UUID correlations and info
}
err error
Manufacturers ManufData
// Exploits Exploit
// DataDir - should be defined by config or cmd flag
DataDir string = "./.eros-data/"
)
var DB map[string]*bitcask.Bitcask
// Ingest UUID will add the UUID to the manufacturer if it doesn't already exist
func (manuf *Manufacturer) IngestUUID(uuid bluetooth.UUID) bool {
contains := func(s []bluetooth.UUID, v bluetooth.UUID) bool {
for _, a := range s {
if a == v {
@ -60,10 +65,24 @@ func (manuf *Manufacturer) IngestUUID(uuid bluetooth.UUID) bool {
manuf.UUIDs = append(manuf.UUIDs, uuid)
return true
}
func FinalizeDevice(bigidea Device) *Device {
bigidea.mu = &sync.RWMutex{}
return &bigidea
}
func (d *Device) ConnectHandler(target bluetooth.Addresser, c bool) {
d.mu.Lock()
defer d.mu.Unlock()
if c {
d.Connected = true
} else {
d.Connected = false
}
}
// ManufLoad loads data from a json file containing UUID manufacturer associations
func ManufLoad() {
path := projVars.ManuFile
path := *projVars.GlobalConfig.StringFlags.MACVendorFile
var uuid bluetooth.UUID
log.Info().
@ -72,8 +91,8 @@ func ManufLoad() {
f, err := os.Open(path)
if err != nil {
log.Debug().Msg(err.Error())
os.Exit(1)
log.Error().Err(err).
Msg("Failed to open JSON file")
}
defer f.Close()
@ -88,7 +107,7 @@ func ManufLoad() {
utmp, err := strconv.ParseUint(mf.UString, 0, 16)
if err != nil {
log.Fatal().Str("file", projVars.ManuFile).
log.Fatal().Str("file", path).
Str("string", mf.UString).
Err(err).Msg("MANUFACTURER_PARSE_ERROR")
}
@ -99,8 +118,8 @@ func ManufLoad() {
log.Debug().
Str("Manufacturer", mf.Name).
Str("UUID_String", mf.UString).
//Interface("UUID_Type", uuid).
//Str("Website", mf.Website).
// Interface("UUID_Type", uuid).
// Str("Website", mf.Website).
Msg("LOADED_MANUFACTURER_DATA")
mf.UString = ""
@ -123,7 +142,7 @@ func ManufLoad() {
log.Debug().Str("Manufacturer", mf.Name).
Int("UUID_Count", len(mf.UUIDs)).
//Interface("UUIDs", mf.UUIDs).
// Interface("UUIDs", mf.UUIDs).
Msg("EXISTING_MANUFACTURER_FOUND")
}
@ -132,52 +151,64 @@ func ManufLoad() {
Manufacturers.Entries = append(Manufacturers.Entries, *mf)
}
}
for _, manuf := range Manufacturers.Entries {
var jsonData []byte
jsonData, err = json.Marshal(manuf)
if err != nil {
log.Fatal().Err(err).
Msg("EROS_FATAL_MANUFACTURER_JSON_MARSHAL")
}
err := DB["manufacturers"].Put([]byte(manuf.Name), jsonData)
if err != nil {
log.Fatal().Err(err).
Msg("EROS_FATAL_MANUFACTURER_JSON_STORE")
}
log.Debug().Str("Name", manuf.Name).
Msg("EROS_MANUFACTURER_STORE")
}
}
// Awaken - create the data directory if it does not exist; initialize bitcask in this directory
func Awaken() {
//log.Debug().Str("DataDir",DataDir).Msg("Initializing eros...")
deviceDb, err = bitcask.Open(DataDir + "devices")
if err != nil {
panic(err.Error)
DB = make(map[string]*bitcask.Bitcask)
for _, name := range dbs {
DB[name], err = bitcask.Open(DataDir+name, bitcask.WithMaxValueSize(1024*1024*1024))
if err != nil {
panic(err.Error())
}
}
}
attackDb, err = bitcask.Open(DataDir + "exploits")
func logErr(err error) {
if err != nil {
panic(err.Error)
}
serviceDb, err = bitcask.Open(DataDir + "services")
if err != nil {
panic(err.Error)
log.Error().Err(err).
Msg("EROS_DATABASE_ERROR")
}
}
// Slumber - Clean up database entries, sync them to persistent storage, and safelty close the database.
func Slumber() {
rest := func(db *bitcask.Bitcask) {
db.Merge()
db.Sync()
db.Close()
for _, db := range DB {
logErr(db.Merge())
logErr(db.Sync())
logErr(db.Close())
}
rest(deviceDb)
rest(attackDb)
rest(serviceDb)
}
// Exists - check if a device is present in the Database
func Exists(Addr string) bool {
if deviceDb.Has([]byte(Addr)) {
if DB["devices"].Has([]byte(Addr)) {
return true
}
return false
}
// Remember - store device details into the database
func Remember(dev Device) error {
// Remember stores device details into the database via an argument
func Remember(dev *Device) error {
var err error
var rhist map[time.Time]int16
@ -200,7 +231,7 @@ func Remember(dev Device) error {
return err
}
err = deviceDb.Put([]byte(dev.Addr), jsonData)
err = DB["devices"].Put([]byte(dev.Addr), jsonData)
return err
}
@ -210,28 +241,148 @@ func Recall(Addr string) (Device, error) {
var bytes []byte
var member Device
bytes, err = deviceDb.Get([]byte(Addr))
bytes, err = DB["devices"].Get([]byte(Addr))
if err != nil {
member = Device{}
return member, err
}
json.Unmarshal(bytes, &member)
if err := json.Unmarshal(bytes, &member); err != nil {
log.Panic().Err(err).Msg("Failed to unmarshal device")
}
return member, err
}
func Backup(path string) error {
for _, db := range DB {
logErr(db.Merge())
logErr(db.Sync())
err := db.Backup(path)
if err != nil {
return err
}
}
return nil
}
/*
// Hypnosis - retrieve new exploits/attacks from a remote http repository
func Hypnosis(repo string) {
// placeholder
e:= echo.New()
// CORS
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE} //TODO: possibly trim the methods
}))
// GET
e.GET("/exploits", func(c echo.Context) error { // This will definitely need to be updated
// Build request
req, err := http.NewRequest("GET", repo, nil)
if err != nil {
fmt.Println("Error in GET request: ", err)
}
// Certificate sanity checks
caCert, err := os.Readfile("server.crt")
if err != nil {
log.Fatal(err)
}
cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
log.Fatal(err)
}
// Add certificates
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Create client
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
},
},
}
// Send request
res, err := client.Do(req)
if err != nil {
fmt.Println("Client Error: ", err)
}
// Defer body close
defer res.Body.Close()
// Late binding data from JSON
var exp Exploit
// Decode JSON stream
If err := json.NewDecoder(res.Body).Decode(&exp); err != nil {
fmt.Println(err)
}
return c.JSON(http.StatusOK, exp)
})
}
// Trauma - store details of an exploit/attack against BLE devices
func Trauma(name string, targ string, cat string, vec Vector, pay Payload) {
// placeholder
func Trauma(exp *Exploit) error {
var err error
var rhist map[time.Time]int16
if !Known(exp.Addr) {
exp.Discovered = time.Now()
rhist = make(map[time.Time]int16)
} else {
re, _ := Flashback(exp.Addr)
exp.Discovered = re.Discovered
rhist = re.RSSIhist
}
rhist[time.Now()] = exp.RSSIlast
exp.RSSIhist = rhist
exp.Seen = time.Now()
var jsonData []byte
jsonData, err = json.Marshal(exp)
if err != nil {
return err
}
err = DB["exploits"].Put([]byte(exp.Addr), jsonData)
return err
}
func FinalizeExploit(bigidea Exploit) *Exploit {
bigidea.mu = &sync.RWMutex{}
return &bigidea
}
*/
// Known - check if an exploit is present in the database
func Known(Addr string) bool {
return DB["exploits"].Has([]byte(Addr))
}
// Flashback - retrieve details for the named exploit/attack
func Flashback(name string) {
//placeholder
func Flashback(Addr string) (Exploit, error) {
var err error
var bytes []byte
var member Exploit
bytes, err = DB["exploits"].Get([]byte(Addr))
if err != nil {
member = Exploit{}
return member, err
}
if err := json.Unmarshal(bytes, &member); err != nil {
log.Panic().Err(err).Msg("Failed to unmarshal exploit")
}
return member, err
}

View File

@ -1,13 +1,15 @@
package eros
import (
"git.tcp.direct/kayos/prototooth"
bluetooth "git.tcp.direct/kayos/prototooth"
"sync"
"time"
)
type Permissions struct {
Read string
Write string
Read string
Write string
Notify string
}
type Characteristic struct {
@ -25,7 +27,6 @@ type Service struct {
Characteristic []Characteristic
}
type ManufData struct {
Entries []Manufacturer
}
@ -45,7 +46,7 @@ type Manufacturer struct {
// Exploit - BLE service exploit details to be marshalled into json before stored in bitcask
type Exploit struct {
Name string
Target string
Target string // Should prabably be a struct of some sort since exploits target service chars
Category string
Vector Vector
Payload Payload
@ -63,11 +64,14 @@ type Payload struct {
// Device will hold details about the discoverd device
type Device struct {
Name string
Addr string
Manufacturer string
RSSIlast int16
RSSIhist map[time.Time]int16
Name string // local name of the device
Addr string // Broadcast MAC
Manufacturer string // Manufacturer Data if broadcast
RSSIlast int16 // Most Current RSSI
RSSIhist map[time.Time]int16 // Last RSSI readings
Alias string // Alias given to device
Trusted bool // Is is in the trusted devices
WakeAllowed bool // Does the device allow wake
// Services - see Service struct
Services []Service
@ -75,4 +79,10 @@ type Device struct {
Discovered time.Time
// Seen - timestamp from when the device was last seen
Seen time.Time
Connected bool
Conn *bluetooth.Device
// The most at-risk type we have so far for concurrency, needs to be mutexed
mu *sync.RWMutex
}

View File

@ -1,37 +1,37 @@
package protogen
import (
projVars "protomolecule/src/vars"
"sync"
"time"
projVars "protomolecule/src/config"
"protomolecule/src/eros"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
bluetooth "git.tcp.direct/kayos/prototooth"
"protomolecule/src/eros"
"time"
bluetooth "git.tcp.direct/kayos/prototooth"
)
// ScanMgr will keep track of concurrently running scans
var ScanMgr *Meta
// NewScan - here we are creating an "anonymous" instance of a Scan struct
// You'll notice it doesn't contain most of the data that actually is supposed to live within that struct
//
// This works because the integer ID is being used as a key that will have a global scope
//
// See: Remember function as it is defined in eros/eros.go
// Remember usage in this file (scanStuff/scanStuff.go
//
// In these examples we are sending an instance of a struct with some data to eros; allowing it to finish filling out the rest
// This can be done with just structs, but becomes problematic when trying to refer to them later
//
// ref: https://gobyexample.com/mutexes
// ref: https://golang.org/pkg/sync/#Mutex
// ref: https://www.geeksforgeeks.org/mutex-in-golang-with-examples/
func (m *Meta) NewScan() *Scan {
// Here we are creating an "anonymous" instance of a Scan struct
// You'll notice it doesn't contain most of the data that actually is supposed to live within that struct
// This works because the integer ID is being used as a key that will have a global scope
//
// See: Remember function as it is defined in eros/eros.go
// Remember usage in this file (scanStuff/scanStuff.go
//
// In these examples we are sending an instance of a struct with some data to eros; allowing it to finish filling out the rest
// This can be done with just structs, but becomes problematic when trying to refer to them later
//
//TODO: implement Mutex locking from sync in most of these structs to prevent concurrent read/write operations from causing a race w̶a̶r̶ condition
// ref: https://gobyexample.com/mutexes
// ref: https://golang.org/pkg/sync/#Mutex
// ref: https://www.geeksforgeeks.org/mutex-in-golang-with-examples/
newid := len(m.Scans)
m.Scans[newid] = &Scan{
@ -40,23 +40,22 @@ func (m *Meta) NewScan() *Scan {
}
scan := m.Scans[newid]
scan.Devices = make(map[int]*eros.Device)
m.Count = len(m.Scans)
scan.Device = make(map[int]*eros.Device)
scan.mu = &sync.RWMutex{}
return scan
}
func (s *Scan) NewDevice(name string, addr string, manuf string, rssi int16) *eros.Device {
newid := len(s.Devices)
s.Devices[newid] = &eros.Device{
s.mu.Lock()
defer s.mu.Unlock()
draft := eros.Device{
Name: name,
Addr: addr,
Addr: addr,
Manufacturer: manuf,
RSSIlast: rssi,
}
s.Count = len(s.Devices)
return s.Devices[newid]
return eros.FinalizeDevice(draft)
}
/*
@ -93,27 +92,22 @@ func ManfCheck(TargetAdvertData bluetooth.AdvertisementPayload) string {
func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.ScanResult) {
var sublog zerolog.Logger
projVars.ScanAdapter.SetConnectHandler(func(Result bluetooth.Addresser, connected bool) {
// It seems that because this is a callback that the library calls itself that it is passing us "connected" as an argument
// therefore I think what we're supposed to do is store that boolean so we can then reference it later
projVars.ConnectedToTarget = connected
})
payload := result.AdvertisementPayload
addr := result.Address.String()
lname := result.LocalName()
//adbytes := payload.Bytes()
// adbytes := payload.Bytes()
rssi := result.RSSI
EnumedManuf := ""
// TODO: probably make this a function or a method in eros(?)
//
//---attempts to set the manufacturer value----
//range through the uuids in the payload and compare
//known manufacturers list
// ---attempts to set the manufacturer value----
// range through the uuids in the payload and compare
// known manufacturers list
uuids := payload.ServiceUUIDOut()
for range uuids {
//for every element within the manufacturers list
// for every element within the manufacturers list
// check each UUID
for _, man := range eros.Manufacturers.Entries {
// pull the UUID the current element of the manufacturer list
@ -121,7 +115,7 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
// for each manufacturer's UUID: compare the advertisment payload for a match
for _, manusss := range currManufErosOut {
manufBool := payload.HasServiceUUID(manusss)
//if there is a UUID match then assign the Manufacturer's name
// if there is a UUID match then assign the Manufacturer's name
// to the output variable EnumedManuf
if manufBool == true {
EnumedManuf = man.Name
@ -132,11 +126,13 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
}
//ManufOut := ManfCheck(payload)
// ManufOut := ManfCheck(payload)
layToRest := func(dev *eros.Device) {
sublog.Debug().Msg("Storing data with Eros")
eros.Remember(*dev)
if err := eros.Remember(dev); err != nil {
log.Warn().Err(err).Msg("EROS_REMEMBER_FAILURE")
}
// simple eros test
fromEros, err := eros.Recall(addr)
@ -147,13 +143,13 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
log.Info().
Str("Name", fromEros.Name).
Str("Addr", fromEros.Addr).
Str("ManuF", EnumedManuf). //needs to be changed back to fromEros.Manufacturer
Str("ManuF", fromEros.Manufacturer). // needs to be changed back to fromEros.Manufacturer
Int16("Current_RSSI", fromEros.RSSIlast).
Int("Service_Count", len(fromEros.Services)).
Msg("EROS_RECALL")
}
//Services level logging
// Service enumeration and storage
// TODO:
// Fix Logging output here -- Prob shouldnt output this much info
// for each service discovered
@ -164,8 +160,8 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
Int16("RSSI", rssi).Logger()
// Skipping duplicate results unless tracking mode enabled (to store RSSI as devices move)
if projVars.TrackingMode == false {
for _, dev := range s.Devices {
if !*projVars.GlobalConfig.CooleanFlags.Tracking {
for _, dev := range s.Device {
if addr == dev.Addr {
return
}
@ -176,6 +172,8 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
s.Activity = time.Now()
dev := s.NewDevice(lname, addr, EnumedManuf, rssi)
projVars.GlobalConfig.GetScanAdapter().SetConnectHandler(dev.ConnectHandler)
// Record all the services advertised, append them into the nested struct within Device
for _, uuid := range uuids {
svc := &eros.Service{
@ -183,89 +181,60 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
}
dev.Services = append(dev.Services, *svc)
sublog.Debug().Str("UUID", svc.UUID).Msg("SERVICE_DISCOVERED")
sublog.Info().Str("UUID", svc.UUID).Msg("SERVICE_DISCOVERED")
}
if !projVars.AttackMode {
if !*projVars.GlobalConfig.CooleanFlags.Attack {
layToRest(dev)
return
}
////////////////////////////////////////////////////////////////////////
//var PreTargetHandling type
//var TargetDeviceService *bluetooth.DeviceService
//var TargetDeviceServiceChar *bluetooth.DeviceCharacteristic
sublog.Info().Str("Adapter", "Attempting Connection").Msg("ADAPTER_STATUS")
var connErr error
var err error
// TODO: re-assess the timeout mechanism
// this is largely going to depend on how concurrent we can get (at least with only one ble adapter)
// TODO: make timeout values and intervals command line arguments instead of hard coding them
timeout := bluetooth.NewDuration(time.Duration(3) * time.Second)
interval := bluetooth.NewDuration(time.Duration(20) * time.Millisecond)
// creates a new timer of d (time.Duration)
// outputs time on {timer_Name}.C chan
// can then be checked against tick (time.Time)
TimerCounts := time.NewTimer(10 * time.Millisecond)
dev.Conn, connErr = projVars.GlobalConfig.GetScanAdapter().
Connect(result.Address, bluetooth.ConnectionParams{ConnectionTimeout: timeout, MinInterval: interval})
var (
conTimeOut time.Duration
//tick <-chan time.Time
//not needed?
//tock <-chan time.Timer
err error
)
TargetDevice, connectError := projVars.ScanAdapter.Connect(result.Address, bluetooth.ConnectionParams{})
if connErr != nil {
sublog.Error().Err(connErr).Msg("CONNECT_ERROR")
layToRest(dev)
return
}
var targetServices []bluetooth.DeviceService
sublog.Info().
Str("status", "Attempting to Read Target Services").
Str("status", "Connected, attempting to Read Target Services").
Msg("ADAPTER_STATUS")
// TODO: this will be running concurrently in a goroutine,
// so rather than set out timeout to be egregiously low we will just let it take its time
conTimeOut = 50 * time.Millisecond
//attempted to fix but probably didnt help anything
if TimerCounts.C == nil {
endTime := time.After(conTimeOut)
select {
case <-endTime:
sublog.Error().Str("Adapter", "Connection Timeout").Msg("ADAPTER_STATUS")
TargetDevice.Disconnect()
endTime = nil
default:
if connectError != nil {
sublog.Error().Err(connectError).Msg("CONNECT_ERROR")
layToRest(dev)
return
}
sublog.Debug().Str("Status", "Connecting...").Msg("ADAPTER_STATUS")
}
}
if !projVars.ConnectedToTarget {
if !dev.Connected {
layToRest(dev)
return
}
ServBuf := make([]byte, 255)
// ServBuf := make([]byte, 255)
Charbuf := make([]byte, 255)
targetServices, err = TargetDevice.DiscoverServices(nil)
targetServices, err = dev.Conn.DiscoverServices(nil)
if err != nil {
sublog.Error().Err(err).Msg("DISCOVER_SERVICE_ERROR")
}
for SerReadPos, srvcs := range targetServices {
// for SerReadPos, srvcs := range targetServices {
for _, srvcs := range targetServices {
charSer := eros.Service{
UUID: srvcs.String(),
}
sublog.Info().Str("Service UUID", charSer.UUID).
Int("Bytes", SerReadPos).
Str("Value", string(ServBuf[:SerReadPos])).
// Int("Bytes", SerReadPos).
// Str("Value", string(ServBuf[:SerReadPos])).
Msg("GATT_SERVICE")
sublog.Debug().Str("status", "Attempting to Retrieve Characteristic List").Msg("ADAPTER_STATUS")
@ -275,51 +244,62 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc
for _, char := range chars {
ReadPos, _ := char.Read(Charbuf)
// flags := char.Flags
sublog.Info().Str("UUID", char.UUID().String()).
Int("Bytes", ReadPos).Str("Value", string(Charbuf[:ReadPos])).
// Int("Bytes", ReadPos).
Str("Value", string(Charbuf[:ReadPos])).
// Bool("Read", flags.Read()).
// Bool("Write", flags.Write()).
Msg("SERVICE_CHARACTERISTIC")
}
}
// finished with this device
TargetDevice.Disconnect()
_ = dev.Conn.Disconnect()
dev.Connected = false
sublog.Info().Str("Adapter", "Successfully Disconnected From Target").Msg("ADAPTER_STATUS")
projVars.ConnectedToTarget = false
layToRest(dev)
//TODO: stop scan and call bluestuff func and pass it the local name value
// TODO: stop scan and call bluestuff func and pass it the local name value
}
func (s *Scan) Stop() error {
// TODO: fix this adapterId situation
err := projVars.GlobalConfig.GetScanAdapter().StopScan()
if err != nil {
return err
}
return nil
}
func (s *Scan) Start() error {
s.Started = time.Now()
// create list of devices in the Area of Operation
//log.Debug().Msg("Creating Device Map")
// log.Debug().Msg("Creating Device Map")
// Enable BLE interface
log.Debug().Msg("Enabling Adapter")
err := projVars.ScanAdapter.Enable()
err := projVars.GlobalConfig.GetScanAdapter().Enable()
if err != nil {
return err
}
adapterId := projVars.ScanAdapter.ID
adapterId := projVars.GlobalConfig.GetScanAdapter().ID
log.Info().
Str("ID", adapterId).
Bool("MODE_TRACK", projVars.TrackingMode).
Bool("MODE_ATTACK", projVars.AttackMode).
Bool("MODE_TRACK", *projVars.GlobalConfig.CooleanFlags.Tracking).
Bool("MODE_ATTACK", *projVars.GlobalConfig.CooleanFlags.Attack).
Msg("Starting new ProtoMolecule BLE Scan")
err = projVars.ScanAdapter.Scan(s.resultHandler)
err = projVars.GlobalConfig.GetScanAdapter().Scan(s.resultHandler)
if err != nil {
return err
}
return nil
}

View File

@ -1,57 +1,63 @@
package protogen
import (
"time"
bluetooth "git.tcp.direct/kayos/prototooth"
"protomolecule/src/eros"
"sync"
"time"
)
/*
Why the Meta struct? This shit is a fucking maze.
Well in theory we will have multiple types of scans in the future,
if that's the case this is going to become necessary very quickly
Why the Meta struct?
In theory we will have multiple types of scans in the future,
if that's the case this is going to become necessary very quickly
I've mocked up some commented out examples below.
I've mocked up some commented out examples in the source code below.
*/
type Meta struct {
Count int
Scans map[int]*Scan
Scans map[int]*Scan
Mailbox chan Postcard
// // // Future Concepts // // //
// BLEScans map[int]*BLEScan
// LoraScans map[int]*LoraScan
// ZigScans map[int]*ZigScan
// WiFiScans map[int]*WiFiScan
// we definitely need this to be safe for concurrency
mu *sync.RWMutex
}
// Postcard will encapsulate interprocess communication messages that we send back to the main thread
type Postcard struct {
// From - the ScanID the message originated from
From int
// Stamp - the time the IPC message was created
Stamp time.Time
// Device ID - relevant DeviceID (if applicable) - Remember to use Scan.Devices[id] for easy referral
DeviceID int
// Command - the actual IPC command
Command string
// Arguments - augmenting arguments to the command
Arguments []string
}
// Instance of a BLE scan
// TODO: Form profiles on devices
// Scan represents an instance of a BLE scan
type Scan struct {
Count int
// The ID is how we will refer back to running scans during IPC to react or cancel a scan
ID int
Started time.Time
Count int
ID int
// Started the scan at this time
Started time.Time
// Activity was last seen at this time
Activity time.Time
Devices map[int]*eros.Device
// Device represents a bluetooth endpoints
Device map[int]*eros.Device
// Connection is an active connection to a bluetooth endpoint
Connection map[int]*bluetooth.Connection
/* Ignore is a map of devices to disregard during a scan,
by using the hardware address as a key. (needs disclaimer?) */
Ignore map[string]bool
// Gonna plan on mutexing scan operations just to be safe
mu *sync.RWMutex
}

View File

@ -1,61 +0,0 @@
package projVars
import (
"flag"
bluetooth "git.tcp.direct/kayos/prototooth"
"github.com/rs/zerolog"
)
//The initial list of device in the area
var ScanList map[string]string
var InitResults []string
// Place holder for
// File with list of all known Manufacturers
// is probably unneeded*****
var ManuFile = "./ManufUUID.json"
//var to hold service UUIDs
var SrvcUUID bluetooth.UUID
var AdapterInUse = *&bluetooth.Adapter{}
var AttackMode bool = false
var TrackingMode bool = false
var ConnectedToTarget bool = false
//var SrvcUUIDList map[uint32]string
//hold the values for the initial ble scan results..
// ... i.e. the mac and broadcast name string
var C = make(chan bluetooth.ScanResult)
//the BLE adapter --duh
//var Adapter = bluetooth.DefaultAdapter
var ScanAdapter = bluetooth.DefaultAdapter
var AttackAdapter = bluetooth.DefaultAdapter
//Device to be targeted --not fully implemented
//var Target = flag.String("t", "00:00:00:00:00:00", "Target device to attack")
var DFlag = flag.Bool("d", false, "global debug logging and pretty printing")
var AFlag = flag.Bool("a", false, "attack mode")
var TFlag = flag.Bool("t", false, "device tracking mode")
var MFlag = flag.String("m", "0", "json file with manufacturer identifying data to preload into eros")
//flag.Parse()
//var attacker bluetooth.Addresser
//var connected bool
//var disconnected bool = true
var log *zerolog.Logger
//Service UUIDs for testing
var SonosScanTest = bluetooth.New16BitUUID(0xfe07)
var AppleScanTest = bluetooth.New16BitUUID(0x004c)
//var ServiceUUID16Out

161
src/wrath/wrath.go Normal file
View File

@ -0,0 +1,161 @@
package wrath
import (
bluetooth "git.tcp.direct/kayos/prototooth"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"tinygo.org/x/bluetooth/rawterm"
projVars "protomolecule/src/config"
)
// used for offensive operations
/*
func targetPicture() bluetooth.MAC {
type targetMac bluetooth.MAC
for c, err := range projVars.WAFlag {
append(targetMac{})
}
println(targetMac)
target, err := bluetooth.ParseMAC(targetMac)
if err != nil {
log.Err(err).Msg("Error")
}
a := bluetooth.Address{
MACAddress: target,
}
return target
}
*/
func Start(targetUUID bluetooth.UUID) {
var sublog zerolog.Logger
// bluetooth.DefaultAdapter.Connect(targetPicture(), bluetooth.ConnectionParams{})
// TargetDevice, connectError := projVars.GlobalConfig.GetScanAdapter().Connect(result.Address, bluetooth.ConnectionParams{})
// Enable BLE interface.
err := projVars.GlobalConfig.GetScanAdapter().Enable()
if err != nil {
log.Error().
Err(err).
Msg("could not enable the BLE stack")
return
}
// The address to connect to. Set during scanning and read afterwards.
var foundDevice bluetooth.ScanResult
// Scan for NUS peripheral.
log.Info().Msg("Scanning...")
err = projVars.GlobalConfig.GetScanAdapter().Scan(func(adapter *bluetooth.Adapter, foundDevice bluetooth.ScanResult) {
if !foundDevice.AdvertisementPayload.HasServiceUUID(targetUUID) {
return
}
// Stop the scan.
err := projVars.GlobalConfig.GetScanAdapter().StopScan()
if err != nil {
// Unlikely, but we can't recover from this.
log.Panic().Err(err).
Msg("failed to stop scan")
}
})
if err != nil {
log.Error().Err(err).
Msg("failed to start scan")
return
}
// Found a device: print this event.
if name := foundDevice.LocalName(); name == "" {
sublog = log.With().Str("MAC", foundDevice.Address.String()).Logger()
} else {
sublog = log.With().Str("MAC", foundDevice.Address.String()).
Str("Name", foundDevice.LocalName()).Logger()
}
// Found a NUS peripheral. Connect to it.
device, err := projVars.GlobalConfig.GetScanAdapter().Connect(foundDevice.Address, bluetooth.ConnectionParams{})
if err != nil {
sublog.Error().Err(err).
Msg("Failed to connect")
return
}
// Connected. Look up the Nordic UART Service.
sublog.Info().Msg("Discovering services...")
services, err := device.DiscoverServices([]bluetooth.UUID{targetUUID})
if err != nil {
log.Error().Err(err).
Msg("Failed to discover the Nordic UART Service")
return
}
service := services[0]
// Discover all characteristics (we'll filter later)
chars, err := service.DiscoverCharacteristics([]bluetooth.UUID{})
if err != nil {
log.Error().Err(err).
Msg("Failed to discover RX and TX characteristics")
return
}
rx := chars[0]
tx := chars[1]
// Enable notifications to receive incoming data.
err = tx.EnableNotifications(func(value []byte) {
for _, c := range value {
rawterm.Putchar(c)
}
})
if err != nil {
sublog.Error().Err(err).
Msg("Failed to enable TX notifications")
return
}
sublog.Info().Msg("Connected. Exit console using Ctrl-X.")
rawterm.Configure()
defer rawterm.Restore()
var line []byte
for {
ch := rawterm.Getchar()
line = append(line, ch)
// Send the current line to the central.
if ch == '\x18' {
// The user pressed Ctrl-X, exit the program.
break
} else if ch == '\n' {
sendbuf := line // copy buffer
// Reset the slice while keeping the buffer in place.
line = line[:0]
// Send the sendbuf after breaking it up in pieces.
for len(sendbuf) != 0 {
// Chop off up to 20 bytes from the sendbuf.
partlen := 20
if len(sendbuf) < 20 {
partlen = len(sendbuf)
}
part := sendbuf[:partlen]
sendbuf = sendbuf[partlen:]
// This performs a "write command" aka "write without response".
_, err := rx.WriteWithoutResponse(part)
if err != nil {
sublog.Error().Err(err).
Msg("could not send:")
}
}
}
}
}