new: new WPS parsing capabilities and wifi.show.wps command

This commit is contained in:
evilsocket 2019-01-27 14:52:59 +01:00
commit 50bf22af9c
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
4 changed files with 224 additions and 23 deletions

View file

@ -141,6 +141,12 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
"true", "true",
"If true, the fake access point will use WPA2, otherwise it'll result as an open AP.")) "If true, the fake access point will use WPA2, otherwise it'll result as an open AP."))
w.AddHandler(session.NewModuleHandler("wifi.show.wps BSSID", "wifi.show.wps ((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))",
"Show WPS information about a given station.",
func(args []string) error {
return w.ShowWPS(args[0])
}))
w.AddHandler(session.NewModuleHandler("wifi.show", "", w.AddHandler(session.NewModuleHandler("wifi.show", "",
"Show current wireless stations list (default sorting by essid).", "Show current wireless stations list (default sorting by essid).",
func(args []string) error { func(args []string) error {
@ -266,6 +272,23 @@ func (w *WiFiModule) Configure() error {
return nil return nil
} }
func (w *WiFiModule) updateInfo(dot11 *layers.Dot11, packet gopacket.Packet) {
if ok, enc, cipher, auth := packets.Dot11ParseEncryption(packet, dot11); ok {
bssid := dot11.Address3.String()
if station, found := w.Session.WiFi.Get(bssid); found {
station.Encryption = enc
station.Cipher = cipher
station.Authentication = auth
}
}
if ok, bssid, info := packets.Dot11ParseWPS(packet, dot11); ok {
if station, found := w.Session.WiFi.Get(bssid.String()); found {
station.WPS = info
}
}
}
func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) { func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
// collect stats from data frames // collect stats from data frames
if dot11.Type.MainType() == layers.Dot11TypeData { if dot11.Type.MainType() == layers.Dot11TypeData {
@ -281,15 +304,6 @@ func (w *WiFiModule) updateStats(dot11 *layers.Dot11, packet gopacket.Packet) {
station.Sent += bytes station.Sent += bytes
} }
} }
if ok, enc, cipher, auth := packets.Dot11ParseEncryption(packet, dot11); ok {
bssid := dot11.Address3.String()
if station, found := w.Session.WiFi.Get(bssid); found {
station.Encryption = enc
station.Cipher = cipher
station.Authentication = auth
}
}
} }
func (w *WiFiModule) Start() error { func (w *WiFiModule) Start() error {
@ -331,6 +345,7 @@ func (w *WiFiModule) Start() error {
w.discoverProbes(radiotap, dot11, packet) w.discoverProbes(radiotap, dot11, packet)
w.discoverAccessPoints(radiotap, dot11, packet) w.discoverAccessPoints(radiotap, dot11, packet)
w.discoverClients(radiotap, dot11, packet) w.discoverClients(radiotap, dot11, packet)
w.updateInfo(dot11, packet)
w.updateStats(dot11, packet) w.updateStats(dot11, packet)
} }
} }

View file

@ -78,7 +78,6 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
return []string{ return []string{
fmt.Sprintf("%d dBm", station.RSSI), fmt.Sprintf("%d dBm", station.RSSI),
bssid, bssid,
/* station.Vendor, */
strconv.Itoa(station.Channel()), strconv.Itoa(station.Channel()),
sent, sent,
recvd, recvd,
@ -95,12 +94,29 @@ func (w *WiFiModule) getRow(station *network.Station) ([]string, bool) {
} }
} }
wps := ""
if station.HasWPS() {
if ver, found := station.WPS["Version"]; found {
wps = ver
} else {
wps = "✔"
}
if state, found := station.WPS["State"]; found {
if state == "Not Configured" {
wps += " (not configured)"
}
}
wps = tui.Dim(tui.Yellow(wps))
}
return []string{ return []string{
fmt.Sprintf("%d dBm", station.RSSI), fmt.Sprintf("%d dBm", station.RSSI),
bssid, bssid,
ssid, ssid,
/* station.Vendor, */
encryption, encryption,
wps,
strconv.Itoa(station.Channel()), strconv.Itoa(station.Channel()),
clients, clients,
sent, sent,
@ -199,13 +215,17 @@ func (w *WiFiModule) colDecorate(colNames []string, name string, dir string) {
} }
} }
func (w *WiFiModule) colNames(nrows int) []string { func (w *WiFiModule) colNames(nrows int, withWPS bool) []string {
columns := []string(nil) columns := []string(nil)
if !w.isApSelected() { if !w.isApSelected() {
columns = []string{"RSSI", "BSSID", "SSID", "Encryption", "Channel", "Clients", "Sent", "Recvd", "Last Seen"} if withWPS {
columns = []string{"RSSI", "BSSID", "SSID", "Encryption", "WPS", "Ch", "Clients", "Sent", "Recvd", "Last Seen"}
} else {
columns = []string{"RSSI", "BSSID", "SSID", "Encryption", "Ch", "Clients", "Sent", "Recvd", "Last Seen"}
}
} else if nrows > 0 { } else if nrows > 0 {
columns = []string{"RSSI", "MAC", "Channel", "Sent", "Received", "Last Seen"} columns = []string{"RSSI", "MAC", "Ch", "Sent", "Received", "Last Seen"}
fmt.Printf("\n%s clients:\n", w.ap.HwAddress) fmt.Printf("\n%s clients:\n", w.ap.HwAddress)
} else { } else {
fmt.Printf("\nNo authenticated clients detected for %s.\n", w.ap.HwAddress) fmt.Printf("\nNo authenticated clients detected for %s.\n", w.ap.HwAddress)
@ -220,7 +240,7 @@ func (w *WiFiModule) colNames(nrows int) []string {
case "bssid": case "bssid":
w.colDecorate(columns, "BSSID", w.selector.SortSymbol) w.colDecorate(columns, "BSSID", w.selector.SortSymbol)
case "channel": case "channel":
w.colDecorate(columns, "Channel", w.selector.SortSymbol) w.colDecorate(columns, "Ch", w.selector.SortSymbol)
case "clients": case "clients":
w.colDecorate(columns, "Clients", w.selector.SortSymbol) w.colDecorate(columns, "Clients", w.selector.SortSymbol)
case "encryption": case "encryption":
@ -243,15 +263,19 @@ func (w *WiFiModule) Show() (err error) {
return return
} }
hasWPS := false
rows := make([][]string, 0) rows := make([][]string, 0)
for _, s := range stations { for _, s := range stations {
if row, include := w.getRow(s); include { if row, include := w.getRow(s); include {
if len(s.WPS) > 0 {
hasWPS = true
}
rows = append(rows, row) rows = append(rows, row)
} }
} }
nrows := len(rows) nrows := len(rows)
if nrows > 0 { if nrows > 0 {
tui.Table(os.Stdout, w.colNames(nrows), rows) tui.Table(os.Stdout, w.colNames(nrows, hasWPS), rows)
} }
w.Session.Queue.Stats.RLock() w.Session.Queue.Stats.RLock()
@ -270,3 +294,42 @@ func (w *WiFiModule) Show() (err error) {
return nil return nil
} }
func (w *WiFiModule) ShowWPS(bssid string) (err error) {
toShow := []*network.AccessPoint{}
if bssid == network.BroadcastMac {
for _, station := range w.Session.WiFi.List() {
if station.HasWPS() {
toShow = append(toShow, station)
}
}
} else {
if station, found := w.Session.WiFi.Get(bssid); found {
if station.HasWPS() {
toShow = append(toShow, station)
}
}
}
if len(toShow) == 0 {
return fmt.Errorf("no WPS enabled access points matched the criteria")
}
for _, station := range toShow {
ssid := station.ESSID()
if ssid == "<hidden>" {
ssid = tui.Dim(ssid)
}
fmt.Println()
fmt.Printf("* %s (%s ch:%d):\n", tui.Bold(ssid), tui.Dim(station.BSSID()), station.Channel())
for name, value := range station.WPS {
fmt.Printf(" %s: %s\n", name, tui.Yellow(value))
}
}
fmt.Println()
return nil
}

View file

@ -6,13 +6,14 @@ import (
type Station struct { type Station struct {
*Endpoint *Endpoint
Frequency int `json:"frequency"` Frequency int `json:"frequency"`
RSSI int8 `json:"rssi"` RSSI int8 `json:"rssi"`
Sent uint64 `json:"sent"` Sent uint64 `json:"sent"`
Received uint64 `json:"received"` Received uint64 `json:"received"`
Encryption string `json:"encryption"` Encryption string `json:"encryption"`
Cipher string `json:"cipher"` Cipher string `json:"cipher"`
Authentication string `json:"authentication"` Authentication string `json:"authentication"`
WPS map[string]string `json:"wps"`
} }
func cleanESSID(essid string) string { func cleanESSID(essid string) string {
@ -47,3 +48,7 @@ func (s *Station) ESSID() string {
func (s *Station) Channel() int { func (s *Station) Channel() int {
return Dot11Freq2Chan(s.Frequency) return Dot11Freq2Chan(s.Frequency)
} }
func (s *Station) HasWPS() bool {
return len(s.WPS) > 0
}

118
packets/dot11_wps.go Normal file
View file

@ -0,0 +1,118 @@
package packets
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"net"
"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
Desc map[string]string
}
var (
wpsSignatureBytes = []byte{0x00, 0x50, 0xf2, 0x04}
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",
}},
0x1057: wpsAttr{Name: "AP Setup Locked"},
0x1041: wpsAttr{Name: "Selected Registrar"},
0x1012: wpsAttr{Name: "Device Password ID"},
0x1053: wpsAttr{Name: "Selected Registrar Config Methods", Desc: map[string]string{
"0001": "USB",
"0002": "Ethernet",
"0004": "Label",
"0008": "Display",
"0010": "External NFC",
"0020": "Internal NFC",
"0040": "NFC Interface",
"0080": "Push Button",
"0100": "Keypad",
}},
0x103B: wpsAttr{Name: "Response Type"},
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},
0x1008: wpsAttr{Name: "Config Methods"},
0x103C: wpsAttr{Name: "RF Bands"},
0x1045: wpsAttr{Name: "SSID", Type: wpsStr},
0x102D: wpsAttr{Name: "OS Version", Type: wpsStr},
0x1049: wpsAttr{Name: "Vendor Extension"},
}
)
func dot11ParseWPSData(data []byte) (ok bool, info map[string]string) {
info = map[string]string{}
size := len(data)
for offset := 0; offset < size; {
tagId := binary.BigEndian.Uint16(data[offset:])
offset += 2
tagLen := binary.BigEndian.Uint16(data[offset:])
offset += 2
tagData := data[offset : offset+int(tagLen)]
if attr, found := wpsAttributes[tagId]; found {
val := ""
if attr.Type == wpsStr {
val = string(tagData)
} else {
val = hex.EncodeToString(tagData)
}
if attr.Desc != nil {
if desc, found := attr.Desc[val]; found {
val = desc
}
}
info[attr.Name] = val
} else {
info[fmt.Sprintf("0x%X", tagId)] = hex.EncodeToString(tagData)
}
offset += int(tagLen)
}
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
}