From 582e1ae81e150228c10c597ea83c6efb1e594dee Mon Sep 17 00:00:00 2001 From: Matrix86 Date: Mon, 12 Mar 2018 15:32:50 +0100 Subject: [PATCH 01/18] wifi module can now use a pcap file as offline recon --- modules/wifi_recon.go | 103 ++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 8b4308df..4cbc5978 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -30,16 +30,18 @@ type WiFiProbe struct { type WiFiModule struct { session.SessionModule - handle *pcap.Handle - channel int - hopPeriod time.Duration - frequencies []int - ap *network.AccessPoint - stickChan int - skipBroken bool - pktSourceChan chan gopacket.Packet - writes *sync.WaitGroup - reads *sync.WaitGroup + handle *pcap.Handle + source string + channel int + hopPeriod time.Duration + frequencies []int + ap *network.AccessPoint + stickChan int + skipBroken bool + pktSourceChan chan gopacket.Packet + pktSourceChanClosed bool + writes *sync.WaitGroup + reads *sync.WaitGroup } func NewWiFiModule(s *session.Session) *WiFiModule { @@ -108,6 +110,11 @@ func NewWiFiModule(s *session.Session) *WiFiModule { "", "WiFi channel or empty for channel hopping.")) + w.AddParam(session.NewStringParameter("wifi.source.file", + "", + "", + "If set, the wifi module will read from this pcap file instead of the hardware interface.")) + w.AddParam(session.NewIntParameter("wifi.hop.period", "250", "If channel hopping is enabled (empty wifi.recon.channel), this is the time in millseconds the algorithm will hop on every channel (it'll be doubled if both 2.4 and 5.0 bands are available).")) @@ -145,21 +152,32 @@ func mhz2chan(freq int) int { func (w *WiFiModule) Configure() error { var hopPeriod int + var err error - ihandle, err := pcap.NewInactiveHandle(w.Session.Interface.Name()) - if err != nil { + if err, w.source = w.StringParam("wifi.source.file"); err != nil { return err } - defer ihandle.CleanUp() - if err = ihandle.SetRFMon(true); err != nil { - return fmt.Errorf("Error while setting interface %s in monitor mode: %s", core.Bold(w.Session.Interface.Name()), err) - } else if err = ihandle.SetSnapLen(65536); err != nil { - return err - } else if err = ihandle.SetTimeout(pcap.BlockForever); err != nil { - return err - } else if w.handle, err = ihandle.Activate(); err != nil { - return err + if w.source != "" { + if w.handle, err = pcap.OpenOffline(w.source); err != nil { + return err + } + } else { + ihandle, err := pcap.NewInactiveHandle(w.Session.Interface.Name()) + if err != nil { + return err + } + defer ihandle.CleanUp() + + if err = ihandle.SetRFMon(true); err != nil { + return fmt.Errorf("Error while setting interface %s in monitor mode: %s", core.Bold(w.Session.Interface.Name()), err) + } else if err = ihandle.SetSnapLen(65536); err != nil { + return err + } else if err = ihandle.SetTimeout(pcap.BlockForever); err != nil { + return err + } else if w.handle, err = ihandle.Activate(); err != nil { + return err + } } if err, w.skipBroken = w.BoolParam("wifi.skip-broken"); err != nil { @@ -170,25 +188,27 @@ func (w *WiFiModule) Configure() error { w.hopPeriod = time.Duration(hopPeriod) * time.Millisecond - if err, w.channel = w.IntParam("wifi.recon.channel"); err == nil { - if err = network.SetInterfaceChannel(w.Session.Interface.Name(), w.channel); err != nil { - return err + if w.source == "" { + if err, w.channel = w.IntParam("wifi.recon.channel"); err == nil { + if err = network.SetInterfaceChannel(w.Session.Interface.Name(), w.channel); err != nil { + return err + } + log.Info("WiFi recon active on channel %d.", w.channel) + } else { + w.channel = 0 + // we need to start somewhere, this is just to check if + // this OS supports switching channel programmatically. + if err = network.SetInterfaceChannel(w.Session.Interface.Name(), 1); err != nil { + return err + } + log.Info("WiFi recon active with channel hopping.") } - log.Info("WiFi recon active on channel %d.", w.channel) - } else { - w.channel = 0 - // we need to start somewhere, this is just to check if - // this OS supports switching channel programmatically. - if err = network.SetInterfaceChannel(w.Session.Interface.Name(), 1); err != nil { - return err - } - log.Info("WiFi recon active with channel hopping.") - } - if frequencies, err := network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { - return err - } else { - w.frequencies = frequencies + if frequencies, err := network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { + return err + } else { + w.frequencies = frequencies + } } return nil @@ -380,7 +400,7 @@ func (w *WiFiModule) Start() error { w.SetRunning(true, func() { // start channel hopper if needed - if w.channel == 0 { + if w.channel == 0 && w.source == "" { go w.channelHopper() } @@ -417,6 +437,7 @@ func (w *WiFiModule) Start() error { w.updateStats(dot11, packet) } } + w.pktSourceChanClosed = true }) return nil @@ -427,7 +448,9 @@ func (w *WiFiModule) Stop() error { // wait any pending write operation w.writes.Wait() // signal the main for loop we want to exit - w.pktSourceChan <- nil + if w.pktSourceChanClosed == false { + w.pktSourceChan <- nil + } // close the pcap handle to make the main for exit w.handle.Close() // close the pcap handle to make the main for exit From 63a07cf2626a1be92697cc561df1dd3a9791cbe0 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 12 Mar 2018 15:51:23 +0100 Subject: [PATCH 02/18] misc: small fix or general refactoring i did not bother commenting --- modules/wifi_hopping.go | 69 +++++++++++++++++++++++++++++++++++++++++ modules/wifi_recon.go | 61 ------------------------------------ 2 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 modules/wifi_hopping.go diff --git a/modules/wifi_hopping.go b/modules/wifi_hopping.go new file mode 100644 index 00000000..79d9b454 --- /dev/null +++ b/modules/wifi_hopping.go @@ -0,0 +1,69 @@ +package modules + +import ( + "time" + + "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/network" +) + +func mhz2chan(freq int) int { + // ambo! + if freq <= 2472 { + return ((freq - 2412) / 5) + 1 + } else if freq == 2484 { + return 14 + } else if freq >= 5035 && freq <= 5865 { + return ((freq - 5035) / 5) + 7 + } + return 0 +} + +func (w *WiFiModule) onChannel(channel int, cb func()) { + prev := w.stickChan + w.stickChan = channel + + if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil { + log.Warning("Error while hopping to channel %d: %s", channel, err) + } else { + log.Debug("Hopped on channel %d", channel) + } + + cb() + + w.stickChan = prev +} + +func (w *WiFiModule) channelHopper() { + w.reads.Add(1) + defer w.reads.Done() + + log.Info("Channel hopper started.") + for w.Running() == true { + delay := w.hopPeriod + // if we have both 2.4 and 5ghz capabilities, we have + // more channels, therefore we need to increase the time + // we hop on each one otherwise me lose information + if len(w.frequencies) > 14 { + delay = 500 * time.Millisecond + } + + for _, frequency := range w.frequencies { + channel := mhz2chan(frequency) + // stick to the access point channel as long as it's selected + // or as long as we're deauthing on it + if w.stickChan != 0 { + channel = w.stickChan + } + + if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil { + log.Warning("Error while hopping to channel %d: %s", channel, err) + } + + time.Sleep(delay) + if w.Running() == false { + return + } + } + } +} diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 4cbc5978..6f2839b4 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -138,18 +138,6 @@ func (w WiFiModule) Author() string { return "Gianluca Braga && Simone Margaritelli >" } -func mhz2chan(freq int) int { - // ambo! - if freq <= 2472 { - return ((freq - 2412) / 5) + 1 - } else if freq == 2484 { - return 14 - } else if freq >= 5035 && freq <= 5865 { - return ((freq - 5035) / 5) + 7 - } - return 0 -} - func (w *WiFiModule) Configure() error { var hopPeriod int var err error @@ -214,21 +202,6 @@ func (w *WiFiModule) Configure() error { return nil } -func (w *WiFiModule) onChannel(channel int, cb func()) { - prev := w.stickChan - w.stickChan = channel - - if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil { - log.Warning("Error while hopping to channel %d: %s", channel, err) - } else { - log.Debug("Hopped on channel %d", channel) - } - - cb() - - w.stickChan = prev -} - func isZeroBSSID(bssid net.HardwareAddr) bool { for _, b := range bssid { if b != 0x00 { @@ -331,40 +304,6 @@ func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) { } } -func (w *WiFiModule) channelHopper() { - w.reads.Add(1) - defer w.reads.Done() - - log.Info("Channel hopper started.") - for w.Running() == true { - delay := w.hopPeriod - // if we have both 2.4 and 5ghz capabilities, we have - // more channels, therefore we need to increase the time - // we hop on each one otherwise me lose information - if len(w.frequencies) > 14 { - delay = 500 * time.Millisecond - } - - for _, frequency := range w.frequencies { - channel := mhz2chan(frequency) - // stick to the access point channel as long as it's selected - // or as long as we're deauthing on it - if w.stickChan != 0 { - channel = w.stickChan - } - - if err := network.SetInterfaceChannel(w.Session.Interface.Name(), channel); err != nil { - log.Warning("Error while hopping to channel %d: %s", channel, err) - } - - time.Sleep(delay) - if w.Running() == false { - return - } - } - } -} - func (w *WiFiModule) stationPruner() { w.reads.Add(1) defer w.reads.Done() From 0a8b8548b6feab701acdfe77d2d38665ad3da09f Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 12 Mar 2018 15:58:45 +0100 Subject: [PATCH 03/18] misc: small fix or general refactoring i did not bother commenting --- modules/wifi_deauth.go | 5 +++-- modules/wifi_hopping.go | 14 +------------- modules/wifi_recon.go | 25 ++++--------------------- modules/wifi_show.go | 4 ++-- network/net.go | 18 ++++++++++++++++++ network/wifi.go | 11 +++++++++++ 6 files changed, 39 insertions(+), 38 deletions(-) diff --git a/modules/wifi_deauth.go b/modules/wifi_deauth.go index 90cf8cc9..8ecb17c0 100644 --- a/modules/wifi_deauth.go +++ b/modules/wifi_deauth.go @@ -6,6 +6,7 @@ import ( "time" "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/packets" ) @@ -62,7 +63,7 @@ func (w *WiFiModule) startDeauth(to net.HardwareAddr) error { if ap, found := w.Session.WiFi.Get(bssid); found == true { clients := ap.Clients() log.Info("Deauthing %d clients from AP %s ...", len(clients), ap.ESSID()) - w.onChannel(mhz2chan(ap.Frequency), func() { + w.onChannel(network.Dot11Freq2Chan(ap.Frequency), func() { for _, c := range clients { if w.Running() == false { break @@ -81,7 +82,7 @@ func (w *WiFiModule) startDeauth(to net.HardwareAddr) error { break } else if c, found := ap.Get(bssid); found == true { log.Info("Deauthing client %s from AP %s ...", c.HwAddress, ap.ESSID()) - w.onChannel(mhz2chan(ap.Frequency), func() { + w.onChannel(network.Dot11Freq2Chan(ap.Frequency), func() { w.sendDeauthPacket(ap.HW, c.HW) }) return nil diff --git a/modules/wifi_hopping.go b/modules/wifi_hopping.go index 79d9b454..aa742d8c 100644 --- a/modules/wifi_hopping.go +++ b/modules/wifi_hopping.go @@ -7,18 +7,6 @@ import ( "github.com/bettercap/bettercap/network" ) -func mhz2chan(freq int) int { - // ambo! - if freq <= 2472 { - return ((freq - 2412) / 5) + 1 - } else if freq == 2484 { - return 14 - } else if freq >= 5035 && freq <= 5865 { - return ((freq - 5035) / 5) + 7 - } - return 0 -} - func (w *WiFiModule) onChannel(channel int, cb func()) { prev := w.stickChan w.stickChan = channel @@ -49,7 +37,7 @@ func (w *WiFiModule) channelHopper() { } for _, frequency := range w.frequencies { - channel := mhz2chan(frequency) + channel := network.Dot11Freq2Chan(frequency) // stick to the access point channel as long as it's selected // or as long as we're deauthing on it if w.stickChan != 0 { diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 6f2839b4..8e32c073 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -76,7 +76,7 @@ func NewWiFiModule(s *session.Session) *WiFiModule { return err } else if ap, found := w.Session.WiFi.Get(bssid.String()); found == true { w.ap = ap - w.stickChan = mhz2chan(ap.Frequency) + w.stickChan = network.Dot11Freq2Chan(ap.Frequency) return nil } return fmt.Errorf("Could not find station with BSSID %s", args[0]) @@ -202,29 +202,12 @@ func (w *WiFiModule) Configure() error { return nil } -func isZeroBSSID(bssid net.HardwareAddr) bool { - for _, b := range bssid { - if b != 0x00 { - return false - } - } - return true -} - -func isBroadcastBSSID(bssid net.HardwareAddr) bool { - for _, b := range bssid { - if b != 0xff { - return false - } - } - return true -} - func (w *WiFiModule) discoverAccessPoints(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) { // search for Dot11InformationElementIDSSID if ok, ssid := packets.Dot11ParseIDSSID(packet); ok == true { - if isZeroBSSID(dot11.Address3) == false && isBroadcastBSSID(dot11.Address3) == false { - bssid := dot11.Address3.String() + from := dot11.Address3 + if network.IsZeroMac(from) == false && network.IsBroadcastMac(from) == false { + bssid := from.String() frequency := int(radiotap.ChannelFrequency) w.Session.WiFi.AddIfNew(ssid, bssid, frequency, radiotap.DBMAntennaSignal) } diff --git a/modules/wifi_show.go b/modules/wifi_show.go index f84ed639..3272b75c 100644 --- a/modules/wifi_show.go +++ b/modules/wifi_show.go @@ -66,7 +66,7 @@ func (w *WiFiModule) getRow(station *network.Station) []string { fmt.Sprintf("%d dBm", station.RSSI), bssid, /* station.Vendor, */ - strconv.Itoa(mhz2chan(station.Frequency)), + strconv.Itoa(network.Dot11Freq2Chan(station.Frequency)), sent, recvd, seen, @@ -88,7 +88,7 @@ func (w *WiFiModule) getRow(station *network.Station) []string { ssid, /* station.Vendor, */ encryption, - strconv.Itoa(mhz2chan(station.Frequency)), + strconv.Itoa(network.Dot11Freq2Chan(station.Frequency)), clients, sent, recvd, diff --git a/network/net.go b/network/net.go index 1c463aec..bc85ec82 100644 --- a/network/net.go +++ b/network/net.go @@ -26,6 +26,24 @@ var ( IPv4Validator = regexp.MustCompile("^[0-9\\.]+/?\\d*$") ) +func IsZeroMac(mac net.HardwareAddr) bool { + for _, b := range mac { + if b != 0x00 { + return false + } + } + return true +} + +func IsBroadcastMac(mac net.HardwareAddr) bool { + for _, b := range mac { + if b != 0xff { + return false + } + } + return true +} + func NormalizeMac(mac string) string { var parts []string if strings.ContainsRune(mac, '-') { diff --git a/network/wifi.go b/network/wifi.go index c7ba2481..d3b22314 100644 --- a/network/wifi.go +++ b/network/wifi.go @@ -7,6 +7,17 @@ import ( "time" ) +func Dot11Freq2Chan(freq int) int { + if freq <= 2472 { + return ((freq - 2412) / 5) + 1 + } else if freq == 2484 { + return 14 + } else if freq >= 5035 && freq <= 5865 { + return ((freq - 5035) / 5) + 7 + } + return 0 +} + type APNewCallback func(ap *AccessPoint) type APLostCallback func(ap *AccessPoint) From 4726c2fc9d545f9904c332be9ea4717f7c2ced4a Mon Sep 17 00:00:00 2001 From: Matrix86 Date: Mon, 12 Mar 2018 16:06:51 +0100 Subject: [PATCH 04/18] wifi module: fix on beacon parsing and multiple channel selection --- modules/wifi_recon.go | 80 ++++++++++++++++++++++++++++++++---------- modules/wifi_show.go | 22 +++++++++--- packets/dot11.go | 17 +++++++++ packets/dot11_types.go | 8 +++++ 4 files changed, 105 insertions(+), 22 deletions(-) diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 4cbc5978..91bade77 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -3,6 +3,8 @@ package modules import ( "fmt" "net" + "strconv" + "strings" "sync" "time" @@ -87,6 +89,10 @@ func NewWiFiModule(s *session.Session) *WiFiModule { func(args []string) error { w.ap = nil w.stickChan = 0 + var err error + if w.frequencies, err = network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { + return err + } return nil })) @@ -106,9 +112,34 @@ func NewWiFiModule(s *session.Session) *WiFiModule { return w.Show("rssi") })) - w.AddParam(session.NewIntParameter("wifi.recon.channel", - "", - "WiFi channel or empty for channel hopping.")) + w.AddHandler(session.NewModuleHandler("wifi.recon.channel", `wifi\.recon\.channel[\s]*([0-9]+(?:[, ]+[0-9]+)*)?`, + "WiFi channels (comma separated) or empty for channel hopping.", + func(args []string) error { + newfrequencies := w.frequencies[:0] + + if len(args) > 0 && args[0] != "" { + channels := strings.Split(args[0], ",") + for _, c := range channels { + trimmed := strings.Trim(c, " ") + channel, err := strconv.Atoi(trimmed) + if err != nil { + return err + } + newfrequencies = append(newfrequencies, chan2mhz(channel)) + } + } else { + // No channels setted, retrieve frequencies supported by the card + if frequencies, err := network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { + return err + } else { + newfrequencies = frequencies + } + } + + w.frequencies = newfrequencies + + return nil + })) w.AddParam(session.NewStringParameter("wifi.source.file", "", @@ -117,7 +148,7 @@ func NewWiFiModule(s *session.Session) *WiFiModule { w.AddParam(session.NewIntParameter("wifi.hop.period", "250", - "If channel hopping is enabled (empty wifi.recon.channel), this is the time in millseconds the algorithm will hop on every channel (it'll be doubled if both 2.4 and 5.0 bands are available).")) + "If channel hopping is enabled (empty wifi.recon.channel), this is the time in milliseconds the algorithm will hop on every channel (it'll be doubled if both 2.4 and 5.0 bands are available).")) w.AddParam(session.NewBoolParameter("wifi.skip-broken", "true", @@ -150,6 +181,18 @@ func mhz2chan(freq int) int { return 0 } +func chan2mhz(channel int) int { + if channel <= 13 { + return ((channel - 1) * 5) + 2412 + } else if channel == 14 { + return 2484 + } else if channel <= 173 { + return ((channel - 7) * 5) + 5035 + } + + return 0 +} + func (w *WiFiModule) Configure() error { var hopPeriod int var err error @@ -189,13 +232,12 @@ func (w *WiFiModule) Configure() error { w.hopPeriod = time.Duration(hopPeriod) * time.Millisecond if w.source == "" { - if err, w.channel = w.IntParam("wifi.recon.channel"); err == nil { - if err = network.SetInterfaceChannel(w.Session.Interface.Name(), w.channel); err != nil { + // No channels setted, retrieve frequencies supported by the card + if len(w.frequencies) == 0 { + if w.frequencies, err = network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { return err } - log.Info("WiFi recon active on channel %d.", w.channel) - } else { - w.channel = 0 + // we need to start somewhere, this is just to check if // this OS supports switching channel programmatically. if err = network.SetInterfaceChannel(w.Session.Interface.Name(), 1); err != nil { @@ -203,12 +245,6 @@ func (w *WiFiModule) Configure() error { } log.Info("WiFi recon active with channel hopping.") } - - if frequencies, err := network.GetSupportedFrequencies(w.Session.Interface.Name()); err != nil { - return err - } else { - w.frequencies = frequencies - } } return nil @@ -251,8 +287,15 @@ func (w *WiFiModule) discoverAccessPoints(radiotap *layers.RadioTap, dot11 *laye // search for Dot11InformationElementIDSSID if ok, ssid := packets.Dot11ParseIDSSID(packet); ok == true { if isZeroBSSID(dot11.Address3) == false && isBroadcastBSSID(dot11.Address3) == false { + var frequency int bssid := dot11.Address3.String() - frequency := int(radiotap.ChannelFrequency) + + if found, channel := packets.Dot11ParseDSSet(packet); found { + frequency = chan2mhz(channel) + } else { + frequency = int(radiotap.ChannelFrequency) + } + w.Session.WiFi.AddIfNew(ssid, bssid, frequency, radiotap.DBMAntennaSignal) } } @@ -342,10 +385,11 @@ func (w *WiFiModule) channelHopper() { // more channels, therefore we need to increase the time // we hop on each one otherwise me lose information if len(w.frequencies) > 14 { - delay = 500 * time.Millisecond + delay = delay * 2 * time.Millisecond } - for _, frequency := range w.frequencies { + frequencies := w.frequencies + for _, frequency := range frequencies { channel := mhz2chan(frequency) // stick to the access point channel as long as it's selected // or as long as we're deauthing on it diff --git a/modules/wifi_show.go b/modules/wifi_show.go index f84ed639..53f239b7 100644 --- a/modules/wifi_show.go +++ b/modules/wifi_show.go @@ -17,7 +17,8 @@ func (w *WiFiModule) isApSelected() bool { return w.ap != nil } -func (w *WiFiModule) getRow(station *network.Station) []string { +func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) { + include := false sinceStarted := time.Since(w.Session.StartedAt) sinceFirstSeen := time.Since(station.FirstSeen) @@ -61,6 +62,17 @@ func (w *WiFiModule) getRow(station *network.Station) []string { recvd = humanize.Bytes(station.Received) } + if w.source == "" { + for _, frequencies := range w.frequencies { + if frequencies == station.Frequency { + include = true + break + } + } + } else { + include = true + } + if w.isApSelected() { return []string{ fmt.Sprintf("%d dBm", station.RSSI), @@ -70,7 +82,7 @@ func (w *WiFiModule) getRow(station *network.Station) []string { sent, recvd, seen, - } + }, include } else { // this is ugly, but necessary in order to have this // method handle both access point and clients @@ -93,7 +105,7 @@ func (w *WiFiModule) getRow(station *network.Station) []string { sent, recvd, seen, - } + }, include } } @@ -123,7 +135,9 @@ func (w *WiFiModule) Show(by string) error { rows := make([][]string, 0) for _, s := range stations { - rows = append(rows, w.getRow(s)) + if row, include := w.getRow(s); include == true { + rows = append(rows, row) + } } nrows := len(rows) diff --git a/packets/dot11.go b/packets/dot11.go index 919b9108..ae27126b 100644 --- a/packets/dot11.go +++ b/packets/dot11.go @@ -126,3 +126,20 @@ func Dot11IsDataFor(dot11 *layers.Dot11, station net.HardwareAddr) bool { // packet going to this specific BSSID? return bytes.Compare(dot11.Address1, station) == 0 } + +func Dot11ParseDSSet(packet gopacket.Packet) (bool, int) { + channel := 0 + found := false + for _, layer := range packet.Layers() { + info, ok := layer.(*layers.Dot11InformationElement) + if ok == true { + if info.ID == layers.Dot11InformationElementIDDSSet { + channel, _ = Dot11InformationElementIDDSSetDecode(info.Info) + found = true + break + } + } + } + + return found, channel +} diff --git a/packets/dot11_types.go b/packets/dot11_types.go index bd85d2e1..6df708af 100644 --- a/packets/dot11_types.go +++ b/packets/dot11_types.go @@ -211,3 +211,11 @@ func Dot11InformationElementRSNInfoDecode(buf []byte) (rsn RSNInfo, err error) { return } + +func Dot11InformationElementIDDSSetDecode(buf []byte) (channel int, err error) { + if err = canParse("DSSet.channel", buf, 1); err == nil { + channel = int(buf[0]) + } + + return +} From 1b7131eb54da5b03b0edb2aebf8f697677017475 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 12 Mar 2018 16:25:12 +0100 Subject: [PATCH 05/18] misc: small fix or general refactoring i did not bother commenting --- modules/wifi_recon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 91bade77..b37a7b45 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -385,7 +385,7 @@ func (w *WiFiModule) channelHopper() { // more channels, therefore we need to increase the time // we hop on each one otherwise me lose information if len(w.frequencies) > 14 { - delay = delay * 2 * time.Millisecond + delay = delay * 2 } frequencies := w.frequencies From 17e5138acd18d34d2d5af59d581f6fe889219f20 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 12 Mar 2018 17:01:53 +0100 Subject: [PATCH 06/18] misc: small fix or general refactoring i did not bother commenting --- modules/wifi_recon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 0faf47c6..d40a4ab1 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -113,7 +113,7 @@ func NewWiFiModule(s *session.Session) *WiFiModule { })) w.AddHandler(session.NewModuleHandler("wifi.recon.channel", `wifi\.recon\.channel[\s]+([0-9]+(?:[, ]+[0-9]+)*|clear)`, - "WiFi channels (comma separated) or empty for channel hopping.", + "WiFi channels (comma separated) or 'clear' for channel hopping.", func(args []string) error { newfrequencies := w.frequencies[:0] From b63c20b757e1936b97fde6c403c5415a6178bfed Mon Sep 17 00:00:00 2001 From: evilsocket Date: Mon, 12 Mar 2018 17:13:28 +0100 Subject: [PATCH 07/18] misc: small fix or general refactoring i did not bother commenting --- build.sh | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/build.sh b/build.sh index 110a2f06..d90ad51f 100755 --- a/build.sh +++ b/build.sh @@ -13,6 +13,16 @@ host_dep() { ping -c 1 $HOST > /dev/null || { echo "@ Virtual machine host $HOST not visible !"; exit 1; } } +create_exe_archive() { + bin_dep 'zip' + + OUTPUT=$1 + + echo "@ Creating archive $OUTPUT ..." + zip -j "$OUTPUT" bettercap.exe ../README.md ../LICENSE.md > /dev/null + rm -rf bettercap bettercap.exe +} + create_archive() { bin_dep 'zip' @@ -172,19 +182,17 @@ mkdir $BUILD_FOLDER cd $BUILD_FOLDER -build_linux_amd64 # && create_archive bettercap_linux_amd64_$VERSION.zip -# build_linux_arm7_static && create_archive bettercap_linux_arm7_$VERSION.zip -# build_linux_arm7hf_static && create_archive bettercap_linux_arm7hf_$VERSION.zip -# build_linux_mips_static && create_archive bettercap_linux_mips_$VERSION.zip -# build_linux_mipsle_static && create_archive bettercap_linux_mipsle_$VERSION.zip -# build_linux_mips64_static && create_archive bettercap_linux_mips64_$VERSION.zip -# build_linux_mips64le_static && create_archive bettercap_linux_mips64le_$VERSION.zip -# -# # these are still not static :( -# build_macos_amd64 && create_archive bettercap_macos_amd64_$VERSION.zip -# build_android_arm && create_archive bettercap_android_arm_$VERSION.zip -# build_windows_amd64 && create_archive bettercap_windows_amd64_$VERSION.zip -# sha256sum * > checksums.txt +build_linux_amd64 && create_archive bettercap_linux_amd64_$VERSION.zip +build_macos_amd64 && create_archive bettercap_macos_amd64_$VERSION.zip +build_android_arm && create_archive bettercap_android_arm_$VERSION.zip +build_windows_amd64 && create_exe_archive bettercap_windows_amd64_$VERSION.zip +build_linux_arm7_static && create_archive bettercap_linux_arm7_$VERSION.zip +build_linux_arm7hf_static && create_archive bettercap_linux_arm7hf_$VERSION.zip +build_linux_mips_static && create_archive bettercap_linux_mips_$VERSION.zip +build_linux_mipsle_static && create_archive bettercap_linux_mipsle_$VERSION.zip +build_linux_mips64_static && create_archive bettercap_linux_mips64_$VERSION.zip +build_linux_mips64le_static && create_archive bettercap_linux_mips64le_$VERSION.zip +sha256sum * > checksums.txt echo echo From 4b8d4aeb1b534478b801e68d60ed2ef9cb6d4998 Mon Sep 17 00:00:00 2001 From: KhasMek Date: Mon, 12 Mar 2018 18:41:53 -0600 Subject: [PATCH 08/18] api: switch request router and add more paths This switches the url router to gorilla and adds the following routes. - /api/events - /api/session - /api/session/ble - /api/session/ble/{mac} - /api/session/env - /api/session/gateway - /api/session/interface - /api/session/lan - /api/session/lan/{mac} - /api/session/options - /api/session/packets - /api/session/started-at - /api/session/wifi - /api/session/wifi/{mac} where {mac} is the mac address of a device. --- modules/api_rest.go | 17 +++++- modules/api_rest_controller.go | 103 ++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/modules/api_rest.go b/modules/api_rest.go index 920fd044..f54ebdaf 100644 --- a/modules/api_rest.go +++ b/modules/api_rest.go @@ -11,6 +11,7 @@ import ( "github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/tls" + "github.com/gorilla/mux" "github.com/gorilla/websocket" ) @@ -146,10 +147,22 @@ func (api *RestAPI) Configure() error { api.server.Addr = fmt.Sprintf("%s:%d", ip, port) - router := http.NewServeMux() + router := mux.NewRouter() - router.HandleFunc("/api/session", api.sessionRoute) router.HandleFunc("/api/events", api.eventsRoute) + router.HandleFunc("/api/session", api.sessionRoute) + router.HandleFunc("/api/session/ble", api.sessionRoute) + router.HandleFunc("/api/session/ble/{mac}", api.sessionRoute) + router.HandleFunc("/api/session/env", api.sessionRoute) + router.HandleFunc("/api/session/gateway", api.sessionRoute) + router.HandleFunc("/api/session/interface", api.sessionRoute) + router.HandleFunc("/api/session/lan", api.sessionRoute) + router.HandleFunc("/api/session/lan/{mac}", api.sessionRoute) + router.HandleFunc("/api/session/options", api.sessionRoute) + router.HandleFunc("/api/session/packets", api.sessionRoute) + router.HandleFunc("/api/session/started-at", api.sessionRoute) + router.HandleFunc("/api/session/wifi", api.sessionRoute) + router.HandleFunc("/api/session/wifi/{mac}", api.sessionRoute) api.server.Handler = router diff --git a/modules/api_rest_controller.go b/modules/api_rest_controller.go index 50e7caac..05bd28eb 100644 --- a/modules/api_rest_controller.go +++ b/modules/api_rest_controller.go @@ -11,6 +11,7 @@ import ( "github.com/bettercap/bettercap/log" "github.com/bettercap/bettercap/session" + "github.com/gorilla/mux" "github.com/gorilla/websocket" ) @@ -67,6 +68,73 @@ func (api *RestAPI) showSession(w http.ResponseWriter, r *http.Request) { toJSON(w, session.I) } +func (api *RestAPI) showBle(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.BLE) +} + +func (api *RestAPI) showBleEndpoint(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + mac := strings.ToLower(params["mac"]) + if dev, found := session.I.BLE.Get(mac); found == true { + toJSON(w, dev) + } +} + +func (api *RestAPI) showEnv(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Env) +} + +func (api *RestAPI) showGateway(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Gateway) +} + +func (api *RestAPI) showInterface(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Interface) +} + +func (api *RestAPI) showLan(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Lan) +} + +func (api *RestAPI) showLanEndpoint(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + mac := strings.ToLower(params["mac"]) + if host, found := session.I.Lan.Get(mac); found == true { + toJSON(w, host) + } +} + +func (api *RestAPI) showOptions(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Options) +} + +func (api *RestAPI) showPackets(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.Queue) +} + +func (api *RestAPI) showStartedAt(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.StartedAt) +} + +func (api *RestAPI) showWiFi(w http.ResponseWriter, r *http.Request) { + toJSON(w, session.I.WiFi) +} + +func (api *RestAPI) showWiFiEndpoint(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + mac := strings.ToLower(params["mac"]) + if station, found := session.I.WiFi.Get(mac); found == true { + toJSON(w, station) + // cycle through station clients if not a station. + } else { + for _, ap := range session.I.WiFi.List() { + if client, found := ap.Get(mac); found == true { + toJSON(w, client) + } + } + } +} + func (api *RestAPI) runSessionCommand(w http.ResponseWriter, r *http.Request) { var err error var cmd CommandRequest @@ -211,7 +279,40 @@ func (api *RestAPI) sessionRoute(w http.ResponseWriter, r *http.Request) { if api.checkAuth(r) == false { setAuthFailed(w, r) } else if r.Method == "GET" { - api.showSession(w, r) + params := mux.Vars(r) + if r.URL.String() == "/api/session" { + api.showSession(w, r) + } else if strings.HasPrefix(r.URL.String(), "/api/session/ble") { + if params["mac"] != "" { + api.showBleEndpoint(w, r) + } else { + api.showBle(w, r) + } + } else if r.URL.String() == "/api/session/env" { + api.showEnv(w, r) + } else if r.URL.String() == "/api/session/gateway" { + api.showGateway(w, r) + } else if r.URL.String() == "/api/session/interface" { + api.showInterface(w, r) + } else if strings.HasPrefix(r.URL.String(), "/api/session/lan") { + if params["mac"] != "" { + api.showLanEndpoint(w, r) + } else { + api.showLan(w, r) + } + } else if r.URL.String() == "/api/session/options" { + api.showOptions(w, r) + } else if r.URL.String() == "/api/session/packets" { + api.showPackets(w, r) + } else if r.URL.String() == "/api/session/started-at" { + api.showStartedAt(w, r) + } else if strings.HasPrefix(r.URL.String(), "/api/session/wifi") { + if params["mac"] != "" { + api.showWiFiEndpoint(w, r) + } else { + api.showWiFi(w, r) + } + } } else if r.Method == "POST" { api.runSessionCommand(w, r) } else { From e40219976c0efe8b8631ed5eab1b7724dc6e01b4 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 13:20:21 +0100 Subject: [PATCH 09/18] new: implemented events.stream.output (closes #169). new: implemented -no-colors argument. --- core/options.go | 2 ++ core/swag.go | 12 +++++--- main.go | 21 ++++++++------ modules/events_stream.go | 29 +++++++++++++++++-- modules/events_view.go | 39 +++++++++++++------------- modules/events_view_ble.go | 8 +++--- modules/events_view_ble_unsupported.go | 2 +- session/prompt.go | 38 +++++++++++++------------ session/session.go | 2 ++ 9 files changed, 97 insertions(+), 56 deletions(-) diff --git a/core/options.go b/core/options.go index 887b2901..d9c2566c 100644 --- a/core/options.go +++ b/core/options.go @@ -7,6 +7,7 @@ type Options struct { Caplet *string Debug *bool Silent *bool + NoColors *bool NoHistory *bool EnvFile *string Commands *string @@ -20,6 +21,7 @@ func ParseOptions() (Options, error) { Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."), Debug: flag.Bool("debug", false, "Print debug messages."), Silent: flag.Bool("silent", false, "Suppress all logs which are not errors."), + NoColors: flag.Bool("no-colors", false, "Disable output color effect,s."), NoHistory: flag.Bool("no-history", false, "Disable interactive session history file."), EnvFile: flag.String("env-file", "", "Load environment variables from this file if found, set to empty to disable environment persistance."), Commands: flag.String("eval", "", "Run one or more commands separated by ; in the interactive session, used to set variables via command line."), diff --git a/core/swag.go b/core/swag.go index 1e9d2ae3..95d71e06 100644 --- a/core/swag.go +++ b/core/swag.go @@ -26,14 +26,17 @@ var ( RESET = "\033[0m" - NoColors = false + HasColors = true ) -func init() { - NoColors = os.Getenv("TERM") == "dumb" || +func isDumbTerminal() bool { + return os.Getenv("TERM") == "dumb" || os.Getenv("TERM") == "" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) - if NoColors { +} + +func InitSwag(disableColors bool) { + if disableColors || isDumbTerminal() { BOLD = "" DIM = "" RED = "" @@ -48,6 +51,7 @@ func init() { BG_YELLOW = "" BG_LBLUE = "" RESET = "" + HasColors = false } } diff --git a/main.go b/main.go index cde04647..116d48d2 100644 --- a/main.go +++ b/main.go @@ -27,8 +27,12 @@ func main() { os.Exit(1) } - if core.NoColors == true { - fmt.Printf("\n\nWARNING: This terminal does not support colors, view will be very limited.\n\n") + if core.HasColors == false { + if *sess.Options.NoColors == true { + fmt.Printf("\n\nWARNING: Terminal colors have been disabled, view will be very limited.\n\n") + } else { + fmt.Printf("\n\nWARNING: This terminal does not support colors, view will be very limited.\n\n") + } } appName := fmt.Sprintf("%s v%s", core.Name, core.Version) @@ -59,12 +63,6 @@ func main() { log.Fatal("%s", err) } - for _, modName := range autoEnableList { - if err = sess.Run(modName + " on"); err != nil { - log.Fatal("Error while starting module %s: %", modName, err) - } - } - /* * Commands sent with -eval are used to set specific * caplet parameters (i.e. arp.spoof.targets) via command @@ -77,6 +75,13 @@ func main() { } } + // Start modules that are enabled by default. + for _, modName := range autoEnableList { + if err = sess.Run(modName + " on"); err != nil { + log.Fatal("Error while starting module %s: %", modName, err) + } + } + // Then run the caplet if specified. if *sess.Options.Caplet != "" { if err = sess.RunCaplet(*sess.Options.Caplet); err != nil { diff --git a/modules/events_stream.go b/modules/events_stream.go index fa1e9d8b..bc0d6394 100644 --- a/modules/events_stream.go +++ b/modules/events_stream.go @@ -2,6 +2,7 @@ package modules import ( "fmt" + "os" "strconv" "time" @@ -12,6 +13,7 @@ import ( type EventsStream struct { session.SessionModule + output *os.File ignoreList *IgnoreList waitFor string waitChan chan *session.Event @@ -22,6 +24,7 @@ type EventsStream struct { func NewEventsStream(s *session.Session) *EventsStream { stream := &EventsStream{ SessionModule: session.NewSessionModule("events.stream", s), + output: os.Stdout, quit: make(chan bool), waitChan: make(chan *session.Event), waitFor: "", @@ -104,6 +107,11 @@ func NewEventsStream(s *session.Session) *EventsStream { return nil })) + stream.AddParam(session.NewStringParameter("events.stream.output", + "", + "", + "If not empty, events will be written to this file instead of the standard output.")) + return stream } @@ -119,11 +127,25 @@ func (s EventsStream) Author() string { return "Simone Margaritelli " } -func (s *EventsStream) Configure() error { - return nil +func (s *EventsStream) Configure() (err error) { + var output string + + if err, output = s.StringParam("events.stream.output"); err == nil { + if output == "" { + s.output = os.Stdout + } else if output, err = core.ExpandPath(output); err == nil { + s.output, err = os.OpenFile(output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + } + } + + return err } func (s *EventsStream) Start() error { + if err := s.Configure(); err != nil { + return err + } + return s.SetRunning(true, func() { s.eventListener = s.Session.Events.Listen() for { @@ -196,5 +218,8 @@ func (s *EventsStream) startWaitingFor(tag string, timeout int) error { func (s *EventsStream) Stop() error { return s.SetRunning(false, func() { s.quit <- true + if s.output != os.Stdout { + s.output.Close() + } }) } diff --git a/modules/events_view.go b/modules/events_view.go index 21d99451..4ac29e80 100644 --- a/modules/events_view.go +++ b/modules/events_view.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "strings" "github.com/bettercap/bettercap/core" @@ -13,15 +14,15 @@ import ( const eventTimeFormat = "15:04:05" -func (s EventsStream) viewLogEvent(e session.Event) { - fmt.Printf("[%s] [%s] [%s] %s\n", +func (s *EventsStream) viewLogEvent(e session.Event) { + fmt.Fprintf(s.output, "[%s] [%s] [%s] %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e.Label(), e.Data.(session.LogMessage).Message) } -func (s EventsStream) viewWiFiEvent(e session.Event) { +func (s *EventsStream) viewWiFiEvent(e session.Event) { if strings.HasPrefix(e.Tag, "wifi.ap.") { ap := e.Data.(*network.AccessPoint) @@ -35,7 +36,7 @@ func (s EventsStream) viewWiFiEvent(e session.Event) { } if e.Tag == "wifi.ap.new" { - fmt.Printf("[%s] [%s] WiFi access point %s%s detected as %s%s.\n", + fmt.Fprintf(s.output, "[%s] [%s] WiFi access point %s%s detected as %s%s.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), core.Bold(ap.ESSID()), @@ -43,13 +44,13 @@ func (s EventsStream) viewWiFiEvent(e session.Event) { core.Green(ap.BSSID()), core.Dim(vend)) } else if e.Tag == "wifi.ap.lost" { - fmt.Printf("[%s] [%s] WiFi access point %s (%s) lost.\n", + fmt.Fprintf(s.output, "[%s] [%s] WiFi access point %s (%s) lost.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), core.Red(ap.ESSID()), ap.BSSID()) } else { - fmt.Printf("[%s] [%s] %s\n", + fmt.Fprintf(s.output, "[%s] [%s] %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), ap.String()) @@ -67,7 +68,7 @@ func (s EventsStream) viewWiFiEvent(e session.Event) { rssi = fmt.Sprintf(" (%d dBm)", probe.RSSI) } - fmt.Printf("[%s] [%s] Station %s%s is probing for SSID %s%s\n", + fmt.Fprintf(s.output, "[%s] [%s] Station %s%s is probing for SSID %s%s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), probe.FromAddr.String(), @@ -77,7 +78,7 @@ func (s EventsStream) viewWiFiEvent(e session.Event) { } } -func (s EventsStream) viewEndpointEvent(e session.Event) { +func (s *EventsStream) viewEndpointEvent(e session.Event) { t := e.Data.(*network.Endpoint) vend := "" name := "" @@ -93,7 +94,7 @@ func (s EventsStream) viewEndpointEvent(e session.Event) { } if e.Tag == "endpoint.new" { - fmt.Printf("[%s] [%s] Endpoint %s%s detected as %s%s.\n", + fmt.Fprintf(s.output, "[%s] [%s] Endpoint %s%s detected as %s%s.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), core.Bold(t.IpAddress), @@ -101,27 +102,27 @@ func (s EventsStream) viewEndpointEvent(e session.Event) { core.Green(t.HwAddress), core.Dim(vend)) } else if e.Tag == "endpoint.lost" { - fmt.Printf("[%s] [%s] Endpoint %s%s lost.\n", + fmt.Fprintf(s.output, "[%s] [%s] Endpoint %s%s lost.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), core.Red(t.IpAddress), core.Dim(vend)) } else { - fmt.Printf("[%s] [%s] %s\n", + fmt.Fprintf(s.output, "[%s] [%s] %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), t.String()) } } -func (s EventsStream) viewModuleEvent(e session.Event) { - fmt.Printf("[%s] [%s] %s\n", +func (s *EventsStream) viewModuleEvent(e session.Event) { + fmt.Fprintf(s.output, "[%s] [%s] %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e.Data) } -func (s EventsStream) viewSnifferEvent(e session.Event) { +func (s *EventsStream) viewSnifferEvent(e session.Event) { se := e.Data.(SnifferEvent) misc := "" @@ -150,16 +151,16 @@ func (s EventsStream) viewSnifferEvent(e session.Event) { misc = fmt.Sprintf("%s", se.Data) } - fmt.Printf("[%s] [%s] %s %s\n", + fmt.Fprintf(s.output, "[%s] [%s] %s %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), se.Message, misc) } -func (s EventsStream) viewSynScanEvent(e session.Event) { +func (s *EventsStream) viewSynScanEvent(e session.Event) { se := e.Data.(SynScanEvent) - fmt.Printf("[%s] [%s] Found open port %d for %s\n", + fmt.Fprintf(s.output, "[%s] [%s] Found open port %d for %s\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), se.Port, @@ -182,10 +183,10 @@ func (s *EventsStream) View(e session.Event, refresh bool) { } else if strings.HasPrefix(e.Tag, "syn.scan.") { s.viewSynScanEvent(e) } else { - fmt.Printf("[%s] [%s] %v\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e) + fmt.Fprintf(s.output, "[%s] [%s] %v\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), e) } - if refresh { + if refresh && s.output == os.Stdout { s.Session.Refresh() } } diff --git a/modules/events_view_ble.go b/modules/events_view_ble.go index 5a1c79d5..41886327 100644 --- a/modules/events_view_ble.go +++ b/modules/events_view_ble.go @@ -11,7 +11,7 @@ import ( "github.com/bettercap/bettercap/session" ) -func (s EventsStream) viewBLEEvent(e session.Event) { +func (s *EventsStream) viewBLEEvent(e session.Event) { if e.Tag == "ble.device.new" { dev := e.Data.(*network.BLEDevice) name := dev.Device.Name() @@ -23,7 +23,7 @@ func (s EventsStream) viewBLEEvent(e session.Event) { vend = fmt.Sprintf(" (%s)", core.Yellow(vend)) } - fmt.Printf("[%s] [%s] New BLE device%s detected as %s%s %s.\n", + fmt.Fprintf(s.output, "[%s] [%s] New BLE device%s detected as %s%s %s.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), name, @@ -41,14 +41,14 @@ func (s EventsStream) viewBLEEvent(e session.Event) { vend = fmt.Sprintf(" (%s)", core.Yellow(vend)) } - fmt.Printf("[%s] [%s] BLE device%s %s%s lost.\n", + fmt.Fprintf(s.output, "[%s] [%s] BLE device%s %s%s lost.\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag), name, dev.Device.ID(), vend) } /* else { - fmt.Printf("[%s] [%s]\n", + fmt.Fprintf(s.output,"[%s] [%s]\n", e.Time.Format(eventTimeFormat), core.Green(e.Tag)) } */ diff --git a/modules/events_view_ble_unsupported.go b/modules/events_view_ble_unsupported.go index 9bddc30e..11dc7e6e 100644 --- a/modules/events_view_ble_unsupported.go +++ b/modules/events_view_ble_unsupported.go @@ -6,6 +6,6 @@ import ( "github.com/bettercap/bettercap/session" ) -func (s EventsStream) viewBLEEvent(e session.Event) { +func (s *EventsStream) viewBLEEvent(e session.Event) { } diff --git a/session/prompt.go b/session/prompt.go index e93828ff..b05ff45f 100644 --- a/session/prompt.go +++ b/session/prompt.go @@ -15,23 +15,6 @@ const ( DefaultPrompt = "{by}{fw}{cidr} {fb}> {env.iface.ipv4} {reset} {bold}ยป {reset}" ) -var PromptEffects = map[string]string{ - "{bold}": core.BOLD, - "{dim}": core.DIM, - "{r}": core.RED, - "{g}": core.GREEN, - "{b}": core.BLUE, - "{y}": core.YELLOW, - "{fb}": core.FG_BLACK, - "{fw}": core.FG_WHITE, - "{bdg}": core.BG_DGRAY, - "{br}": core.BG_RED, - "{bg}": core.BG_GREEN, - "{by}": core.BG_YELLOW, - "{blb}": core.BG_LBLUE, // Ziggy this is for you <3 - "{reset}": core.RESET, -} - var PromptCallbacks = map[string]func(s *Session) string{ "{cidr}": func(s *Session) string { return s.Interface.CIDR() @@ -71,7 +54,26 @@ func (p Prompt) Render(s *Session) string { prompt = DefaultPrompt } - for tok, effect := range PromptEffects { + // these are here because if colors are disabled, + // we need the updated core.* variables + var effects = map[string]string{ + "{bold}": core.BOLD, + "{dim}": core.DIM, + "{r}": core.RED, + "{g}": core.GREEN, + "{b}": core.BLUE, + "{y}": core.YELLOW, + "{fb}": core.FG_BLACK, + "{fw}": core.FG_WHITE, + "{bdg}": core.BG_DGRAY, + "{br}": core.BG_RED, + "{bg}": core.BG_GREEN, + "{by}": core.BG_YELLOW, + "{blb}": core.BG_LBLUE, // Ziggy this is for you <3 + "{reset}": core.RESET, + } + + for tok, effect := range effects { prompt = strings.Replace(prompt, tok, effect, -1) } diff --git a/session/session.go b/session/session.go index 57381ad6..01d3e6c4 100644 --- a/session/session.go +++ b/session/session.go @@ -138,6 +138,8 @@ func New() (*Session, error) { return nil, err } + core.InitSwag(*s.Options.NoColors) + if *s.Options.CpuProfile != "" { if f, err := os.Create(*s.Options.CpuProfile); err != nil { return nil, err From 1ea44ec73d043c8ccfd593d7c341672b693118f3 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 13:22:09 +0100 Subject: [PATCH 10/18] misc: small fix or general refactoring i did not bother commenting --- core/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/options.go b/core/options.go index d9c2566c..9dac88e8 100644 --- a/core/options.go +++ b/core/options.go @@ -21,7 +21,7 @@ func ParseOptions() (Options, error) { Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."), Debug: flag.Bool("debug", false, "Print debug messages."), Silent: flag.Bool("silent", false, "Suppress all logs which are not errors."), - NoColors: flag.Bool("no-colors", false, "Disable output color effect,s."), + NoColors: flag.Bool("no-colors", false, "Disable output color effects."), NoHistory: flag.Bool("no-history", false, "Disable interactive session history file."), EnvFile: flag.String("env-file", "", "Load environment variables from this file if found, set to empty to disable environment persistance."), Commands: flag.String("eval", "", "Run one or more commands separated by ; in the interactive session, used to set variables via command line."), From cc01a995796007fdc9b6e464d2503f20652ff727 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 13:57:52 +0100 Subject: [PATCH 11/18] refact: refactored api.rest controller --- modules/api_rest_controller.go | 121 +++++++++++++++++---------------- network/wifi.go | 14 ++++ 2 files changed, 77 insertions(+), 58 deletions(-) diff --git a/modules/api_rest_controller.go b/modules/api_rest_controller.go index 05bd28eb..ec060122 100644 --- a/modules/api_rest_controller.go +++ b/modules/api_rest_controller.go @@ -69,14 +69,15 @@ func (api *RestAPI) showSession(w http.ResponseWriter, r *http.Request) { } func (api *RestAPI) showBle(w http.ResponseWriter, r *http.Request) { - toJSON(w, session.I.BLE) -} - -func (api *RestAPI) showBleEndpoint(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) mac := strings.ToLower(params["mac"]) - if dev, found := session.I.BLE.Get(mac); found == true { + + if mac == "" { + toJSON(w, session.I.BLE) + } else if dev, found := session.I.BLE.Get(mac); found == true { toJSON(w, dev) + } else { + http.Error(w, "Not Found", 404) } } @@ -93,14 +94,15 @@ func (api *RestAPI) showInterface(w http.ResponseWriter, r *http.Request) { } func (api *RestAPI) showLan(w http.ResponseWriter, r *http.Request) { - toJSON(w, session.I.Lan) -} - -func (api *RestAPI) showLanEndpoint(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) mac := strings.ToLower(params["mac"]) - if host, found := session.I.Lan.Get(mac); found == true { + + if mac == "" { + toJSON(w, session.I.Lan) + } else if host, found := session.I.Lan.Get(mac); found == true { toJSON(w, host) + } else { + http.Error(w, "Not Found", 404) } } @@ -117,21 +119,17 @@ func (api *RestAPI) showStartedAt(w http.ResponseWriter, r *http.Request) { } func (api *RestAPI) showWiFi(w http.ResponseWriter, r *http.Request) { - toJSON(w, session.I.WiFi) -} - -func (api *RestAPI) showWiFiEndpoint(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) mac := strings.ToLower(params["mac"]) - if station, found := session.I.WiFi.Get(mac); found == true { + + if mac == "" { + toJSON(w, session.I.WiFi) + } else if station, found := session.I.WiFi.Get(mac); found == true { toJSON(w, station) - // cycle through station clients if not a station. + } else if client, found := session.I.WiFi.GetClient(mac); found == true { + toJSON(w, client) } else { - for _, ap := range session.I.WiFi.List() { - if client, found := ap.Get(mac); found == true { - toJSON(w, client) - } - } + http.Error(w, "Not Found", 404) } } @@ -278,45 +276,49 @@ func (api *RestAPI) sessionRoute(w http.ResponseWriter, r *http.Request) { if api.checkAuth(r) == false { setAuthFailed(w, r) - } else if r.Method == "GET" { - params := mux.Vars(r) - if r.URL.String() == "/api/session" { - api.showSession(w, r) - } else if strings.HasPrefix(r.URL.String(), "/api/session/ble") { - if params["mac"] != "" { - api.showBleEndpoint(w, r) - } else { - api.showBle(w, r) - } - } else if r.URL.String() == "/api/session/env" { - api.showEnv(w, r) - } else if r.URL.String() == "/api/session/gateway" { - api.showGateway(w, r) - } else if r.URL.String() == "/api/session/interface" { - api.showInterface(w, r) - } else if strings.HasPrefix(r.URL.String(), "/api/session/lan") { - if params["mac"] != "" { - api.showLanEndpoint(w, r) - } else { - api.showLan(w, r) - } - } else if r.URL.String() == "/api/session/options" { - api.showOptions(w, r) - } else if r.URL.String() == "/api/session/packets" { - api.showPackets(w, r) - } else if r.URL.String() == "/api/session/started-at" { - api.showStartedAt(w, r) - } else if strings.HasPrefix(r.URL.String(), "/api/session/wifi") { - if params["mac"] != "" { - api.showWiFiEndpoint(w, r) - } else { - api.showWiFi(w, r) - } - } + return } else if r.Method == "POST" { api.runSessionCommand(w, r) - } else { + return + } else if r.Method != "GET" { http.Error(w, "Bad Request", 400) + return + } + + path := r.URL.String() + switch { + case path == "/api/session": + api.showSession(w, r) + + case path == "/api/session/env": + api.showEnv(w, r) + + case path == "/api/session/gateway": + api.showGateway(w, r) + + case path == "/api/session/interface": + api.showInterface(w, r) + + case strings.HasPrefix(path, "/api/session/lan"): + api.showLan(w, r) + + case path == "/api/session/options": + api.showOptions(w, r) + + case path == "/api/session/packets": + api.showPackets(w, r) + + case path == "/api/session/started-at": + api.showStartedAt(w, r) + + case strings.HasPrefix(path, "/api/session/ble"): + api.showBle(w, r) + + case strings.HasPrefix(path, "/api/session/wifi"): + api.showWiFi(w, r) + + default: + http.Error(w, "Not Found", 404) } } @@ -325,7 +327,10 @@ func (api *RestAPI) eventsRoute(w http.ResponseWriter, r *http.Request) { if api.checkAuth(r) == false { setAuthFailed(w, r) - } else if r.Method == "GET" { + return + } + + if r.Method == "GET" { api.showEvents(w, r) } else if r.Method == "DELETE" { api.clearEvents(w, r) diff --git a/network/wifi.go b/network/wifi.go index 6a87615c..64ec588d 100644 --- a/network/wifi.go +++ b/network/wifi.go @@ -156,6 +156,20 @@ func (w *WiFi) Get(mac string) (*AccessPoint, bool) { return ap, found } +func (w *WiFi) GetClient(mac string) (*Station, bool) { + w.Lock() + defer w.Unlock() + + mac = NormalizeMac(mac) + for _, ap := range w.aps { + if client, found := ap.Get(mac); found == true { + return client, true + } + } + + return nil, false +} + func (w *WiFi) Clear() error { w.aps = make(map[string]*AccessPoint) return nil From d09eec3535fef58ad2a82b69c1a946a8d6fed7bd Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:41:37 +0100 Subject: [PATCH 12/18] misc: small fix or general refactoring i did not bother commenting --- modules/api_rest_controller.go | 104 +---------------------------- modules/api_rest_ws.go | 116 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 103 deletions(-) create mode 100644 modules/api_rest_ws.go diff --git a/modules/api_rest_controller.go b/modules/api_rest_controller.go index ec060122..71315e6c 100644 --- a/modules/api_rest_controller.go +++ b/modules/api_rest_controller.go @@ -6,22 +6,11 @@ import ( "net/http" "strconv" "strings" - "time" "github.com/bettercap/bettercap/log" "github.com/bettercap/bettercap/session" "github.com/gorilla/mux" - "github.com/gorilla/websocket" -) - -const ( - // Time allowed to write an event to the client. - writeWait = 10 * time.Second - // Time allowed to read the next pong message from the client. - pongWait = 60 * time.Second - // Send pings to client with this period. Must be less than pongWait. - pingPeriod = (pongWait * 9) / 10 ) type CommandRequest struct { @@ -148,103 +137,12 @@ func (api *RestAPI) runSessionCommand(w http.ResponseWriter, r *http.Request) { } } -func (api *RestAPI) streamEvent(ws *websocket.Conn, event session.Event) error { - msg, err := json.Marshal(event) - if err != nil { - log.Error("Error while creating websocket message: %s", err) - return err - } - - ws.SetWriteDeadline(time.Now().Add(writeWait)) - if err := ws.WriteMessage(websocket.TextMessage, msg); err != nil { - if !strings.Contains(err.Error(), "closed connection") { - log.Error("Error while writing websocket message: %s", err) - return err - } - } - - return nil -} - -func (api *RestAPI) sendPing(ws *websocket.Conn) error { - ws.SetWriteDeadline(time.Now().Add(writeWait)) - if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { - log.Error("Error while writing websocket ping message: %s", err) - return err - } - return nil -} - -func (api *RestAPI) streamWriter(ws *websocket.Conn, w http.ResponseWriter, r *http.Request) { - defer ws.Close() - - // first we stream what we already have - events := session.I.Events.Sorted() - n := len(events) - if n > 0 { - log.Debug("Sending %d events.", n) - for _, event := range events { - if err := api.streamEvent(ws, event); err != nil { - return - } - } - } - - session.I.Events.Clear() - - log.Debug("Listening for events and streaming to ws endpoint ...") - - pingTicker := time.NewTicker(pingPeriod) - - for { - select { - case <-pingTicker.C: - if err := api.sendPing(ws); err != nil { - return - } - case event := <-api.eventListener: - if err := api.streamEvent(ws, event); err != nil { - return - } - case <-api.quit: - log.Info("Stopping websocket events streamer ...") - return - } - } -} - -func (api *RestAPI) streamReader(ws *websocket.Conn) { - defer ws.Close() - ws.SetReadLimit(512) - ws.SetReadDeadline(time.Now().Add(pongWait)) - ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) - for { - _, _, err := ws.ReadMessage() - if err != nil { - log.Debug("Closing websocket reader.") - break - } - } -} - func (api *RestAPI) showEvents(w http.ResponseWriter, r *http.Request) { var err error if api.useWebsocket { - ws, err := api.upgrader.Upgrade(w, r, nil) - if err != nil { - if _, ok := err.(websocket.HandshakeError); !ok { - log.Error("Error while updating api.rest connection to websocket: %s", err) - } - return - } - - log.Debug("Websocket streaming started for %s", r.RemoteAddr) - - go api.streamWriter(ws, w, r) - api.streamReader(ws) + api.startStreamingEvents(w, r) } else { - events := session.I.Events.Sorted() nevents := len(events) nmax := nevents diff --git a/modules/api_rest_ws.go b/modules/api_rest_ws.go new file mode 100644 index 00000000..b32a8bed --- /dev/null +++ b/modules/api_rest_ws.go @@ -0,0 +1,116 @@ +package modules + +import ( + "encoding/json" + "net/http" + "strings" + "time" + + "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/session" + + "github.com/gorilla/websocket" +) + +const ( + // Time allowed to write an event to the client. + writeWait = 10 * time.Second + // Time allowed to read the next pong message from the client. + pongWait = 60 * time.Second + // Send pings to client with this period. Must be less than pongWait. + pingPeriod = (pongWait * 9) / 10 +) + +func (api *RestAPI) streamEvent(ws *websocket.Conn, event session.Event) error { + msg, err := json.Marshal(event) + if err != nil { + log.Error("Error while creating websocket message: %s", err) + return err + } + + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.TextMessage, msg); err != nil { + if !strings.Contains(err.Error(), "closed connection") { + log.Error("Error while writing websocket message: %s", err) + return err + } + } + + return nil +} + +func (api *RestAPI) sendPing(ws *websocket.Conn) error { + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { + log.Error("Error while writing websocket ping message: %s", err) + return err + } + return nil +} + +func (api *RestAPI) streamWriter(ws *websocket.Conn, w http.ResponseWriter, r *http.Request) { + defer ws.Close() + + // first we stream what we already have + events := session.I.Events.Sorted() + n := len(events) + if n > 0 { + log.Debug("Sending %d events.", n) + for _, event := range events { + if err := api.streamEvent(ws, event); err != nil { + return + } + } + } + + session.I.Events.Clear() + + log.Debug("Listening for events and streaming to ws endpoint ...") + + pingTicker := time.NewTicker(pingPeriod) + + for { + select { + case <-pingTicker.C: + if err := api.sendPing(ws); err != nil { + return + } + case event := <-api.eventListener: + if err := api.streamEvent(ws, event); err != nil { + return + } + case <-api.quit: + log.Info("Stopping websocket events streamer ...") + return + } + } +} + +func (api *RestAPI) streamReader(ws *websocket.Conn) { + defer ws.Close() + ws.SetReadLimit(512) + ws.SetReadDeadline(time.Now().Add(pongWait)) + ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) + for { + _, _, err := ws.ReadMessage() + if err != nil { + log.Debug("Closing websocket reader.") + break + } + } +} + +func (api *RestAPI) startStreamingEvents(w http.ResponseWriter, r *http.Request) { + ws, err := api.upgrader.Upgrade(w, r, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + log.Error("Error while updating api.rest connection to websocket: %s", err) + } + return + } + + log.Debug("Websocket streaming started for %s", r.RemoteAddr) + + go api.streamWriter(ws, w, r) + api.streamReader(ws) +} From db32cc42eb0afa2c60923a27cace721a435a9332 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:46:03 +0100 Subject: [PATCH 13/18] refact: updated Dockerfile as gopacket static build is no longer used. --- Dockerfile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b23568f..d05fc8d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,13 +3,8 @@ FROM golang:1.10-alpine AS build-env ENV GOPATH=/gocode ENV SRC_DIR=/gocode/src/github.com/bettercap/bettercap -# As Alpine Linux uses a different folder, we need this -# ugly hack in order to compile gopacket statically -# https://github.com/bettercap/bettercap/issues/106 -RUN apk add --update ca-certificates && \ -apk add --no-cache --update bash iptables wireless-tools build-base libpcap-dev git python py-six && \ -mkdir -p /usr/lib/x86_64-linux-gnu/ && \ -cp /usr/lib/libpcap.a /usr/lib/x86_64-linux-gnu/libpcap.a +RUN apk add --update ca-certificates +RUN apk add --no-cache --update bash iptables wireless-tools build-base libpcap-dev git python py-six WORKDIR $SRC_DIR ADD . $SRC_DIR From a8c569e2782261bb58ec9f87c4fdd8b3ebadce56 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:47:56 +0100 Subject: [PATCH 14/18] misc: small fix or general refactoring i did not bother commenting --- ISSUE_TEMPLATE.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 95326b50..77622d81 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,9 +1,6 @@ ### Prerequisites -* [ ] I read the [README](https://github.com/bettercap/bettercap/blob/master/README.md). -* [ ] I am running the [latest stable version](https://github.com/bettercap/bettercap/releases). -* [ ] I already searched [other issues](https://github.com/bettercap/bettercap/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if this problem was already reported. -* [ ] I understand I don't necessarily have to paste this `Prerequisites` section in the issue. +Please, before creating this issue make sure that you read the [README](https://github.com/bettercap/bettercap/blob/master/README.md), that you are running the [latest stable version](https://github.com/bettercap/bettercap/releases) and that you already searched [other issues](https://github.com/bettercap/bettercap/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if your problem or request was already reported. ### Description @@ -17,8 +14,7 @@ Please provide: * OS version and architecture you are using. * Go version if building from sources. * Command line arguments you are using. -* Caplet code you are using (if any). -* Interactive session commands you are using (if any). +* Caplet code you are using or the interactive session commands. * **Full debug output** while reproducing the issue ( `bettercap -debug ...` ). ### Steps to Reproduce From a3a8839372a6410c4bdd468fa42b651f77408f00 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:49:08 +0100 Subject: [PATCH 15/18] misc: small fix or general refactoring i did not bother commenting --- ISSUE_TEMPLATE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 77622d81..6a6f0021 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -2,6 +2,8 @@ Please, before creating this issue make sure that you read the [README](https://github.com/bettercap/bettercap/blob/master/README.md), that you are running the [latest stable version](https://github.com/bettercap/bettercap/releases) and that you already searched [other issues](https://github.com/bettercap/bettercap/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if your problem or request was already reported. +You an cut out this part and leave the next sections in your report. + ### Description *Description of the bug or feature request* From 72ac7e63fc7c71236fafc162ccdef8962aed03b2 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:50:44 +0100 Subject: [PATCH 16/18] misc: small fix or general refactoring i did not bother commenting --- ISSUE_TEMPLATE.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 6a6f0021..ff3d01ea 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,10 +1,9 @@ -### Prerequisites +# Prerequisites Please, before creating this issue make sure that you read the [README](https://github.com/bettercap/bettercap/blob/master/README.md), that you are running the [latest stable version](https://github.com/bettercap/bettercap/releases) and that you already searched [other issues](https://github.com/bettercap/bettercap/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if your problem or request was already reported. -You an cut out this part and leave the next sections in your report. - -### Description +! PLEASE REMOVE THIS PART AND LEAVE ONLY THE FOLLOWING SECTIONS IN YOUR REPORT ! +--- *Description of the bug or feature request* From 5727fa3c56d8054e15d7c4ccc1cc51705954f8c4 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 14:59:27 +0100 Subject: [PATCH 17/18] new: modules enabled by default can now be controlled with the -autostart argument --- core/core.go | 11 +++++++++++ core/options.go | 2 ++ main.go | 9 ++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/core/core.go b/core/core.go index 2a212c03..5706001a 100644 --- a/core/core.go +++ b/core/core.go @@ -41,6 +41,17 @@ func UniqueInts(a []int, sorted bool) []int { return uniq } +func CommaSplit(csv string) []string { + filtered := make([]string, 0) + for _, part := range strings.Split(csv, ",") { + part = Trim(part) + if part != "" { + filtered = append(filtered, part) + } + } + return filtered +} + func ExecSilent(executable string, args []string) (string, error) { path, err := exec.LookPath(executable) if err != nil { diff --git a/core/options.go b/core/options.go index 9dac88e8..261bf172 100644 --- a/core/options.go +++ b/core/options.go @@ -5,6 +5,7 @@ import "flag" type Options struct { InterfaceName *string Caplet *string + AutoStart *string Debug *bool Silent *bool NoColors *bool @@ -18,6 +19,7 @@ type Options struct { func ParseOptions() (Options, error) { o := Options{ InterfaceName: flag.String("iface", "", "Network interface to bind to, if empty the default interface will be auto selected."), + AutoStart: flag.String("autostart", "events.stream, net.recon", "Comma separated list of modules to auto start."), Caplet: flag.String("caplet", "", "Read commands from this file and execute them in the interactive session."), Debug: flag.Bool("debug", false, "Print debug messages."), Silent: flag.Bool("silent", false, "Suppress all logs which are not errors."), diff --git a/main.go b/main.go index 116d48d2..168a391f 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,6 @@ import ( var sess *session.Session var err error -// Some modules are enabled by default in order -// to make the interactive session useful. var autoEnableList = []string{ "events.stream", "net.recon", @@ -75,10 +73,11 @@ func main() { } } - // Start modules that are enabled by default. - for _, modName := range autoEnableList { + // Some modules are enabled by default in order + // to make the interactive session useful. + for _, modName := range core.CommaSplit(*sess.Options.AutoStart) { if err = sess.Run(modName + " on"); err != nil { - log.Fatal("Error while starting module %s: %", modName, err) + log.Fatal("Error while starting module %s: %s", modName, err) } } From 892eff56a602301e8d2068074a59843c91cbba51 Mon Sep 17 00:00:00 2001 From: evilsocket Date: Tue, 13 Mar 2018 15:03:11 +0100 Subject: [PATCH 18/18] misc: small fix or general refactoring i did not bother commenting --- main.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/main.go b/main.go index 168a391f..9dc1e5a6 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ func main() { fmt.Println(err) os.Exit(1) } + defer sess.Close() if core.HasColors == false { if *sess.Options.NoColors == true { @@ -104,9 +105,4 @@ func main() { } } } - - sess.Close() - - // Windows requires this otherwise the app never exits ... - os.Exit(0) }