mirror of
https://github.com/bettercap/bettercap
synced 2025-07-15 01:23:42 -07:00
229 lines
5.3 KiB
Go
229 lines
5.3 KiB
Go
package packets
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/google/gopacket"
|
|
"github.com/google/gopacket/layers"
|
|
)
|
|
|
|
type wpsAttrType int
|
|
|
|
const (
|
|
wpsHex wpsAttrType = 0
|
|
wpsStr wpsAttrType = 1
|
|
)
|
|
|
|
type wpsAttr struct {
|
|
Name string
|
|
Type wpsAttrType
|
|
Func func([]byte) string
|
|
Desc map[string]string
|
|
}
|
|
|
|
var (
|
|
wpsSignatureBytes = []byte{0x00, 0x50, 0xf2, 0x04}
|
|
wfaExtensionBytes = []byte{0x00, 0x37, 0x2a}
|
|
wpsVersion2ID = uint8(0x00)
|
|
|
|
wpsAttributes = map[uint16]wpsAttr{
|
|
0x104A: wpsAttr{Name: "Version", Desc: map[string]string{
|
|
"10": "1.0",
|
|
"11": "1.1",
|
|
}},
|
|
0x1044: wpsAttr{Name: "State", Desc: map[string]string{
|
|
"01": "Not Configured",
|
|
"02": "Configured",
|
|
}},
|
|
0x1012: wpsAttr{Name: "Device Password ID", Desc: map[string]string{
|
|
"0000": "Pin",
|
|
"0004": "PushButton",
|
|
}},
|
|
0x103B: wpsAttr{Name: "Response Type", Desc: map[string]string{
|
|
"00": "Enrollee Info",
|
|
"01": "Enrollee",
|
|
"02": "Registrar",
|
|
"03": "AP",
|
|
}},
|
|
0x1049: wpsAttr{Name: "Vendor Extension", Func: dot11ParseWPSVendorExtension},
|
|
0x1057: wpsAttr{Name: "AP Setup Locked"},
|
|
0x1041: wpsAttr{Name: "Selected Registrar"},
|
|
0x1047: wpsAttr{Name: "UUID-E"},
|
|
0x1021: wpsAttr{Name: "Manufacturer", Type: wpsStr},
|
|
0x1023: wpsAttr{Name: "Model Name", Type: wpsStr},
|
|
0x1024: wpsAttr{Name: "Model Number", Type: wpsStr},
|
|
0x1042: wpsAttr{Name: "Serial Number", Type: wpsStr},
|
|
0x1054: wpsAttr{Name: "Primary Device Type"},
|
|
0x1011: wpsAttr{Name: "Device Name", Type: wpsStr},
|
|
0x1053: wpsAttr{Name: "Selected Registrar Config Methods", Func: dot11ParseWPSConfigMethods},
|
|
0x1008: wpsAttr{Name: "Config Methods", Func: dot11ParseWPSConfigMethods},
|
|
0x103C: wpsAttr{Name: "RF Bands", Func: dott11ParseWPSBands},
|
|
0x1045: wpsAttr{Name: "SSID", Type: wpsStr},
|
|
0x102D: wpsAttr{Name: "OS Version", Type: wpsStr},
|
|
}
|
|
|
|
wpsConfigs = map[uint16]string{
|
|
0x0001: "USB",
|
|
0x0002: "Ethernet",
|
|
0x0004: "Label",
|
|
0x0008: "Display",
|
|
0x0010: "External NFC",
|
|
0x0020: "Internal NFC",
|
|
0x0040: "NFC Interface",
|
|
0x0080: "Push Button",
|
|
0x0100: "Keypad",
|
|
}
|
|
|
|
wpsBands = map[uint8]string{
|
|
0x01: "2.4Ghz",
|
|
0x02: "5.0Ghz",
|
|
}
|
|
)
|
|
|
|
func dott11ParseWPSBands(data []byte) string {
|
|
if len(data) == 1 {
|
|
mask := uint8(data[0])
|
|
bands := []string{}
|
|
|
|
for bit, band := range wpsBands {
|
|
if mask&bit != 0 {
|
|
bands = append(bands, band)
|
|
}
|
|
}
|
|
|
|
if len(bands) > 0 {
|
|
return strings.Join(bands, ", ")
|
|
}
|
|
}
|
|
|
|
return hex.EncodeToString(data)
|
|
}
|
|
|
|
func dot11ParseWPSConfigMethods(data []byte) string {
|
|
if len(data) == 2 {
|
|
mask := binary.BigEndian.Uint16(data)
|
|
configs := []string{}
|
|
|
|
for bit, conf := range wpsConfigs {
|
|
if mask&bit != 0 {
|
|
configs = append(configs, conf)
|
|
}
|
|
}
|
|
|
|
if len(configs) > 0 {
|
|
return strings.Join(configs, ", ")
|
|
}
|
|
}
|
|
|
|
return hex.EncodeToString(data)
|
|
}
|
|
|
|
func dot11ParseWPSVendorExtension(data []byte) string {
|
|
if len(data) > 3 && bytes.Equal(data[0:3], wfaExtensionBytes) {
|
|
size := len(data)
|
|
for offset := 3; offset < size; {
|
|
idByte := uint8(data[offset])
|
|
sizeByte := uint8(data[offset+1])
|
|
if idByte == wpsVersion2ID {
|
|
return fmt.Sprintf("version2=0x%x", data[offset+2])
|
|
}
|
|
offset += int(sizeByte) + 2
|
|
}
|
|
}
|
|
return hex.EncodeToString(data)
|
|
}
|
|
|
|
func wpsUint16At(data []byte, size int, offset *int) (bool, uint16) {
|
|
if *offset <= size-2 {
|
|
off := *offset
|
|
*offset += 2
|
|
return true, binary.BigEndian.Uint16(data[off:])
|
|
}
|
|
// fmt.Printf("uint16At( data(%d), off=%d )\n", size, *offset)
|
|
return false, 0
|
|
}
|
|
|
|
func wpsDataAt(data []byte, size int, offset *int, num int) (bool, []byte) {
|
|
max := size - num
|
|
if *offset <= max {
|
|
off := *offset
|
|
*offset += num
|
|
return true, data[off : off+num]
|
|
}
|
|
// fmt.Printf("dataAt( data(%d), off=%d, num=%d )\n", size, *offset, num)
|
|
return false, nil
|
|
}
|
|
|
|
func dot11ParseWPSTag(id uint16, size uint16, data []byte, info *map[string]string) {
|
|
name := ""
|
|
val := ""
|
|
|
|
if attr, found := wpsAttributes[id]; found {
|
|
name = attr.Name
|
|
if attr.Type == wpsStr {
|
|
val = string(data)
|
|
} else {
|
|
val = hex.EncodeToString(data)
|
|
}
|
|
|
|
if attr.Desc != nil {
|
|
if desc, found := attr.Desc[val]; found {
|
|
val = desc
|
|
}
|
|
}
|
|
|
|
if attr.Func != nil {
|
|
val = attr.Func(data)
|
|
}
|
|
} else {
|
|
name = fmt.Sprintf("0x%X", id)
|
|
val = hex.EncodeToString(data)
|
|
}
|
|
|
|
(*info)[name] = val
|
|
}
|
|
|
|
func dot11ParseWPSData(data []byte) (ok bool, info map[string]string) {
|
|
info = map[string]string{}
|
|
size := len(data)
|
|
|
|
for offset := 0; offset < size; {
|
|
ok := false
|
|
tagId := uint16(0)
|
|
tagLen := uint16(0)
|
|
tagData := []byte(nil)
|
|
|
|
if ok, tagId = wpsUint16At(data, size, &offset); !ok {
|
|
break
|
|
} else if ok, tagLen = wpsUint16At(data, size, &offset); !ok {
|
|
break
|
|
} else if ok, tagData = wpsDataAt(data, size, &offset, int(tagLen)); !ok {
|
|
break
|
|
} else {
|
|
dot11ParseWPSTag(tagId, tagLen, tagData, &info)
|
|
}
|
|
}
|
|
|
|
return true, info
|
|
}
|
|
|
|
func Dot11ParseWPS(packet gopacket.Packet, dot11 *layers.Dot11) (ok bool, bssid net.HardwareAddr, info map[string]string) {
|
|
ok = false
|
|
for _, layer := range packet.Layers() {
|
|
if layer.LayerType() == layers.LayerTypeDot11InformationElement {
|
|
if dot11info, infoOk := layer.(*layers.Dot11InformationElement); infoOk && dot11info.ID == layers.Dot11InformationElementIDVendor {
|
|
if bytes.Equal(dot11info.OUI, wpsSignatureBytes) {
|
|
bssid = dot11.Address3
|
|
ok, info = dot11ParseWPSData(dot11info.Info)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|