etc.git


etc

~ scripts and random things
git clone https://github.com/djnnvx/etc.git
log | files | refs | archive

lila.ino (14441B)

      1 /*
      2    lila ~ https://djnn.sh/posts/why-fi/
      3 
      4    esp8266 packet-sniffer. relays packets count over mqtt & informs you in case of
      5    deauth attack.
      6 
      7 PLEASE NOTE:
      8 
      9   since it uses the same WiFi stack to run analysis & communicate, this really fucking
     10   sucks. ive attempted to do this just to do something funny. please dont actually use
     11   this or attempt to replicate. its fucking stupid.
     12 
     13 Dependencies:
     14 
     15 - arduinojson
     16 - arduino pubsub client
     17 - base64
     18 - time
     19 
     20  */
     21 
     22 
     23 #include "base64.hpp"
     24 #include <SPI.h>
     25 #include <ArduinoJson.h>
     26 #include <PubSubClient.h>
     27 #include <WiFiClientSecure.h>
     28 #include <Arduino.h>
     29 #include <TimeLib.h>
     30 
     31 
     32 #ifdef ESP8266
     33 #include <ESP8266WiFi.h>
     34 #else
     35 #include <WiFi.h>
     36 #endif
     37 
     38 extern "C" {
     39   #include "user_interface.h"
     40 }
     41 
     42 // ignore stupid warnings
     43 #pragma GCC diagnostic ignored "-Wwrite-strings"
     44 
     45 /* CONSTANTS */
     46 
     47 #define LED             2           /* LED pin (2=built-in LED) */
     48 #define SERIAL_BAUD     9600        /* Baudrate for serial communication */
     49 #define CH_TIME         140         /* Scan time (in ms) per channel */
     50 
     51 #define DELAY_TIME              1000
     52 #define QUICK_DELAY_TIME        500
     53 #define VERY_QUICK_DELAY_TIME   10
     54 
     55 
     56 #define MQTT_TOPIC_INPUT    "lila_output"
     57 #define MQTT_TOPIC_OUTPUT   "lila_input" /* name is confusing because the chip output is the server input */
     58 #define MQTT_USERNAME       "lila-sniffer"
     59 #define MQTT_PASSWORD       ""
     60 #define MQTT_SERVER_URL     "broker.hivemq.com"
     61 #define MQTT_CLIENT_ID      "djnn.sh"
     62 #define MQTT_PORT           1883
     63 
     64 #define STATE_ASLEEP            0
     65 #define STATE_MONITOR_MODE      1
     66 #define STATE_SOFT_AP_MODE      2
     67 
     68 #define COMMAND_SET_ASLEEP    "ASLEEP"
     69 #define COMMAND_SET_MONITOR   "MONITOR_DEAUTH"
     70 #define COMMAND_SET_SOFTAP    "SOFTAP"
     71 
     72 #define MSG_OK "OK"
     73 #define MSG_KO "KO"
     74 
     75 /* VARIABLES */
     76 
     77 #define MQTT_MSG_SIZE 512
     78 
     79 // program things
     80 unsigned int program_state = STATE_SOFT_AP_MODE;
     81 char mqtt_msg_to_send[MQTT_MSG_SIZE];
     82 
     83 WiFiClient net_client;
     84 PubSubClient ps_client(net_client);
     85 
     86 int nb_packets = 0;
     87 char ip_address[256];
     88 
     89 char saved_ssid[256];
     90 char saved_pass[256];
     91 
     92 
     93 /* FUNCTIONS */
     94 
     95 // Connects to local WiFi hotspot
     96 void __wifi_local_connect(char const *ssid, char const *pass) {
     97     WiFi.mode(WIFI_STA);
     98     WiFi.begin(ssid, pass);
     99     while (WiFi.status() != WL_CONNECTED) {
    100         delay(VERY_QUICK_DELAY_TIME);
    101     }
    102 }
    103 
    104 
    105 // sets up soft access point on setup
    106 void __wifi_setup_soft_ap() {
    107 
    108     delay(QUICK_DELAY_TIME);
    109     Serial.println("Setting up soft-AP with credentials: lila1337:lila1337.......");
    110     if (WiFi.softAP("lila1337", "lila1337")) {
    111         __blink_success();
    112 
    113         program_state = STATE_SOFT_AP_MODE;
    114 
    115         // ensure we can scan & use AP mode
    116         WiFi.mode(WIFI_AP_STA);
    117 
    118         IPAddress myIP = WiFi.softAPIP();
    119         Serial.print("[+] AP IP address: http://");
    120         Serial.println(myIP);
    121     } else {
    122         __blink_failure();
    123         Serial.println("[!] Could not set up webserver........");
    124         return;
    125     }
    126 
    127     Serial.println("Booting up webserver...");
    128 
    129     WiFiClient net_client;
    130     WiFiServer configWebServer(80);
    131     configWebServer.begin();
    132 
    133     // run webserver until we have wifi credentials
    134     while (program_state == STATE_SOFT_AP_MODE) {
    135 
    136         // either scan for Wifi hotspots or connect to them...
    137         net_client = configWebServer.available();
    138         if (net_client) {
    139 
    140             char line[64];
    141             int l = net_client.readBytesUntil('\n', line, sizeof(line));
    142             line[l] = 0;
    143 
    144             net_client.find((char*) "\r\n\r\n");
    145             if (strncmp_P(line, PSTR("POST"), strlen("POST")) == 0) {
    146                 l = net_client.readBytes(line, sizeof(line));
    147                 line[l] = 0;
    148 
    149                 // parse the parameters sent by the html form
    150                 const char* delims = "=&";
    151                 strtok(line, delims);
    152 
    153                 const char* ssid = strtok(NULL, delims);
    154                 strtok(NULL, delims);
    155 
    156                 const char* pass = strtok(NULL, delims);
    157 
    158                 memset(saved_ssid, 0, 256);
    159                 memset(saved_pass, 0, 256);
    160                 strncpy(saved_ssid, ssid, 256);
    161                 strncpy(saved_pass, pass, 256);
    162 
    163                 // send a response before attemting to connect to the WiFi network
    164                 // because it will reset the SoftAP and disconnect the client station
    165                 net_client.println(F("HTTP/1.1 200 OK"));
    166                 net_client.println(F("Connection: close"));
    167                 net_client.println(F("Refresh: 10")); // send a request after 10 seconds
    168                 net_client.println();
    169                 net_client.println(F("<html><body><h3>Configuration AP</h3><br>connecting...</body></html>"));
    170                 net_client.stop();
    171 
    172                 Serial.println();
    173                 Serial.print("Attempting to connect to WPA SSID: ");
    174                 Serial.println(ssid);
    175 
    176                 WiFi.persistent(true);
    177                 WiFi.setAutoConnect(true);
    178                 WiFi.begin(ssid, pass);
    179                 WiFi.waitForConnectResult();
    180 
    181             } {
    182 
    183                 net_client.println(F("HTTP/1.1 200 OK"));
    184                 net_client.println(F("Connection: close"));
    185                 net_client.println();
    186                 net_client.println(F("<html><body><h3>Configuration AP</h3><br>"));
    187 
    188                 int status = WiFi.status();
    189                 if (status == WL_CONNECTED) {
    190 
    191                     net_client.println(F("</body></html>"));
    192 
    193                     program_state = STATE_ASLEEP;
    194                     net_client.println(F("Connection successful. Ending AP."));
    195                     net_client.stop();
    196 
    197                     delay(1000);
    198                     Serial.println("Connection successful. Ending AP.");
    199                     configWebServer.stop();
    200 
    201                     WiFi.mode(WIFI_STA);
    202                     Serial.print("WiFi status = ");
    203                     Serial.println(WiFi.status());
    204 
    205                     Serial.print("Local IP address:");
    206                     Serial.println(WiFi.localIP());
    207 
    208 
    209                     return;
    210 
    211                 } else {
    212                     net_client.println(F("<form action='/' method='POST'>WiFi connection failed. Enter valid parameters, please.<br><br>"));
    213                     net_client.println(F("SSID:<br><input type='text' name='i'><br>"));
    214                     net_client.println(F("Password:<br><input type='password' name='p'><br><br>"));
    215                     net_client.println(F("<input type='submit' value='Submit'></form>"));
    216                     net_client.println(F("</body></html>"));
    217                 }
    218             }
    219         }
    220     }
    221 }
    222 
    223 // Reconnects to MQTT server
    224 PubSubClient __mqtt_reconnect(PubSubClient ps_client, WiFiClient net_client, char ip[256]) {
    225 
    226     Serial.printf(
    227       "[+] Attempting MQTT connection to %s: [username = %s, client id: %s]\n",
    228       MQTT_SERVER_URL,
    229       MQTT_USERNAME,
    230       MQTT_CLIENT_ID
    231     );
    232 
    233     if (ps_client.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
    234       __blink_success();
    235       ps_client.subscribe(MQTT_TOPIC_INPUT);
    236       Serial.printf("Subscribed to topic %s\n", MQTT_TOPIC_INPUT);
    237 
    238     } else {
    239       __blink_failure();
    240       Serial.print("error: ");
    241       Serial.println(ps_client.state());
    242       return ps_client;
    243    }
    244 
    245     char mqtt_message[512];
    246     DynamicJsonDocument js = __get_net_information(net_client, ip);
    247 
    248     serializeJson(js, mqtt_message);
    249     ps_client.publish(MQTT_TOPIC_OUTPUT, mqtt_message, true);
    250     Serial.printf("[+] net info: %s\n", mqtt_message);
    251     return ps_client;
    252 }
    253 
    254 // returns public ip address by querying various "what's my IP" services
    255 void __net_get_public_ip(WiFiClient net_client, char *output, size_t output_size) {
    256 
    257     char return_value[256];
    258 
    259     memset(output, 0, output_size);
    260 
    261     strncpy(return_value, "0.0.0.0", 256);
    262     strncpy(output, return_value, output_size - 1);
    263     output[output_size - 1] = '\0';
    264 
    265     Serial.println("Attempting to retrieve Public IP address...");
    266 
    267     delay(QUICK_DELAY_TIME);
    268 
    269     // check if service is up & we can connect
    270     if (!net_client.connect("ipecho.net", 80)) {
    271         Serial.print("could not connect. status = ");
    272         Serial.println(net_client.status());
    273         __blink_failure();
    274         return;
    275     }
    276 
    277     // hand-write the request
    278     net_client.println(F("GET /plain HTTP/1.0"));
    279     net_client.println(F("Host: ipecho.net"));
    280     net_client.println(F("User-Agent: lila (ESP8266 packet sniffer)"));
    281     net_client.println(F("Accept: */*"));
    282     net_client.println(F("Connection: close"));
    283     net_client.println();
    284 
    285     delay(5000);
    286 
    287     // skip all lines until last one
    288     String line;
    289     do {
    290         line = net_client.readStringUntil('\n');
    291     } while (net_client.available());
    292 
    293     // Copy the last line to return_value
    294     strncpy(output, line.c_str(), output_size - 1);
    295 
    296     Serial.printf("IP Address: %s\n", output);
    297 }
    298 
    299 
    300 // returns wifi security type (WEP, WPA, etc) as a string to be serialized
    301 char *__wifi_get_security() {
    302     char *security_descriptors[] = {
    303         "UNKNOWN",
    304         "UNKNOWN",
    305         "TKIP (WPA)",
    306         "UNKNOWN",
    307         "CCMP (WPA)",
    308         "WEP",
    309         "UNKNOWN",
    310         "NONE",
    311         "AUTO",
    312     };
    313 
    314     return security_descriptors[8];
    315 }
    316 
    317 // Retrieves network information related to current SSID
    318 DynamicJsonDocument __get_net_information(WiFiClient net_client, char ip[256]) {
    319 
    320     /*
    321        Retrieve following information and return it in a JSON-formatted string:
    322 
    323        - SSID
    324        - signal strength
    325        - public IP address
    326        - Security (WPA/WPA2)
    327        - channel number
    328        - number of packets
    329      */
    330 
    331     DynamicJsonDocument js(MQTT_MSG_SIZE);
    332 
    333     js["ssid"] = WiFi.SSID();
    334     js["mac"] = WiFi.macAddress();
    335     js["channel"] = WiFi.channel();
    336     js["strength"] = WiFi.RSSI();
    337     js["ip-address"] = ip;
    338     js["security"] = __wifi_get_security();
    339     js["nb_packets"] = nb_packets;
    340 
    341     return js;
    342 }
    343 
    344 
    345 // MQTT callback on message read
    346 void __mqtt_read_callback(char* topic, byte* payload, unsigned int length) {
    347 
    348     String msg = "";
    349     for (int i = 0; i < length; i++)
    350       msg += (char)payload[i];
    351 
    352     Serial.println("[MQTT] received [" + String(topic) + "]: " + msg);
    353     if (!strcmp(msg.c_str(), COMMAND_SET_ASLEEP) && program_state != STATE_ASLEEP) {
    354       Serial.println("SET MODE ASLEEP");
    355       program_state = STATE_ASLEEP;
    356 
    357       wifi_promiscuous_enable(0);
    358       wifi_set_promiscuous_rx_cb(__sniffer_asleep);
    359       wifi_set_channel(WiFi.channel());
    360       wifi_promiscuous_enable(1);
    361       goto CALLBACK_SEND_OK;
    362     }
    363 
    364     if (!strcmp(msg.c_str(), COMMAND_SET_MONITOR) && program_state != STATE_MONITOR_MODE) {
    365       Serial.println("SET MODE MONITOR");
    366       program_state = STATE_MONITOR_MODE;
    367 
    368       wifi_promiscuous_enable(0);
    369       wifi_set_promiscuous_rx_cb(__sniffer_monitor);
    370       wifi_promiscuous_enable(1);
    371       goto CALLBACK_SEND_OK;
    372     }
    373 
    374 
    375     if (!strcmp(msg.c_str(), COMMAND_SET_SOFTAP)) { // cannot interact once softap mode enabled
    376       Serial.println("SET MODE SOFT_AP");
    377       program_state = STATE_SOFT_AP_MODE;
    378 
    379       wifi_promiscuous_enable(0);
    380       goto CALLBACK_SEND_OK;
    381     }
    382 
    383     strncpy(mqtt_msg_to_send, MSG_KO, sizeof(MSG_KO));
    384     return;
    385 
    386 CALLBACK_SEND_OK:
    387     strncpy(mqtt_msg_to_send, MSG_OK, sizeof(MSG_OK));
    388     return;
    389 }
    390 
    391 
    392 // blink for a long time in case of error
    393 void __blink_failure() {
    394     digitalWrite(LED, LOW);
    395     delay(DELAY_TIME);
    396     digitalWrite(LED, HIGH);
    397 }
    398 
    399 // blink for a short time in case of success
    400 void __blink_success() {
    401     digitalWrite(LED, LOW);
    402     delay(QUICK_DELAY_TIME);
    403     digitalWrite(LED, HIGH);
    404 }
    405 
    406 void __sniffer_relay(uint8_t *buf, uint16_t len) {
    407 
    408   char mqtt_message[512];
    409   DynamicJsonDocument js(512);
    410 
    411   char pcap[64];
    412   encode_base64(buf, len, (unsigned char *)pcap);
    413 
    414   js["mac"] = WiFi.macAddress();
    415   js["strength"] = WiFi.RSSI();
    416   js["pcap"] = pcap;
    417 
    418   serializeJson(js, mqtt_message);
    419 
    420   Serial.println(mqtt_message);
    421 }
    422 
    423 
    424 void __sniffer_monitor(uint8_t *buf, uint16_t len) {
    425   if (buf && len >= 27) {
    426     byte pkt_type = buf[12];
    427 
    428     // If captured packet is a deauthentication or dissassociaten frame
    429     if (pkt_type == 0xA0 || pkt_type == 0xC0) {
    430       ps_client.publish(MQTT_TOPIC_OUTPUT, "ALERT DEAUTH", true);
    431       Serial.println("Spotted DEAUTH attack!");
    432     }
    433   }
    434 }
    435 
    436 void __sniffer_asleep(uint8_t *buf, uint16_t len) {
    437    if (buf && len >= 27)
    438       nb_packets += 1;
    439 }
    440 
    441 void __switch_promiscuous_mode(int mode) {
    442   if (mode == 1) {
    443 
    444     WiFi.disconnect();
    445 
    446     if (program_state == STATE_ASLEEP) {
    447       wifi_set_promiscuous_rx_cb(__sniffer_asleep);
    448     } else if (program_state == STATE_MONITOR_MODE) {
    449       wifi_set_promiscuous_rx_cb(__sniffer_monitor);
    450     }
    451 
    452     wifi_promiscuous_enable(1);
    453     delay(VERY_QUICK_DELAY_TIME);
    454 
    455   } else {
    456 
    457     wifi_promiscuous_enable(0);
    458     __wifi_local_connect(saved_ssid, saved_pass);
    459     ps_client.setServer(MQTT_SERVER_URL, MQTT_PORT);
    460     ps_client.setCallback(__mqtt_read_callback);
    461 
    462     if (ps_client.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
    463       ps_client.subscribe(MQTT_TOPIC_INPUT);
    464     }
    465   }
    466 
    467 }
    468 
    469 /*
    470  * Main routines for arduino things
    471  *
    472  * setup -> constructor, will set up the environment for the esp to do it thing
    473  * loop -> main execution loop. manages state etc
    474  */
    475 
    476 
    477 void setup() {
    478 
    479     // init led
    480     pinMode(LED, OUTPUT);
    481     randomSeed(millis());
    482 
    483     // init serial output
    484     Serial.begin(SERIAL_BAUD);
    485     while (!Serial) delay(QUICK_DELAY_TIME);
    486 
    487     delay(QUICK_DELAY_TIME);
    488 
    489     Serial.println("waking up.......");
    490     __wifi_setup_soft_ap();
    491     __blink_success();
    492    __net_get_public_ip(net_client, ip_address, 256);
    493    __switch_promiscuous_mode(1);
    494 }
    495 
    496 
    497 void loop() {
    498     Serial.println("[+] Looping...");
    499 
    500     delay(DELAY_TIME * 3);
    501     __switch_promiscuous_mode(0);
    502     delay(DELAY_TIME);
    503     ps_client.loop();
    504     __switch_promiscuous_mode(1);
    505 
    506 
    507     if (program_state == STATE_SOFT_AP_MODE) {
    508       __wifi_setup_soft_ap();
    509       goto endloop;
    510     }
    511 
    512     if (program_state == STATE_ASLEEP) {
    513       memset(mqtt_msg_to_send, 0, MQTT_MSG_SIZE);
    514 
    515       __switch_promiscuous_mode(0);
    516       DynamicJsonDocument js = __get_net_information(net_client, ip_address);
    517       serializeJson(js, mqtt_msg_to_send);
    518       Serial.printf("[MQTT] sending: %s\n", mqtt_msg_to_send);
    519       ps_client.publish(MQTT_TOPIC_OUTPUT, mqtt_msg_to_send, true);
    520       nb_packets = 0;
    521       __switch_promiscuous_mode(1);
    522     }
    523 
    524 endloop:
    525     delay(DELAY_TIME);
    526 
    527 }