diff --git a/modules/wifi/wifi_recon_handshakes.go b/modules/wifi/wifi_recon_handshakes.go index a5e2fc96..e06b6ab3 100644 --- a/modules/wifi/wifi_recon_handshakes.go +++ b/modules/wifi/wifi_recon_handshakes.go @@ -3,6 +3,8 @@ package wifi import ( "bytes" "fmt" + "github.com/bettercap/bettercap/network" + "net" "path" "github.com/bettercap/bettercap/packets" @@ -21,7 +23,11 @@ func allZeros(s []byte) bool { } func (mod *WiFiModule) discoverHandshakes(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) { + isEAPOL := false + if ok, key, apMac, staMac := packets.Dot11ParseEAPOL(packet, dot11); ok { + isEAPOL = true + // first, locate the AP in our list by its BSSID ap, found := mod.Session.WiFi.Get(apMac.String()) if !found { @@ -126,4 +132,60 @@ func (mod *WiFiModule) discoverHandshakes(radiotap *layers.RadioTap, dot11 *laye ap.RemoveClient(staMac.String()) } } + + // quick and dirty heuristic, see thread here https://github.com/bettercap/bettercap/issues/810#issuecomment-805145392 + if isEAPOL || (dot11.Type.MainType() != layers.Dot11TypeData && dot11.Type.MainType() != layers.Dot11TypeCtrl) { + target := (* network.Station)(nil) + targetAP := (* network.AccessPoint)(nil) + + // collect target bssids + bssids := make([]net.HardwareAddr, 0) + for _, addr := range []net.HardwareAddr{dot11.Address1, dot11.Address2, dot11.Address3, dot11.Address4} { + if bytes.Equal(addr, network.BroadcastHw) == false { + bssids = append(bssids, addr) + } + } + + // for each AP + mod.Session.WiFi.EachAccessPoint(func(mac string, ap *network.AccessPoint) { + // only check APs we captured handshakes of + if target == nil && ap.HasKeyMaterial() { + // search client station + ap.EachClient(func(mac string, station *network.Station) { + // any valid key material for this station? + if station.Handshake.Any() { + // check if target + for _, a := range bssids { + if bytes.Equal(a, station.HW) { + target = station + targetAP = ap + break + } + } + } + }) + } + }) + + if target != nil { + mod.Info("saving extra %s frame (%d bytes) for %s", + dot11.Type.String(), + len(packet.Data()), + target.String()) + + target.Handshake.AddExtra(packet) + + shakesFileName := mod.shakesFile + if mod.shakesAggregate == false { + shakesFileName = path.Join(shakesFileName, fmt.Sprintf("%s.pcap", targetAP.PathFriendlyName())) + } + if shakesFileName != "" { + mod.Debug("(aggregate %v) saving handshake frames to %s", mod.shakesAggregate, shakesFileName) + if err := mod.Session.WiFi.SaveHandshakesTo(shakesFileName, mod.handle.LinkType()); err != nil { + mod.Error("error while saving handshake frames to %s: %s", shakesFileName, err) + } + } + } + } + } diff --git a/network/wifi.go b/network/wifi.go index 4983cce8..f6c6e1ce 100644 --- a/network/wifi.go +++ b/network/wifi.go @@ -245,7 +245,7 @@ func (w *WiFi) SaveHandshakesTo(fileName string, linkType layers.LinkType) error for _, ap := range w.aps { for _, station := range ap.Clients() { // if half (which includes also complete) or has pmkid - if station.Handshake.Half() || station.Handshake.HasPMKID() { + if station.Handshake.Any() { err = nil station.Handshake.EachUnsavedPacket(func(pkt gopacket.Packet) { if err == nil { diff --git a/network/wifi_handshake.go b/network/wifi_handshake.go index 7181baec..29c3305b 100644 --- a/network/wifi_handshake.go +++ b/network/wifi_handshake.go @@ -79,6 +79,12 @@ func (h *Handshake) AddFrame(n int, pkt gopacket.Packet) { h.unsaved = append(h.unsaved, pkt) } +func (h *Handshake) AddExtra(pkt gopacket.Packet) { + h.Lock() + defer h.Unlock() + h.unsaved = append(h.unsaved, pkt) +} + func (h *Handshake) Complete() bool { h.RLock() defer h.RUnlock() @@ -115,6 +121,10 @@ func (h *Handshake) HasPMKID() bool { return h.hasPMKID } +func (h *Handshake) Any() bool { + return h.HasPMKID() || h.Half() || h.Complete() +} + func (h *Handshake) NumUnsaved() int { h.RLock() defer h.RUnlock()