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 }