diff --git a/modules/wifi_recon.go b/modules/wifi_recon.go index 87019894..f0f848c0 100644 --- a/modules/wifi_recon.go +++ b/modules/wifi_recon.go @@ -154,6 +154,9 @@ func (w *WiFiRecon) getRow(station *network.Station) []string { } encryption := station.Encryption + if len(station.Cipher) > 0 { + encryption = fmt.Sprintf("%s [%s,%s]", station.Encryption, station.Cipher, station.Authentication) + } if encryption == "OPEN" || encryption == "" { encryption = core.Green("OPEN") } @@ -508,10 +511,12 @@ func (w *WiFiRecon) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) { } } - if ok, enc := packets.Dot11ParseEncryption(packet, dot11); ok == true { + if ok, enc, cipher, auth := packets.Dot11ParseEncryption(packet, dot11); ok == true { bssid := dot11.Address3.String() if station, found := w.Session.WiFi.Get(bssid); found == true { station.Encryption = enc + station.Cipher = cipher + station.Authentication = auth } } } diff --git a/network/wifi_station.go b/network/wifi_station.go index 06f7cee5..48b0a768 100644 --- a/network/wifi_station.go +++ b/network/wifi_station.go @@ -6,11 +6,13 @@ import ( type Station struct { *Endpoint - Frequency int `json:"frequency"` - RSSI int8 `json:"rssi"` - Sent uint64 `json:"sent"` - Received uint64 `json:"received"` - Encryption string `json:"encryption"` + Frequency int `json:"frequency"` + RSSI int8 `json:"rssi"` + Sent uint64 `json:"sent"` + Received uint64 `json:"received"` + Encryption string `json:"encryption"` + Cipher string `json:"cipher"` + Authentication string `json:"authentication"` } func cleanESSID(essid string) string { diff --git a/packets/dot11.go b/packets/dot11.go index 00f4a799..74689466 100644 --- a/packets/dot11.go +++ b/packets/dot11.go @@ -2,12 +2,160 @@ package packets import ( "bytes" + "encoding/binary" + "fmt" "net" "github.com/google/gopacket" "github.com/google/gopacket/layers" ) +type Dot11CipherType uint8 + +const ( + Dot11CipherWep Dot11CipherType = 1 + Dot11CipherTkip Dot11CipherType = 2 + Dot11CipherWrap Dot11CipherType = 3 + Dot11CipherCcmp Dot11CipherType = 4 + Dot11CipherWep104 Dot11CipherType = 5 +) + +func (a Dot11CipherType) String() string { + switch a { + case Dot11CipherWep: + return "WEP" + case Dot11CipherTkip: + return "TKIP" + case Dot11CipherWrap: + return "WRAP" + case Dot11CipherCcmp: + return "CCMP" + case Dot11CipherWep104: + return "WEP104" + default: + return "UNK" + } +} + +type Dot11AuthType uint8 + +const ( + Dot11AuthMgt Dot11AuthType = 1 + Dot11AuthPsk Dot11AuthType = 2 +) + +func (a Dot11AuthType) String() string { + switch a { + case Dot11AuthMgt: + return "MGT" + case Dot11AuthPsk: + return "PSK" + default: + return "UNK" + } +} + +type CipherSuite struct { + OUI []byte // 3 bytes + Type Dot11CipherType +} + +type AuthSuite struct { + OUI []byte // 3 bytes + Type Dot11AuthType +} + +type CipherSuiteSelector struct { + Count uint16 + Suites []CipherSuite +} +type AuthSuiteSelector struct { + Count uint16 + Suites []AuthSuite +} + +type VendorInfo struct { + WPAVersion uint16 + Multicast CipherSuite + Unicast CipherSuiteSelector + AuthKey AuthSuiteSelector +} + +type RSNInfo struct { + Version uint16 + Group CipherSuite + Pairwise CipherSuiteSelector + AuthKey AuthSuiteSelector +} + +func Dot11InformationElementVendorInfoDecode(vendorInfo []byte) (VendorInfo, error) { + var v VendorInfo + var i uint16 + if len(vendorInfo) < 15 { + return v, fmt.Errorf("VendorInfo packet length %v too short, %v required", len(vendorInfo), 15) + } + + v.WPAVersion = binary.LittleEndian.Uint16(vendorInfo[0:2]) + v.Multicast.OUI = vendorInfo[2:5] + v.Multicast.Type = Dot11CipherType(vendorInfo[5]) + + v.Unicast.Count = binary.LittleEndian.Uint16(vendorInfo[6:8]) + + p := 8 + for i = 0; i < v.Unicast.Count && p < len(vendorInfo); i++ { + var suite CipherSuite + suite.OUI = vendorInfo[p : p+3] + suite.Type = Dot11CipherType(vendorInfo[p+3]) + v.Unicast.Suites = append(v.Unicast.Suites, suite) + p = p + 4 + } + + v.AuthKey.Count = binary.LittleEndian.Uint16(vendorInfo[p : p+2]) + p = p + 2 + for i = 0; i < v.AuthKey.Count && p < len(vendorInfo); i++ { + var suite AuthSuite + suite.OUI = vendorInfo[p : p+3] + suite.Type = Dot11AuthType(vendorInfo[p+3]) + v.AuthKey.Suites = append(v.AuthKey.Suites, suite) + p = p + 4 + } + + return v, nil +} + +func Dot11InformationElementRSNInfoDecode(info []byte) (RSNInfo, error) { + var rsn RSNInfo + if len(info) < 20 { + return rsn, fmt.Errorf("RSNInfo packet length %v too short, %v required", len(info), 20) + } + + rsn.Version = binary.LittleEndian.Uint16(info[0:2]) + rsn.Group.OUI = info[2:5] + rsn.Group.Type = Dot11CipherType(info[5]) + rsn.Pairwise.Count = binary.LittleEndian.Uint16(info[6:8]) + + p := 8 + for i := uint16(0); i < rsn.Pairwise.Count && p < len(info); i++ { + var suite CipherSuite + suite.OUI = info[p : p+3] + suite.Type = Dot11CipherType(info[p+3]) + rsn.Pairwise.Suites = append(rsn.Pairwise.Suites, suite) + p = p + 4 + } + + rsn.AuthKey.Count = binary.LittleEndian.Uint16(info[p : p+2]) + p = p + 2 + for i := uint16(0); i < rsn.AuthKey.Count && p < len(info); i++ { + var suite AuthSuite + suite.OUI = info[p : p+3] + suite.Type = Dot11AuthType(info[p+3]) + rsn.AuthKey.Suites = append(rsn.AuthKey.Suites, suite) + p = p + 4 + } + + return rsn, nil +} + func NewDot11Deauth(a1 net.HardwareAddr, a2 net.HardwareAddr, a3 net.HardwareAddr, seq uint16) (error, []byte) { return Serialize( &layers.RadioTap{}, @@ -64,8 +212,11 @@ func Dot11ParseIDSSID(packet gopacket.Packet) (bool, string) { return false, "" } -func Dot11ParseEncryption(packet gopacket.Packet, dot11 *layers.Dot11) (bool, string) { +func Dot11ParseEncryption(packet gopacket.Packet, dot11 *layers.Dot11) (bool, string, string, string) { + var i uint16 enc := "" + cipher := "" + auth := "" found := false if dot11.Flags.WEP() { @@ -80,8 +231,26 @@ func Dot11ParseEncryption(packet gopacket.Packet, dot11 *layers.Dot11) (bool, st found = true if info.ID == layers.Dot11InformationElementIDRSNInfo { enc = "WPA2" + rsn, err := Dot11InformationElementRSNInfoDecode(info.Info) + if err == nil { + for i = 0; i < rsn.Pairwise.Count; i++ { + cipher = rsn.Pairwise.Suites[i].Type.String() + } + for i = 0; i < rsn.AuthKey.Count; i++ { + auth = rsn.AuthKey.Suites[i].Type.String() + } + } } else if enc == "" && info.ID == layers.Dot11InformationElementIDVendor && info.Length >= 8 && bytes.Compare(info.OUI, []byte{0, 0x50, 0xf2, 1}) == 0 && bytes.HasPrefix(info.Info, []byte{1, 0}) { enc = "WPA" + vendor, err := Dot11InformationElementVendorInfoDecode(info.Info) + if err == nil { + for i = 0; i < vendor.Unicast.Count; i++ { + cipher = vendor.Unicast.Suites[i].Type.String() + } + for i = 0; i < vendor.AuthKey.Count; i++ { + auth = vendor.AuthKey.Suites[i].Type.String() + } + } } } } @@ -91,7 +260,7 @@ func Dot11ParseEncryption(packet gopacket.Packet, dot11 *layers.Dot11) (bool, st enc = "OPEN" } - return found, enc + return found, enc, cipher, auth }