声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。 |
防走失: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,逐个解析每个答案,这些答案由表示为<len><domain><len><domain>....
的域名组成。
例如,example.com 将表示为 7example3com
。该函数遍历构成答案中域名的每个<len><domain>
对,并检查<len>
是否小于 63(domain_name & 0xc0 != 0
)。然后,它调用 memcpy 并将对应于 <domain>
的答案中的 <len>
字节复制到 current_answer
。它对域名中的下一个 ``
intDNS_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元/天)感谢阅读,如果觉得还不错的话,欢迎分享给更多喜爱的朋友~
原文始发于微信公众号(骨哥说事):【CVE-2025-40634】缓冲区溢出 EXP 公布
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论