bettercap/network/wifi_handshake.go

142 lines
2.8 KiB
Go

package network
import (
"sync"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
type Handshake struct {
sync.RWMutex
Beacon gopacket.Packet
Challenges []gopacket.Packet
Responses []gopacket.Packet
Confirmations []gopacket.Packet
hasPMKID bool
unsaved []gopacket.Packet
}
func NewHandshake() *Handshake {
return &Handshake{
Challenges: make([]gopacket.Packet, 0),
Responses: make([]gopacket.Packet, 0),
Confirmations: make([]gopacket.Packet, 0),
unsaved: make([]gopacket.Packet, 0),
}
}
func (h *Handshake) SetBeacon(pkt gopacket.Packet) {
h.Lock()
defer h.Unlock()
if h.Beacon == nil {
h.Beacon = pkt
h.unsaved = append(h.unsaved, pkt)
}
}
func (h *Handshake) AddAndGetPMKID(pkt gopacket.Packet) []byte {
h.AddFrame(0, pkt)
prevWasKey := false
for _, layer := range pkt.Layers() {
if layer.LayerType() == layers.LayerTypeEAPOLKey {
prevWasKey = true
continue
}
if prevWasKey && layer.LayerType() == layers.LayerTypeDot11InformationElement {
info := layer.(*layers.Dot11InformationElement)
if info.ID == layers.Dot11InformationElementIDVendor && info.Length == 20 {
h.Lock()
defer h.Unlock()
h.hasPMKID = true
return info.Info
}
}
prevWasKey = false
}
return nil
}
func (h *Handshake) AddFrame(n int, pkt gopacket.Packet) {
h.Lock()
defer h.Unlock()
switch n {
case 0:
h.Challenges = append(h.Challenges, pkt)
case 1:
h.Responses = append(h.Responses, pkt)
case 2:
h.Confirmations = append(h.Confirmations, pkt)
}
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()
nChal := len(h.Challenges)
nResp := len(h.Responses)
nConf := len(h.Confirmations)
return nChal > 0 && nResp > 0 && nConf > 0
}
func (h *Handshake) Half() bool {
h.RLock()
defer h.RUnlock()
/*
* You can use every combination of the handshake to crack the net:
* M1/M2
* M2/M3
* M3/M4
* M1/M4 (if M4 snonce is not zero)
* We only have M1 (the challenge), M2 (the response) and M3 (the confirmation)
*/
nChal := len(h.Challenges)
nResp := len(h.Responses)
nConf := len(h.Confirmations)
return (nChal > 0 && nResp > 0) || (nResp > 0 && nConf > 0)
}
func (h *Handshake) HasPMKID() bool {
h.RLock()
defer h.RUnlock()
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()
return len(h.unsaved)
}
func (h *Handshake) EachUnsavedPacket(cb func(gopacket.Packet)) {
h.Lock()
defer h.Unlock()
for _, pkt := range h.unsaved {
cb(pkt)
}
h.unsaved = make([]gopacket.Packet, 0)
}