【CVE-2025-40634】缓冲区溢出 EXP 公布

【CVE-2025-40634】缓冲区溢出 EXP 公布

原创 骨哥说事 骨哥说事 2025-05-21 06:32

声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。

****# 防走失:https://gugesay.com/

**不想错过任何消息?设置星标↓ ↓ ↓


概述

TP-Link Archer AX50 路由器在其固件版本1.0.14 Build 20240108 rel.42655(4555)上存在基于堆的缓冲区溢出漏洞,导致在LAN和WAN侧均可远程代码执行。

此漏洞与CVE-2020-10881相同,由Flashback团队发现,并在他们关于此漏洞的视频系列中进行了大量详细说明(见参考文献)。然而,利用过程略有不同。

EXP 地址见文末。

漏洞原因

此漏洞出现在conn-indicator二进制文件中,该文件负责通过定期发送 DNS 查询并在32000到61000之间的随机UDP端口上监听其响应来检查路由器是否连接到互联网。

接收并首先处理这些 DNS 响应数据包的函数是 TPDns_RecvAndResolve()
,位于0x00405e3c
。当使用recvfrom
接收数据包时,它被存储在buf中,buf的大小为2960字节。然后检查返回码是否正确(RCODE == 0)并检查数据包中的”问题”和”答案”数量(QDCOUNT和ANCOUNT)。

为了处理”答案”,它会调用process_resolved_IP()
,并传递buf的指针、指向buf内答案位置的answer_ptr
指针、答案数量(ANCOUNT)和其它标志:

undefined4 * TPDns_RecvAndResolve(int socket,void *param_2,int param_3){  [...]  byte buf [2960];  [...]      while( true ) {        recv_bytes = recvfrom(socket,buf + total_recv_bytes,0xb90 - total_recv_bytes,0,&sStack_50,                              local_38);        piVar2 = __errno_location();        if (recv_bytes == 0) goto RECV_ERROR;        if (recv_bytes < 0) break;        total_recv_bytes = total_recv_bytes + recv_bytes;        if (2959 < total_recv_bytes) goto PROCESS_DNS_RESP;      }  [...]                    /* Check that ANCOUNT is not 0 (answer contains at least one domain) */          puVar5 = (undefined4 *)0x0;          if (buf._6_2_ != 0) {            local_40 = 0;            puVar5 = process_resolved_IP(buf,answer_ptr,(uint)buf._6_2_,&local_3c,&local_40);            answer_ptr = answer_ptr + local_40;          }  [...]

函数 process_resolved_IP()
 位于 0x00405818,遍历每个答案并为每个答案调用 DNS_answer_parser()
。它传递相同的指针到 buf、answer,这是一个指向在 buf 中原始数据包内正在解析的current_answer
的指针,以及一个指向 current_answer
 的指针,这是一个大小为 256 的缓冲区:

undefined4 * process_resolved_IP(byte *buf,byte *answer_ptr,uint ANCOUNT,undefined4 *param_4,int *param_5){  [...]  byte current_answer [256];  ushort answer_flags [5];  i = 0;  puVar9 = (undefined4 *)0x0;  puVar7 = (undefined4 *)0x0;  answer = answer_ptr;do {                    /* Check if all answers have been parsed already */    if (i == ANCOUNT) {      if (param_4 != (undefined4 *)0x0) {        *param_4 = puVar7;      }      if (param_5 != (int *)0x0) {        *param_5 = (int)answer - (int)answer_ptr;      }      return puVar9;    }    bytes_processed = DNS_answer_parser(buf,answer,current_answer,1);    memcpy(answer_flags,answer + bytes_processed,10);    uVar1 = answer_flags._4_4_;    bytes_processed = bytes_processed + 10;    uVar6 = (uint)answer_flags[4];    uVar8 = (uint)answer_flags[0];    if (uVar8 == 2) {LAB_00405924:      DNS_answer_parser(buf,answer + bytes_processed,abStack_240,1);    }    elseif (uVar8 < 3) {      pbVar2 = answer + bytes_processed;      if (uVar8 == 1) {        sprintf((char *)abStack_240,"%u.%u.%u.%u",(uint)*pbVar2,(uint)pbVar2[1],(uint)pbVar2[2],                (uint)pbVar2[3]);      }    }    else {      if (uVar8 == 5) goto LAB_00405924;      if (uVar8 == 0x1c) {        inet_ntop(10,answer,(char *)abStack_240,0xff);      }    }    answer = answer + bytes_processed + uVar6;  [...]    i = i + 1;  } while( true );}

函数 DNS_answer_parser()
 位于 0x004054e0,逐个解析每个答案,这些答案由表示为….
 的域名组成。

例如,example.com 将表示为 7example3com
。该函数遍历构成答案中域名的每个
对,并检查
是否小于 63(domain_name & 0xc0 != 0
)。然后,它调用 memcpy 并将对应于 
 的答案中的 
 字节复制到 current_answer
。它对域名中的下一个 “`对重复此过程。

int DNS_answer_parser(byte *buf,byte *answer,byte *current_answer,int flag){int iVar1;  uint __n;int iVar2;  uint uVar3;  ushort flag_and_offset;  byte domain_name;  iVar2 = 0;do {    domain_name = *answer;    __n = (uint)domain_name;    iVar1 = 1;    if (__n == 0) {      *current_answer = 0;LAB_004055b0:      return iVar2 + iVar1;    }                    /* Check if compression mode is used */    if ((domain_name & 0xc0) != 0) {      flag_and_offset = CONCAT11(domain_name,answer[1]);      DNS_answer_parser(buf,buf + (flag_and_offset & 0x3fff),current_answer,flag);      iVar1 = 2;      goto LAB_004055b0;    }    uVar3 = __n + 1;    if (flag == 0) {      *current_answer = '.';      memcpy(current_answer + 1,answer + 1,__n);      __n = uVar3;    }    else {      memcpy(current_answer,answer + 1,__n);    }    answer = answer + uVar3;    current_answer = current_answer + __n;    iVar2 = iVar2 + uVar3;    flag = 0;  } while( true );}

由于current_answer
只有256字节长,攻击者可以发送一个包含足够大的域名以溢出缓冲区的答案数据包。

EXP 地址:
https://github.com/hacefresko/CVE-2025-40634

  • END –

加入星球,随时交流:

*(会员统一定价):128元/年(0.35元/天)***

感谢阅读,如果觉得还不错的话,欢迎分享给更多喜爱的朋友~