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 +}