why-fi

This was a very silly idea. I had to, for school, build a small arduino project that relays some metric over MQTT and sends some notifications in case of an alert.

We also had to make a small mobile app, in order to provide access to these metrics, etc.

It’s simple on paper but a project like this is prone to issues related to cheap hardware, ordering stuff is annoying, and I did not feel like going through the pain of using a breadboard.

In order to circumvent that, I had the brilliant idea to just monitor what goes through the chip. We already have an Arduino chip with WiFi capabilities, why not just use that as our monitor ?

The idea was simple:

  • We need to monitor something ? Let’s monitor the WiFi packets going through!
  • We need to send back alerts ? Let’s just send one if we spot a Deauth attack. It’s very easy to check for, right ?

Experienced Arduino conoisseurs already know this is a bad idea.

But I am getting ahead of myself.

If you don’t care about the article and just want to read the code, you can check it out here.

Setting up the project

First issue I had was with the Arduino-IDE. It’s pretty good to flash firmware on a various set of chips and manage libraries. But, the developer experience is ass. No language-server, themes, or any of that fancy shit.

I ended up writing my code in another editor and just use the IDE to flash firmware. You can also use the CLI to do that, but I was lazy and in a bit of a hurry.

To make the flashing process work, I had to install support for the boards and select “Generic ESP8266” as my current board.

MQTT ? more like Message Queues That Test my patience

My first task was to get the application to send network data over MQTT.

In no particular order, here are some things that gave me trouble, and how I mitigated them:

  • The WiFi hotspot on my phone (although set as 2.4Ghz) would drop all packets related to the Arduino. No idea why; ended up using another phone,
  • Could not get a TLS connection going, even after following a few tutorials; fuck it, we wont use TLS (Lazy and in a hurry, remember ?),
  • Because of the problem described above, I could not use the “““default””” port 8883; turns out I should have used 1883,
  • Runtime crashes when the last statement of a function was ps_client.publish(); ended up adding some logging after and it fixed the issue ? I assume it’s because the garbage collectors pops the function-related data before the connection has finished sending it.

After all this trouble, I eventually managed to retrieve some information about my current WiFi network, and relay it over MQTT. Some of the issues I had were just weird, but I imagine that the embedded world is more complicated than it looks like (things often are).

Setting up a public WiFi hotspot (not sponsored by a VPN provider)

Another thing we had to do was to set up WiFi connection settings at runtime.

You can’t just flash a different firmware with hard-coded credentials for each user.

Instead, we set up the on-board WiFi chip to be able to receive connection. This will then host a little web-server on which you can input the real SSID and Password.

With EEPROM or an SD-card, you could even just store it in memory and not require it unless the connection fails, or something like that.

This was not that hard to do but hosting a web server on this chip is pretty slow. Although there is a mode where you can scan and another to manage connections to the on-board network, you cannot do both at once.

This means, in short, that any person requesting a scan to get the nearby networks would prevent other users to access the chip’s web server.

I honestly could not care less. In the end, I just had a little script that looked like this, which I would run at the end of the flashing process, everytime I wanted to test my firmware:

#!/bin/bash

# name of my WiFi hotspot on my phone
nmcli con up lila1337

# Web request with WiF settings
curl -v 'http://192.168.4.1/' \
    -H 'Referer: http://192.168.4.1/' \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    --data-raw 'i=MY_SSID&p=ITS_PASSWORD'

nmcli con up ${MY_INITIAL_NETWORK}

In total, the major part of my .ino script ended up managing incoming connections and setting the “real” WiFi connection up.

For completeness and debug, I added a command to reset the chip to SoftAP mode.

Yes, I receive commands over an unsecured MQTT-channel, on a public broker.

Do I think it’s a good idea ? Of course not.

Do I give a shit ? Of course not. :)~

Monitoring the packets

This is when the problems really started piling up.

For one, the ESP8266 is less reliable than its bigger brother (the ESP32). For second, the documentation is of course absolutely terrible once you want to research weird wifi_set_something() functions.

Because I’m nice, I’ll give you the secret sauce. It’s real simple. In order to have a callback for each passing packet, you can just do:

int nb_packets = 0;
void do_something(uint8_t *buf, uint16_t len) {
    // you can do anything here, but lets just count the packets.
    nb_packets += 1;
}

// this function is called after boot automatically
void setup() {

    // do things before
    // ...

    // station mode is important ; you cant do it in another mode
    WiFi.mode(WIFI_STA);

    // will set a callback on packet reception
    wifi_set_promiscuous_rx_cb(do_something);

    // enable the promiscuous mode
    wifi_promiscuous_enable(1);

    // if you want to disable
    wifi_promiscuous_disable(0);
}

Easy-peasy right ? Wrong. Dumbass. Idiot. WRONG.

It’s so over

My plan was to initially serialize (using TLV; Type, Length, Value) the packets on the chip, transmit them over MQTT (maybe with a circular buffer) and then turn it to a PCAP in the back-end, before uploading it to S3 & offering the user to actually download .pcaps from the current network.

Looks real fucking cool on paper, but there is simply just too many packets. So, no actual monitoring of the packets. Well that’s a bummer.

But at least, I can still count them and send it over MQTT, right ? Wrong. Idiot. Stupid motherfucker. WRONG.

You see, as soon as the promiscuous mode is enabled, you cannot use your WiFi connection normally. So you cannot use a WiFi chip for both ? What do we do ?

We’re so fucking back

Although this meant this is not usable in “production” (was it ever ?), I could still salvage this (and my GPA).

If I stored in memory the WiFi credentials, and reconnected to the network I wanted to analyze ever N second I could still monitor some of them, which is better than nothing, I guess.

Some frenetic coding later, I managed to get something to work.

Every time I wanted to switch promiscuous mode, I went through this little helper function which would set the appropriate callbacks:

void __switch_promiscuous_mode(int mode) {
  if (mode == 1) {

    WiFi.disconnect();

    // yes, program state is a global variable without semaphore or care
    // in the word. if it works it works, ok??
    if (program_state == STATE_ASLEEP) {
      wifi_set_promiscuous_rx_cb(__sniffer_asleep);
    } else if (program_state == STATE_MONITOR_MODE) {
      wifi_set_promiscuous_rx_cb(__sniffer_monitor);
    }

    wifi_promiscuous_enable(1);
    delay(VERY_QUICK_DELAY_TIME);

  } else {

    wifi_promiscuous_enable(0);
    __wifi_local_connect(saved_ssid, saved_pass);

    // ps_client == MQTT client
    ps_client.setServer(MQTT_SERVER_URL, MQTT_PORT);
    ps_client.setCallback(__mqtt_read_callback);

    if (ps_client.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
      ps_client.subscribe(MQTT_TOPIC_INPUT);
    }
  }
}

an astute reader notices that I have named all my function with a leading __ in order to more easily differentiate them from the standard / library functions I use.

this is not good coding style nor a smart thing to do, but you can’t stop me so fuck you

Now, I could send messages again. This was all well and good, but I had two issues:

  • Callbacks wouldn’t actually trigger, or barely. Most of the time the Arduino was doing IO/network stuff and didnt have promiscuous mode set at that time,
  • Remember when I wanted to send instructions to my chip over MQTT ? Yeah, forget that. Since it disconnects as soon as it has finished sending its message, I cannot send an instruction from the MQTT broker.

My elegant (no) solution for this was to put delay() calls everywhere and just vibe. As I said before, the goal was just to relay some information & then trigger an alert if something happens. It could still do that, so it’s a W in my book.

Nevermind, it’s over

Well, now I have a packet monitor….of sorts. It can relay things, and does very cool stuff.

It’s also uncommon for a teacher to see that kind of idea because people usually just monitor temperature or something. I was feeling happy about myself, confident, clever and all those words.

Job well done and time to go home, right ? Wrong. Stupid. Stupid. Stupid. WRONG.

Do you remember the beginning of the article ? Of course not, so I will paste it here again for you:

This was a very silly idea. I had to, for school, build a small arduino project that relays some metric over MQTT and sends some notifications in case of an alert.

We also had to make a small mobile app, in order to provide access to these metrics, etc.

Fuck.

We forgot to make the app. It also turns out most of the notation is based on the app and not on the Arduino stuff at all.

All of this for nothing. Damn 😔 …

Conclusion

For nothing ? Well no.

First, now we know this is a stupid idea that should not be attempted anymore. If you want to monitor packets, it’s very easy. If you want to send messages over MQTT, it’s very easy too ! But if you want to do the two things at once with the same chip ? Not easy, stupid.

Second, I learned (and I hope you did too) about the ESP8266’s capabilities for WiFi. It can do a lot of things, it’s very cool ! This gives me a lot of ideas for the future.

Third, this was fun (surprisingly).

Also, don’t worry about my school credits or my GPA. I am in my final year and I should easily graduate. This is not a big deal to me at all. :)

Here is the code if you want to suffer.

See you next time :)~

djnn.sh

offensive security & software engineering


an ESP8266 and a dream

2024-01-27