From 4726c2fc9d545f9904c332be9ea4717f7c2ced4a Mon Sep 17 00:00:00 2001 From: Matrix86 Date: Mon, 12 Mar 2018 16:06:51 +0100 Subject: [PATCH] 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 +}