mirror of
https://github.com/bettercap/bettercap.git
synced 2024-09-16 05:30:21 -07:00
272 lines
5.8 KiB
Go
272 lines
5.8 KiB
Go
package packets
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
type Dot11CipherType uint8
|
|
|
|
func (a Dot11CipherType) String() string {
|
|
switch a {
|
|
case 0:
|
|
return "NONE"
|
|
case 1:
|
|
return "WEP-40-bit"
|
|
case 2:
|
|
return "TKIP"
|
|
case 3:
|
|
return "AES-OCB"
|
|
case 4:
|
|
return "AES-CCM"
|
|
case 5:
|
|
return "WEP-104-bit"
|
|
case 6:
|
|
return "BIP-128"
|
|
case 7:
|
|
return "Group addressed traffic not allowed"
|
|
case 8:
|
|
return "GCMP-128"
|
|
case 9:
|
|
return "GCMP-256"
|
|
case 10:
|
|
return "CCMP-256"
|
|
case 11:
|
|
return "BIP-GMAC-128"
|
|
case 12:
|
|
return "BIP-GMAC-256"
|
|
case 13:
|
|
return "BIP-CMAC-256"
|
|
default:
|
|
return fmt.Sprintf("CIPHER %d", a)
|
|
}
|
|
}
|
|
|
|
type Dot11AuthType uint8
|
|
|
|
func (a Dot11AuthType) String() string {
|
|
// https://raw.githubusercontent.com/wireshark/wireshark/master/epan/dissectors/packet-ieee80211.c
|
|
switch a {
|
|
case 0:
|
|
return "NONE"
|
|
case 1:
|
|
return "WPA"
|
|
case 2:
|
|
return "PSK"
|
|
case 3:
|
|
return "FT over IEEE 802.1X"
|
|
case 4:
|
|
return "FT using PSK"
|
|
case 5:
|
|
return "WPA (SHA256)"
|
|
case 6:
|
|
return "PSK (SHA256)"
|
|
case 7:
|
|
return "TDLS / TPK Handshake (SHA256)"
|
|
case 8:
|
|
return "SAE (SHA256)"
|
|
case 9:
|
|
return "FT using SAE (SHA256)"
|
|
case 10:
|
|
return "APPeerKey (SHA256)"
|
|
case 11:
|
|
return "WPA (SHA256-SuiteB)"
|
|
case 12:
|
|
return "WPA (SHA384-SuiteB)"
|
|
case 13:
|
|
return "FT over IEEE 802.1X (SHA384)"
|
|
case 14:
|
|
return "FILS (SHA256 and AES-SIV-256)"
|
|
case 15:
|
|
return "FILS (SHA384 and AES-SIV-512)"
|
|
case 16:
|
|
return "FT over FILS (SHA256 and AES-SIV-256)"
|
|
case 17:
|
|
return "FT over FILS (SHA384 and AES-SIV-512)"
|
|
case 18:
|
|
return "Opportunistic Wireless Encryption"
|
|
case 19:
|
|
return "FT using PSK (SHA384)"
|
|
case 20:
|
|
return "PSK (SHA384)"
|
|
case 21:
|
|
return "PASN"
|
|
case 24:
|
|
return "SAE (GROUP-DEPEND)"
|
|
case 25:
|
|
return "FT using SAE (GROUP-DEPEND)"
|
|
default:
|
|
return fmt.Sprintf("AUTH %d", a)
|
|
}
|
|
}
|
|
|
|
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 RSNInfo struct {
|
|
Version uint16
|
|
Group CipherSuite
|
|
Pairwise CipherSuiteSelector
|
|
AuthKey AuthSuiteSelector
|
|
}
|
|
|
|
type VendorInfo struct {
|
|
WPAVersion uint16
|
|
Multicast CipherSuite
|
|
Unicast CipherSuiteSelector
|
|
AuthKey AuthSuiteSelector
|
|
}
|
|
|
|
func canParse(what string, buf []byte, need int) error {
|
|
available := len(buf)
|
|
if need > available {
|
|
return fmt.Errorf("Malformed 802.11 packet, could not parse %s: needed %d bytes but only %d are available.", what, need, available)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parsePairwiseSuite(buf []byte) (suite CipherSuite, err error) {
|
|
if err = canParse("RSN.Pairwise.Suite", buf, 4); err == nil {
|
|
suite.OUI = buf[0:3]
|
|
suite.Type = Dot11CipherType(buf[3])
|
|
}
|
|
return
|
|
}
|
|
|
|
func parseAuthkeySuite(buf []byte) (suite AuthSuite, err error) {
|
|
if err = canParse("RSN.AuthKey.Suite", buf, 4); err == nil {
|
|
suite.OUI = buf[0:3]
|
|
suite.Type = Dot11AuthType(buf[3])
|
|
}
|
|
return
|
|
}
|
|
|
|
func Dot11InformationElementVendorInfoDecode(buf []byte) (v VendorInfo, err error) {
|
|
if err = canParse("Vendor", buf, 8); err == nil {
|
|
v.WPAVersion = binary.LittleEndian.Uint16(buf[0:2])
|
|
v.Multicast.OUI = buf[2:5]
|
|
v.Multicast.Type = Dot11CipherType(buf[5])
|
|
v.Unicast.Count = binary.LittleEndian.Uint16(buf[6:8])
|
|
buf = buf[8:]
|
|
} else {
|
|
v.Unicast.Count = 0
|
|
return
|
|
}
|
|
|
|
// check what we're left with
|
|
if err = canParse("Vendor.Unicast.Suites", buf, int(v.Unicast.Count)*4); err == nil {
|
|
for i := uint16(0); i < v.Unicast.Count; i++ {
|
|
if suite, err := parsePairwiseSuite(buf); err == nil {
|
|
v.Unicast.Suites = append(v.Unicast.Suites, suite)
|
|
buf = buf[4:]
|
|
} else {
|
|
return v, err
|
|
}
|
|
}
|
|
} else {
|
|
v.Unicast.Count = 0
|
|
return
|
|
}
|
|
|
|
if err = canParse("Vendor.AuthKey.Count", buf, 2); err == nil {
|
|
v.AuthKey.Count = binary.LittleEndian.Uint16(buf[0:2])
|
|
buf = buf[2:]
|
|
} else {
|
|
v.AuthKey.Count = 0
|
|
return
|
|
}
|
|
|
|
// just like before, check if we have enough data
|
|
if err = canParse("Vendor.AuthKey.Suites", buf, int(v.AuthKey.Count)*4); err == nil {
|
|
for i := uint16(0); i < v.AuthKey.Count; i++ {
|
|
if suite, err := parseAuthkeySuite(buf); err == nil {
|
|
v.AuthKey.Suites = append(v.AuthKey.Suites, suite)
|
|
buf = buf[4:]
|
|
} else {
|
|
return v, err
|
|
}
|
|
}
|
|
} else {
|
|
v.AuthKey.Count = 0
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Dot11InformationElementRSNInfoDecode(buf []byte) (rsn RSNInfo, err error) {
|
|
if err = canParse("RSN", buf, 8); err == nil {
|
|
rsn.Version = binary.LittleEndian.Uint16(buf[0:2])
|
|
rsn.Group.OUI = buf[2:5]
|
|
rsn.Group.Type = Dot11CipherType(buf[5])
|
|
rsn.Pairwise.Count = binary.LittleEndian.Uint16(buf[6:8])
|
|
buf = buf[8:]
|
|
} else {
|
|
rsn.Pairwise.Count = 0
|
|
return
|
|
}
|
|
|
|
// check what we're left with
|
|
if err = canParse("RSN.Pairwise.Suites", buf, int(rsn.Pairwise.Count)*4); err == nil {
|
|
for i := uint16(0); i < rsn.Pairwise.Count; i++ {
|
|
if suite, err := parsePairwiseSuite(buf); err == nil {
|
|
rsn.Pairwise.Suites = append(rsn.Pairwise.Suites, suite)
|
|
buf = buf[4:]
|
|
} else {
|
|
return rsn, err
|
|
}
|
|
}
|
|
} else {
|
|
rsn.Pairwise.Count = 0
|
|
return
|
|
}
|
|
|
|
if err = canParse("RSN.AuthKey.Count", buf, 2); err == nil {
|
|
rsn.AuthKey.Count = binary.LittleEndian.Uint16(buf[0:2])
|
|
buf = buf[2:]
|
|
} else {
|
|
rsn.AuthKey.Count = 0
|
|
return
|
|
}
|
|
|
|
// just like before, check if we have enough data
|
|
if err = canParse("RSN.AuthKey.Suites", buf, int(rsn.AuthKey.Count)*4); err == nil {
|
|
for i := uint16(0); i < rsn.AuthKey.Count; i++ {
|
|
if suite, err := parseAuthkeySuite(buf); err == nil {
|
|
rsn.AuthKey.Suites = append(rsn.AuthKey.Suites, suite)
|
|
buf = buf[4:]
|
|
} else {
|
|
return rsn, err
|
|
}
|
|
}
|
|
} else {
|
|
rsn.AuthKey.Count = 0
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Dot11InformationElementIDDSSetDecode(buf []byte) (channel int, err error) {
|
|
if err = canParse("DSSet.channel", buf, 1); err == nil {
|
|
channel = int(buf[0])
|
|
}
|
|
|
|
return
|
|
}
|