micropython / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
19.1k stars 7.65k forks source link

network.WLAN(...).scan() on Pico W returns out of range security and hidden parameters #10017

Open mrmabs opened 1 year ago

mrmabs commented 1 year ago

Hi all,

When doing wifi scans, the returned values regularly have values 5 of 7 in security, and values varying from 0 to 8 in hidden; the documentation states security should be 0-4 and hidden should be 0 or 1.

I've tried to go through the source from micropython to the cyw43 pico driver, but I'm not able to identify the issue (as I don't believe I understand the code enough to make a definitive statement). My [poorly informed] assumption is the security values aren't being translated from the CYW43 driver (CYW43AUTH), and maybe the hidden variable is getting overrun because it only ever appears to be set to 1 (network_cyw43_scan_cb() in extmod/network_cyw43.c), which would be hidden and should probably be 0 for visible. But neither of those assumptions completely make sense.

I have used two different firmware releases:

I initially followed the scanning code from this website, and quoting from the website where you can see the example output shows out of range values:

import network #import required module wlan = network.WLAN(network.STA_IF) #initialize the wlan object wlan.active(True) #activates the wlan interface accessPoints = wlan.scan() #perform a WiFi Access Points scan for ap in accessPoints: #this loop prints each AP found in a single row on shell     print(ap)

'>>> %Run -c $EDITOR_CONTENT (b'er-1', b'\xac\x9e\x17k\xd6@', 2, -47, 5, 5) (b'****G3P4', b'\xc8Z\x9f\xdc\xa47', 11, -81, 5, 3) (b'TWEB', b'\xcaZ\x9f\xdc\xa47', 11, -80, 5, 2)

And this blog post also mentions unusual output values: https://dev.webonomic.nl/scanning-network-with-the-raspberry-pi-pico-w

My end goal is to get reliable values to generate logs for wardriving.

iabdalkader commented 1 year ago

The list of values returned in a scan entry are, in order: (ssid, bssid, channel, RSSI, auth_mode, 1). auth_mode is not a single value it's a bitfield. See: https://github.com/micropython/micropython/blob/master/extmod/network_cyw43.c#L160 https://github.com/georgerobotics/cyw43-driver/blob/2ab6ca93f9cd044bc6f35c1403b1284e4161294a/src/cyw43_ll.c#L556

The documentation may be wrong, outdated or just for a different WiFi module/port.

mrmabs commented 1 year ago

Understood. In the examples I provided above, the last field (hidden) is returning values that are not 1. I'm seeing values as high as 8; but for my use case, I usually ignore this. I am using the Pi Pico W and I am accessing the onboard wifi that I am assuming is the CYW43 driver, as far as I understand the code.

In the auth_mode field, a value of 5 as a bitfield, would equal WPA2 || WEP_PSK. if I assume WEP_PSK is intended to be WEP or PSK, that makes more sense, 5 = WPA2||PSK and 7 = WPA||WPA2||PSK. So this is just a documentation issue.

iabdalkader commented 1 year ago

Yes the last field is hard-coded to 1, and yes Pico-W uses that driver/module and I saw the output you posted, I can't explain it, but the output I see with my Pico-W matches the expected output.

mrmabs commented 1 year ago

OK, I just grabbed the latest nightly build (rp2-pico-w-20221129-unstable-v1.19.1-722-g1b774b373.uf2) from https://micropython.org/download/rp2-pico-w/

And ran this code

import time, ubinascii, network, rp2

# set your WiFi Country
rp2.country('AU')

# init wifi

wlan = network.WLAN(network.STA_IF) #initialize the wlan object
wlan.active(True) #activates the wlan interface
wlan.config(channel=13)

def scan():
    accessPoints = wlan.scan() #perform a WiFi Access Points scan

    for ap in accessPoints: #this loop prints each AP found in a single row on shell
        ssid = ap[0].decode()
        bssid =  ubinascii.hexlify(ap[1],":").decode()
        ch = ap[2]
        rssi = ap[3]
        auth = hex(ap[4])
        vis = hex(ap[5])
        print("{:30s} | {:s} | {:2d} | {:3d} | {:s} | {:s}".format(ssid, bssid, ch, rssi, auth, vis))

scan()

And I get something resembling this:

beaker breaker | 42:60:f9:d6:e2:42 | 1 | -40 | 0x5 | 0x6 [LG_Washer]8fd4 | 62:fb:14:a9:80:a4 | 11 | -79 | 0x5 | 0x2

iabdalkader commented 1 year ago

That's interesting! Yes you're right, I do see values other than the hard-coded 1, seems like there may be a bug there, I can take a look later.

iabdalkader commented 1 year ago

Okay I took a closer look at the code, and this is definitely Not a bug it's just bad documentation. The last number in a scan entry is the number of times that network has been found in the scan results (duplicates are removed). Not sure how that is useful, or why it's done this way but it's just that. This is the line that increments the last number when a duplicate entry is found: https://github.com/micropython/micropython/blob/master/extmod/network_cyw43.c#L151

EDIT: Not sure if the documented hidden value makes any sense either, I don't think these simple scans can find hidden networks, but I could be wrong.

iabdalkader commented 1 year ago

Took a look at other networking modules and what they return in the last value of scan results entries and :

This might be worth making consistent across ports, or at least documenting correctly.

jimmo commented 1 year ago

This was discussed recently (can't remember if it was Discord or GitHub Discussions). There are also other differences, the one that I find most difficult when moving between ports is the different auth mode constants (for both connecting and scan results). I had originally planned to try and get this fixed for v1.20, but it's very difficult to do in a way that doesn't break backwards compatibility with other ports.

Depending on what I can get done this week I might still try and get this fixed for Pico W at least because there's never been an official release for that board so we still sort of have a window to change things.

But I think likely what we're going to need to do is save all this for v2.0 and make everything exactly the same.

iabdalkader commented 1 year ago

the one that I find most difficult when moving between ports is the different auth mode constants (for both connecting and scan results).

I recently fixed that for for scan and connect keyword args in all ports, and to maintain backwards compatibility (at least until the next release) I used duplicate constants/args, for examples see: https://github.com/micropython/micropython/blob/master/extmod/network_cyw43.c#L187 And https://github.com/micropython/micropython/blob/master/extmod/network_cyw43.c#L242

I think as a first step all scans should return at least 6 args with the last one being the hardcoded hidden arg, as documented and the CYW43 can return the extra arg that indicates the number of times a network was detected.

mrmabs commented 1 year ago

May be it's worth throwing a few use cases in.

I'm currently using this for wigle war driving, and this link describes the data being ingested into the system. WLAN.scan() in the docs does cover everything, other than some extended capabilities, like CCMP, TKIP, EAP (Enterprise), etc...

Another could be to use a microcontroller as a Kismet scanning source (sending data over Ethernet for example).

The only feature that I (and probably others) would find useful is restricting the channel, to either a single channel WLAN.scan(channel=1) or a list of channels WLAN.scan(channel=[1,6,11]). On one end you have The Wifydra (each module is on its own channel), and the other you might have a device you want to scan for home WiFi before attempting to connect, and you know the SSID you are looking for will only ever be on channels: [1, 6, 11].

MaxMyzer commented 1 year ago

Looks related to #6430

maxi07 commented 9 months ago

is there any update to this? this is still an issue, I am using MicroPython v1.20 with a Raspberry Pico W and get the following result:

[(b'MagentaWLAN-DYHG', b'\x84\x90\nTA\xbe', 6, -73, 5, 1), (b'FRITZ!Box 7360', b'4\x81\xc4\xd7\x08\x00', 11, -43, 7, 5), (b'FRITZ!Box 7430 BB', b'|\xffM`^\x9f', 11, -85, 5, 1)]

I cannot make any sense of the last two numbers.

apribot commented 3 months ago

I was able to get a speculative list from this. Note that this is only anecdotally correct from my brief testing, I haven't spent the time to dig through the source for a concrete answer: 0: open, 1: WEP, 2: WPA-PSK, 3: WPA2-PSK, 4: WPA/WPA2-PSK, 5: WPA2 ENTERPRISE, 6: WPA3-PSK, 7: WPA2/3 PSK, 8: WAPI-PSK, 9: OWE

Hopefully someone can update the documentation, it was not easy to find this thread.