Преглед изворни кода

Merge flip_wifi from https://github.com/jblanked/FlipWiFi

WillyJL пре 8 месеци
родитељ
комит
c83de9032e

+ 3 - 0
flip_wifi/CHANGELOG.md

@@ -1,3 +1,6 @@
+## v1.6
+- Added Deauthentication mode.
+
 ## v1.5.2
 - Fixed a BusFault when leaving the AP Mode.
 - Increased the buffer size for sending HTML data.

+ 14 - 10
flip_wifi/README.md

@@ -1,8 +1,8 @@
-FlipWiFi is the companion app for the popular FlipperHTTP flash, originally introduced in the https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP. It allows you to scan and save WiFi networks for use across all FlipperHTTP apps.
+FlipWiFi is the companion app for the popular FlipperHTTP firmware. It allows you to scan and save Wi-Fi networks for use across all FlipperHTTP apps, set up captive portals, and send deauthentication attacks.
 
 ## Requirements
-- WiFi Developer Board, BW16, Raspberry Pi, or ESP32 Device flashed with FlipperHTTP v1.8.5 or higher: https://github.com/jblanked/FlipperHTTP
-- 2.4 GHz WiFi Access Point
+- Wi-Fi Developer Board, BW16, Raspberry Pi, or ESP32 device flashed with FlipperHTTP v2.0 or higher: https://github.com/jblanked/FlipperHTTP
+- 2.4 GHz or 5 GHz Wi-Fi access point
 
 ## Connect Online
 - Discord: https://discord.gg/5aN9qwkEc6
@@ -12,15 +12,19 @@ FlipWiFi is the companion app for the popular FlipperHTTP flash, originally intr
 
 ## Features
 
-- **Scan**: Discover nearby WiFi networks and add them to your list.
-- **AP Mode**: Create a captive portal with custom HTML and auto-input routing.
-- **Saved Access Points**: View your saved networks, manually add new ones, or configure the WiFi network to be used across all FlipperHTTP apps.
+- **Scan**: Discover nearby Wi-Fi networks and add them to your list.
+- **Deauthentication**: Send deauthentication frames to disconnect clients from a selected network for testing or troubleshooting.
+- **Captive Portal**: Create a captive portal with custom HTML and auto-input routing.
+- **Saved Access Points**: View your saved networks, manually add new ones, or configure the Wi-Fi network to be used across all FlipperHTTP apps.
 
 ## Setup
 
 FlipWiFi automatically allocates the necessary resources and initializes settings upon launch. If WiFi settings have been previously configured, they are loaded automatically for easy access. You can also edit the list of WiFi settings by downloading and modifying the "wifi_list.txt" file located in the "/SD/apps_data/flip_wifi/data" directory. To use the app:
 
-1. **Flash the WiFi Developer Board**: Follow the instructions to flash the WiFi Dev Board with FlipperHTTP: https://github.com/jblanked/FlipperHTTP
-2. **Install the App**: Download FlipWiFi from the Flipper Lab.
-3. **Launch FlipWiFi**: Open the app on your Flipper Zero.
-4. Connect, review, and save WiFi networks.
+1. **Flash the Wi-Fi Developer Board**: Follow the instructions to flash the Wi-Fi Dev Board with FlipperHTTP: https://github.com/jblanked/FlipperHTTP  
+2. **Install the App**: Download FlipWiFi from the Flipper Lab.  
+3. **Launch FlipWiFi**: Open the app on your Flipper Zero.  
+4. Connect, review, and save Wi-Fi networks.
+
+## Disclaimer
+Please use this firmware responsibly. JBlanked and JBlanked, LLC disclaim all liability for any misuse of this firmware. You are solely responsible for your actions.

+ 2 - 1
flip_wifi/alloc/flip_wifi_alloc.c

@@ -19,7 +19,8 @@ FlipWiFiApp *flip_wifi_app_alloc()
         return NULL;
     }
     submenu_add_item(app->submenu_main, "Scan", FlipWiFiSubmenuIndexWiFiScan, callback_submenu_choices, app);
-    submenu_add_item(app->submenu_main, "AP Mode", FlipWiFiSubmenuIndexWiFiAP, callback_submenu_choices, app);
+    submenu_add_item(app->submenu_main, "Deauthentication", FlipWiFiSubmenuIndexWiFiDeauth, callback_submenu_choices, app);
+    submenu_add_item(app->submenu_main, "Captive Portal", FlipWiFiSubmenuIndexWiFiAP, callback_submenu_choices, app);
     submenu_add_item(app->submenu_main, "Saved APs", FlipWiFiSubmenuIndexWiFiSaved, callback_submenu_choices, app);
     submenu_add_item(app->submenu_main, "Commands", FlipWiFiSubmenuIndexCommands, callback_submenu_choices, app);
     submenu_add_item(app->submenu_main, "Info", FlipWiFiSubmenuIndexAbout, callback_submenu_choices, app);

+ 1 - 1
flip_wifi/application.fam

@@ -9,6 +9,6 @@ App(
     fap_icon_assets="assets",
     fap_author="JBlanked",
     fap_weburl="https://github.com/jblanked/FlipWiFi",
-    fap_version="1.5.2",
+    fap_version="1.6",
     fap_description="FlipperHTTP companion app.",
 )

BIN
flip_wifi/assets/01-home.png


+ 36 - 1
flip_wifi/callback/alloc.c

@@ -254,7 +254,7 @@ bool alloc_text_inputs(void *context, uint32_t view)
     case FlipWiFiSubmenuIndexWiFiAPSetSSID:
         if (!app->uart_text_input)
         {
-            if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter AP SSID", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, callback_ap_ssid_updated, callback_to_submenu_saved, &app->view_dispatcher, app))
+            if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter AP SSID", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, callback_ap_ssid_updated, callback_to_submenu_main, &app->view_dispatcher, app))
             {
                 FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
                 return false;
@@ -266,6 +266,27 @@ bool alloc_text_inputs(void *context, uint32_t view)
             }
         }
         return true;
+    case FlipWiFiViewTextInputDeauth:
+        if (!app->uart_text_input)
+        {
+            if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter SSID", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, callback_text_updated_deauth, callback_to_submenu_scan, &app->view_dispatcher, app))
+            {
+                FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Deauth");
+                return false;
+            }
+            if (!app->uart_text_input)
+            {
+                FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Deauth");
+                return false;
+            }
+            char deauth_ssid[64];
+            if (load_char("deauth_ssid", deauth_ssid, sizeof(deauth_ssid)))
+            {
+                strncpy(app->uart_text_input_temp_buffer, deauth_ssid, app->uart_text_input_buffer_size);
+                app->uart_text_input_temp_buffer[app->uart_text_input_buffer_size - 1] = '\0';
+            }
+        }
+        return true;
     }
     return false;
 }
@@ -304,6 +325,20 @@ bool alloc_views(void *context, uint32_t view)
             }
         }
         return true;
+    case FlipWiFiViewWiFiDeauth:
+        if (!app->view_wifi)
+        {
+            if (!easy_flipper_set_view(&app->view_wifi, FlipWiFiViewGeneric, callback_view_draw_callback_deauth, callback_view_input_callback_deauth, callback_to_submenu_main, &app->view_dispatcher, app))
+            {
+                return false;
+            }
+            if (!app->view_wifi)
+            {
+                FURI_LOG_E(TAG, "Failed to allocate view for WiFi Deauth");
+                return false;
+            }
+        }
+        return true;
     default:
         return false;
     }

+ 151 - 1
flip_wifi/callback/callback.c

@@ -86,6 +86,116 @@ void callback_ap_ssid_updated(void *context)
     save_char("ap_ssid", app->uart_text_input_temp_buffer);
     view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
 }
+void callback_text_updated_deauth(void *context)
+{
+    FlipWiFiApp *app = (FlipWiFiApp *)context;
+    furi_check(app);
+    if (!app->uart_text_input_temp_buffer)
+    {
+        FURI_LOG_E(TAG, "Text input buffer is NULL");
+        return;
+    }
+    if (!app->uart_text_input_temp_buffer[0])
+    {
+        FURI_LOG_E(TAG, "Text input buffer is empty");
+        return;
+    }
+    save_char("deauth_ssid", app->uart_text_input_temp_buffer);
+    if (!app->fhttp)
+    {
+        app->fhttp = flipper_http_alloc();
+        if (!app->fhttp)
+        {
+            easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
+            return;
+        }
+    }
+    // first check version number
+    if (!flipper_http_send_data(app->fhttp, "[VERSION]"))
+    {
+        easy_flipper_dialog("[ERROR]", "Failed to send version command");
+        flipper_http_free(app->fhttp);
+        return;
+    }
+    while (app->fhttp->last_response == NULL || strlen(app->fhttp->last_response) == 0)
+    {
+        furi_delay_ms(100);
+    }
+    // check if verison is 2.0
+    if (strstr(app->fhttp->last_response, "2.0") == NULL)
+    {
+        FURI_LOG_I(TAG, app->fhttp->last_response);
+        easy_flipper_dialog("[ERROR]", "FlipperHTTP version 2.0 or\nhigher is required");
+        flipper_http_free(app->fhttp);
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        return;
+    }
+    // erase the response
+    if (app->fhttp->last_response)
+        snprintf(app->fhttp->last_response, RX_BUF_SIZE, "%s", "");
+    Loading *loading = loading_alloc();
+    int32_t loading_view_id = 87654321; // Random ID
+    view_dispatcher_add_view(app->view_dispatcher, loading_view_id, loading_get_view(loading));
+    view_dispatcher_switch_to_view(app->view_dispatcher, loading_view_id);
+    if (!flipper_http_deauth_start(app->fhttp, app->uart_text_input_temp_buffer))
+    {
+        easy_flipper_dialog("[ERROR]", "Failed to start deauth attack");
+        flipper_http_free(app->fhttp);
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        view_dispatcher_remove_view(app->view_dispatcher, loading_view_id);
+        loading_free(loading);
+        loading = NULL;
+        return;
+    }
+    while (app->fhttp->last_response == NULL || strlen(app->fhttp->last_response) == 0)
+    {
+        furi_delay_ms(100);
+    }
+    if (strstr(app->fhttp->last_response, "[DEAUTH/STARTING]") == NULL)
+    {
+        char response[256];
+        snprintf(response, sizeof(response), "Failed to start deauth attack:\n%s", app->fhttp->last_response);
+        easy_flipper_dialog("[ERROR]", response);
+        flipper_http_free(app->fhttp);
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        view_dispatcher_remove_view(app->view_dispatcher, loading_view_id);
+        loading_free(loading);
+        loading = NULL;
+        return;
+    }
+    while (strstr(app->fhttp->last_response, "[DEAUTH/STARTING]") != NULL)
+    {
+        furi_delay_ms(100);
+    }
+    if (strstr(app->fhttp->last_response, "[ERROR]") != NULL)
+    {
+        char response[256];
+        snprintf(response, sizeof(response), "Failed to start deauth attack:\n%s", app->fhttp->last_response);
+        easy_flipper_dialog("[ERROR]", response);
+        flipper_http_free(app->fhttp);
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        view_dispatcher_remove_view(app->view_dispatcher, loading_view_id);
+        loading_free(loading);
+        loading = NULL;
+        return;
+    }
+
+    if (!alloc_views(app, FlipWiFiViewWiFiDeauth))
+    {
+        FURI_LOG_E(TAG, "Failed to allocate view for WiFi Deauth");
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        view_dispatcher_remove_view(app->view_dispatcher, loading_view_id);
+        loading_free(loading);
+        loading = NULL;
+        return;
+    }
+
+    // switch to a canvas view
+    view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
+    view_dispatcher_remove_view(app->view_dispatcher, loading_view_id);
+    loading_free(loading);
+    loading = NULL;
+}
 
 void callback_redraw_submenu_saved(void *context)
 {
@@ -143,6 +253,17 @@ void callback_view_draw_callback_saved(Canvas *canvas, void *model)
     canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Edit");
 }
 
+// Callback for drawing the deauth screen
+void callback_view_draw_callback_deauth(Canvas *canvas, void *model)
+{
+    UNUSED(model);
+    canvas_clear(canvas);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str(canvas, 0, 10, "Deauthing...");
+    canvas_draw_icon(canvas, 0, 53, &I_ButtonBACK_10x8);
+    canvas_draw_str_aligned(canvas, 12, 54, AlignLeft, AlignTop, "Hit Back to stop");
+}
+
 // Input callback for the view (async input handling)
 bool callback_view_input_callback_scan(InputEvent *event, void *context)
 {
@@ -161,6 +282,26 @@ bool callback_view_input_callback_scan(InputEvent *event, void *context)
     }
     return false;
 }
+
+// Input callback for the view (async input handling)
+bool callback_view_input_callback_deauth(InputEvent *event, void *context)
+{
+    FlipWiFiApp *app = (FlipWiFiApp *)context;
+    if (event->type == InputTypePress && event->key == InputKeyBack)
+    {
+        if (app->fhttp)
+        {
+            flipper_http_deauth_stop(app->fhttp);
+            furi_delay_ms(200);
+            flipper_http_free(app->fhttp);
+            app->fhttp = NULL;
+        }
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
+        return true;
+    }
+    return false;
+}
+
 // Input callback for the view (async input handling)
 bool callback_view_input_callback_saved(InputEvent *event, void *context)
 {
@@ -391,7 +532,7 @@ static void update_text_box(FlipWiFiApp *app)
             text_box_reset(app->textbox);
             text_box_set_focus(app->textbox, TextBoxFocusEnd);
             text_box_set_font(app->textbox, TextBoxFontText);
-            text_box_set_text(app->textbox, "AP Connected... please wait");
+            text_box_set_text(app->textbox, "Connected... please wait");
         }
         else if (furi_string_size(app->fhttp->last_response_str) != last_response_len)
         {
@@ -568,6 +709,15 @@ void callback_submenu_choices(void *context, uint32_t index)
             return;
         }
         break;
+    case FlipWiFiSubmenuIndexWiFiDeauth:
+        free_all(app);
+        if (!alloc_text_inputs(app, FlipWiFiViewTextInputDeauth))
+        {
+            FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
+            return;
+        }
+        view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
+        break;
     case FlipWiFiSubmenuIndexWiFiSaved:
         free_all(app);
         if (!alloc_submenus(app, FlipWiFiViewSubmenuSaved))

+ 3 - 0
flip_wifi/callback/callback.h

@@ -10,10 +10,13 @@ uint32_t callback_to_submenu_scan(void *context);
 uint32_t callback_to_submenu_saved(void *context);
 void callback_custom_command_updated(void *context);
 void callback_ap_ssid_updated(void *context);
+void callback_text_updated_deauth(void *context);
 void callback_redraw_submenu_saved(void *context);
 void callback_view_draw_callback_scan(Canvas *canvas, void *model);
 void callback_view_draw_callback_saved(Canvas *canvas, void *model);
+void callback_view_draw_callback_deauth(Canvas *canvas, void *model);
 bool callback_view_input_callback_scan(InputEvent *event, void *context);
+bool callback_view_input_callback_deauth(InputEvent *event, void *context);
 bool callback_view_input_callback_saved(InputEvent *event, void *context);
 void callback_timer_callback(void *context);
 void callback_submenu_choices(void *context, uint32_t index);

+ 8 - 4
flip_wifi/flip_wifi.h

@@ -6,7 +6,7 @@
 #include <storage/storage.h>
 
 #define TAG "FlipWiFi"
-#define VERSION "1.5.2"
+#define VERSION "1.6"
 #define VERSION_TAG TAG " " VERSION
 #define MAX_SCAN_NETWORKS 100
 #define MAX_SAVED_NETWORKS 25
@@ -18,6 +18,7 @@ typedef enum
     FlipWiFiSubmenuIndexAbout,
     //
     FlipWiFiSubmenuIndexWiFiScan,
+    FlipWiFiSubmenuIndexWiFiDeauth,
     FlipWiFiSubmenuIndexWiFiAP,
     FlipWiFiSubmenuIndexWiFiSaved,
     FlipWiFiSubmenuIndexCommands,
@@ -37,9 +38,11 @@ typedef enum
 // Define a single view for our FlipWiFi application
 typedef enum
 {
-    FlipWiFiViewWiFiScan,  // The view for the wifi scan screen
-    FlipWiFiViewWiFiAP,    // The view for the wifi AP screen
-    FlipWiFiViewWiFiSaved, // The view for the wifi scan screen
+    FlipWiFiViewWiFiScan,       // The view for the wifi scan screen
+    FlipWiFiViewWiFiDeauth,     // The view for the wifi scan screen
+    FlipWiFiViewWiFiDeauthWait, // The view for the wifi scan screen
+    FlipWiFiViewWiFiAP,         // The view for the wifi AP screen
+    FlipWiFiViewWiFiSaved,      // The view for the wifi scan screen
     //
     FlipWiFiViewSubmenuMain,     // The submenu for the main screen
     FlipWiFiViewSubmenuScan,     // The submenu for the wifi scan screen
@@ -48,6 +51,7 @@ typedef enum
     FlipWiFiViewSubmenuCommands, // The submenu for the fast commands screen
     FlipWiFiViewAbout,           // The about screen
     FlipWiFiViewTextInputScan,   // The text input screen for the wifi scan screen
+    FlipWiFiViewTextInputDeauth, // The text input screen for the wifi scan screen
     FlipWiFiViewTextInputSaved,  // The text input screen for the wifi saved screen
     //
     FlipWiFiViewTextInputSavedAddSSID,     // The text input screen for the wifi saved screen

+ 48 - 0
flip_wifi/flipper_http/flipper_http.c

@@ -392,6 +392,54 @@ bool flipper_http_append_to_file(
     return true;
 }
 
+/**
+ * @brief      Send a command to deauthenticate a WiFi network.
+ * @return     true if the request was successful, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_deauth_start(FlipperHTTP *fhttp, const char *ssid)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(HTTP_TAG, "flipper_http_deauth_start: Failed to get context.");
+        return false;
+    }
+    if (!ssid)
+    {
+        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_deauth_start.");
+        return false;
+    }
+
+    char buffer[256];
+
+    int ret = snprintf(buffer, sizeof(buffer), "[DEAUTH]{\"ssid\":\"%s\"}", ssid);
+
+    if (ret < 0 || ret >= (int)sizeof(buffer))
+    {
+        FURI_LOG_E("FlipperHTTP", "Failed to format WiFi deauth command.");
+        return false;
+    }
+
+    return flipper_http_send_data(fhttp, buffer);
+}
+
+/**
+ * @brief      Send a request to stop the deauth
+ * @return     true if the request was successful, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_deauth_stop(FlipperHTTP *fhttp)
+{
+    if (!fhttp)
+    {
+        FURI_LOG_E(HTTP_TAG, "flipper_http_deauth_stop: Failed to get context.");
+        return false;
+    }
+    return flipper_http_send_data(fhttp, "[DEAUTH/STOP]");
+}
+
 /**
  * @brief      Load data from a file.
  * @return     The loaded data as a FuriString.

+ 16 - 0
flip_wifi/flipper_http/flipper_http.h

@@ -125,6 +125,22 @@ bool flipper_http_append_to_file(
     bool start_new_file,
     char* file_path);
 
+/**
+ * @brief      Send a command to deauthenticate a WiFi network.
+ * @return     true if the request was successful, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_deauth_start(FlipperHTTP *fhttp, const char *ssid);
+
+/**
+ * @brief      Send a request to stop the deauth
+ * @return     true if the request was successful, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_deauth_stop(FlipperHTTP *fhttp);
+
 /**
  * @brief      Load data from a file.
  * @return     The loaded data as a FuriString.