mirror of
https://github.com/bettercap/bettercap
synced 2025-08-21 14:03:17 -07:00
new: added native wifi handshakes capture from wifi.recon module
This commit is contained in:
parent
23f340d8eb
commit
a6cfb2413f
9 changed files with 273 additions and 30 deletions
|
@ -77,6 +77,19 @@ func (s *EventsStream) viewWiFiEvent(e session.Event) {
|
|||
tui.Dim(desc),
|
||||
tui.Bold(probe.SSID),
|
||||
tui.Yellow(rssi))
|
||||
} else if e.Tag == "wifi.client.handshake" {
|
||||
hand := e.Data.(WiFiHandshakeEvent)
|
||||
ss := "s"
|
||||
if hand.NewPackets == 1 {
|
||||
ss = ""
|
||||
}
|
||||
fmt.Fprintf(s.output, "[%s] [%s] captured a full handshake for station %s and AP %s (saved %d new packet%s to %s)\n",
|
||||
e.Time.Format(eventTimeFormat),
|
||||
tui.Green(e.Tag),
|
||||
hand.Station.String(),
|
||||
hand.AP.String(),
|
||||
hand.NewPackets, ss,
|
||||
hand.File)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcap"
|
||||
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
|
@ -35,6 +36,7 @@ type WiFiModule struct {
|
|||
pktSourceChanClosed bool
|
||||
deauthSkip []net.HardwareAddr
|
||||
deauthSilent bool
|
||||
shakesFile string
|
||||
apRunning bool
|
||||
apConfig packets.Dot11ApConfig
|
||||
writes *sync.WaitGroup
|
||||
|
@ -123,6 +125,11 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
|
|||
}
|
||||
}))
|
||||
|
||||
w.AddParam(session.NewStringParameter("wifi.handshakes.file",
|
||||
"~/bettercap-wifi-handshakes.pcap",
|
||||
"",
|
||||
"File path of the pcap file to save handshakes to."))
|
||||
|
||||
w.AddParam(session.NewStringParameter("wifi.ap.ssid",
|
||||
"FreeWiFi",
|
||||
"",
|
||||
|
@ -221,6 +228,14 @@ func (w *WiFiModule) Configure() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err, w.shakesFile = w.StringParam("wifi.handshakes.file"); err != nil {
|
||||
return err
|
||||
} else if w.shakesFile != "" {
|
||||
if w.shakesFile, err = fs.Expand(w.shakesFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if w.source != "" {
|
||||
if w.handle, err = pcap.OpenOffline(w.source); err != nil {
|
||||
return err
|
||||
|
@ -353,6 +368,7 @@ func (w *WiFiModule) Start() error {
|
|||
w.discoverProbes(radiotap, dot11, packet)
|
||||
w.discoverAccessPoints(radiotap, dot11, packet)
|
||||
w.discoverClients(radiotap, dot11, packet)
|
||||
w.discoverHandshakes(radiotap, dot11, packet)
|
||||
w.updateInfo(dot11, packet)
|
||||
w.updateStats(dot11, packet)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
var maxStationTTL = 5 * time.Minute
|
||||
|
@ -23,6 +25,13 @@ type WiFiProbe struct {
|
|||
RSSI int8
|
||||
}
|
||||
|
||||
type WiFiHandshakeEvent struct {
|
||||
File string
|
||||
NewPackets int
|
||||
AP net.HardwareAddr
|
||||
Station net.HardwareAddr
|
||||
}
|
||||
|
||||
func (w *WiFiModule) stationPruner() {
|
||||
w.reads.Add(1)
|
||||
defer w.reads.Done()
|
||||
|
@ -121,3 +130,76 @@ func (w *WiFiModule) discoverClients(radiotap *layers.RadioTap, dot11 *layers.Do
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func allZeros(s []byte) bool {
|
||||
for _, v := range s {
|
||||
if v != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WiFiModule) discoverHandshakes(radiotap *layers.RadioTap, dot11 *layers.Dot11, packet gopacket.Packet) {
|
||||
if keyLayer := packet.Layer(layers.LayerTypeEAPOLKey); keyLayer != nil {
|
||||
if key := keyLayer.(*layers.EAPOLKey); key.KeyType == layers.EAPOLKeyTypePairwise {
|
||||
staMac := net.HardwareAddr{}
|
||||
apMac := net.HardwareAddr{}
|
||||
if dot11.Flags.FromDS() {
|
||||
staMac = dot11.Address1
|
||||
apMac = dot11.Address2
|
||||
} else if dot11.Flags.ToDS() {
|
||||
staMac = dot11.Address2
|
||||
apMac = dot11.Address1
|
||||
}
|
||||
|
||||
if station, found := w.Session.WiFi.GetClient(staMac.String()); found {
|
||||
// ref. https://wlan1nde.wordpress.com/2014/10/27/4-way-handshake/
|
||||
if !key.Install && key.KeyACK && !key.KeyMIC {
|
||||
// [1] (ACK) AP is sending ANonce to the client
|
||||
log.Debug("[%s] got frame 1/4 of the %s <-> %s handshake (anonce:%x)",
|
||||
tui.Green("wifi"),
|
||||
apMac,
|
||||
staMac,
|
||||
key.Nonce)
|
||||
station.Handshake.AddFrame(0, packet)
|
||||
} else if !key.Install && !key.KeyACK && key.KeyMIC && !allZeros(key.Nonce) {
|
||||
// [2] (MIC) client is sending SNonce+MIC to the API
|
||||
log.Debug("[%s] got frame 2/4 of the %s <-> %s handshake (snonce:%x mic:%x)",
|
||||
tui.Green("wifi"),
|
||||
apMac,
|
||||
staMac,
|
||||
key.Nonce,
|
||||
key.MIC)
|
||||
station.Handshake.AddFrame(1, packet)
|
||||
} else if key.Install && key.KeyACK && key.KeyMIC {
|
||||
// [3]: (INSTALL+ACK+MIC) AP informs the client that the PTK is installed
|
||||
log.Debug("[%s] got frame 3/4 of the %s <-> %s handshake (mic:%x)",
|
||||
tui.Green("wifi"),
|
||||
apMac,
|
||||
staMac,
|
||||
key.MIC)
|
||||
station.Handshake.AddFrame(2, packet)
|
||||
}
|
||||
|
||||
numUnsaved := station.Handshake.NumUnsaved()
|
||||
doSave := numUnsaved > 0
|
||||
if doSave && w.shakesFile != "" {
|
||||
log.Debug("saving handshake frames to %s", w.shakesFile)
|
||||
if err := w.Session.WiFi.SaveHandshakesTo(w.shakesFile, w.handle.LinkType()); err != nil {
|
||||
log.Error("error while saving handshake frames to %s: %s", w.shakesFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
if doSave && station.Handshake.Complete() {
|
||||
w.Session.Events.Add("wifi.client.handshake", WiFiHandshakeEvent{
|
||||
File: w.shakesFile,
|
||||
NewPackets: numUnsaved,
|
||||
AP: apMac,
|
||||
Station: staMac,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,11 +48,20 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
|
|||
if len(station.Cipher) > 0 {
|
||||
encryption = fmt.Sprintf("%s (%s, %s)", station.Encryption, station.Cipher, station.Authentication)
|
||||
}
|
||||
|
||||
if encryption == "OPEN" || encryption == "" {
|
||||
encryption = tui.Green("OPEN")
|
||||
ssid = tui.Green(ssid)
|
||||
bssid = tui.Green(bssid)
|
||||
} else {
|
||||
// this is ugly, but necessary in order to have this
|
||||
// method handle both access point and clients
|
||||
// transparently
|
||||
if ap, found := w.Session.WiFi.Get(station.HwAddress); found && ap.HasHandshakes() {
|
||||
encryption = tui.Red(encryption)
|
||||
}
|
||||
}
|
||||
|
||||
sent := ""
|
||||
if station.Sent > 0 {
|
||||
sent = humanize.Bytes(station.Sent)
|
||||
|
@ -318,7 +327,7 @@ func (w *WiFiModule) ShowWPS(bssid string) (err error) {
|
|||
fmt.Println()
|
||||
fmt.Printf("* %s (%s ch:%d):\n", tui.Bold(ssid), tui.Dim(station.BSSID()), station.Channel())
|
||||
keys := []string{}
|
||||
for name, _ := range station.WPS {
|
||||
for name := range station.WPS {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue