Tenda-AC15路由器CVE:四个缓冲区溢出漏洞分析复现
CVE-2020-13394
漏洞介绍
| 项目 | 内容 |
|---|---|
| CVE编号 | CVE-2020-13394 |
| 漏洞名称 | Tenda多款产品httpd服务缓冲区溢出漏洞 |
| 漏洞类型 | 缓冲区溢出 (CWE-120: Buffer Copy without Checking Size of Input) |
| CVSS v3.1评分 | 9.8 (严重) |
| 攻击向量 | 网络 (AV:N) |
| 权限要求 | 无 |
| 影响范围 | 多款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_multi_TD01) - AC18 (固件 V15.03.05.19(6318)_CN) |
| 漏洞描述 | 路由器的httpd服务在处理对/goform/SetNetControlList URL的POST请求时,未能检查list参数的长度。程序使用strcpy函数将该参数值直接复制到栈上的局部变量中,导致栈缓冲区溢出。 |
| 利用后果 | 攻击者可以构建特制的payload,造成服务崩溃或实现任意代码执行,从而完全控制设备。 |
| 披露日期 | 2020年5月22日 |
| 补丁情况 | 暂无官方补丁信息 (N/A) |
漏洞函数
直接看IDA,说是在SetNetControlList函数,直接定位cgi接口函数
发现当url=/goform/SetNetControlList会执行formSetQosBand函数
formSetQosBand:
1 | int __fastcall formSetQosBand(int a1) |
sub_7DD20(v8, "bandwidth.mode", 10):a1指向list参数,a2=bandwidth.mode,a3=10
1 | int __fastcall sub_7DD20(char *a1, int a2, unsigned __int8 a3) |
漏洞分析
很明显。可以发现漏洞是出现在sub_7d020的strcpy函数,未进行长度检查从而造成溢出,所以关键是让函数执行到这里,往回看,首先是src,也就是a1(我们输入的内容)必须包含\n,不然无法继续while循环
测试
poc
1 | from pwn import * |
成功了
同时我们可以得到溢出长度1960
然后就可以获取root权限了
CVE-2020-13392
漏洞介绍
| 项目 | 内容 |
|---|---|
| 漏洞名称 | 多款Tenda产品缓冲区错误漏洞 |
| 厂商 | 腾达(Tenda) |
| CNNVD编号 | CNNVD-202005-1142 |
| CVE编号 | CVE-2020-13392 |
| 危害等级 | 超危(CVSS v3.1:9.8 / Critical) |
| 漏洞类型 | 缓冲区错误(CWE-120:未进行输入大小检查的缓冲区拷贝) |
| 收录时间 | 2020-05-22 |
| 更新时间 | 2020-05-28 |
| 漏洞根源 | 路由器Web服务器httpd中,处理/goform/setcfm URL的funcpara1 POST参数时,使用sprintf直接将参数值写入栈上局部变量,未做边界检查,导致可覆盖函数返回地址,从而实现任意代码执行或服务崩溃 |
漏洞函数
看cgi函数可以得到方位这个url会执行formSetCfm
formSetCfm:
1 | int __fastcall formSetCfm(int a1) |
sub_4EC58:a1指向funcpara1,a2指向funcpara2,a3=126
1 | int __fastcall sub_4EC58(const char *a1, char *a2, unsigned __int8 a3) |
漏洞分析
简单地说,就是sub_4ec58()函数中sprintf函数,首先是要让程序进入这个函数,要求就是v5=save_list_data,然后就是满足strlen(a2)>4,a2是funcpara2的参数,第一个printf函数触发是要满足a2中有个~,而第二个就是正常溢出就好了
poc
第一个sprintf
1 | from pwn import * |
成功
第二个sprintf
1 | from pwn import * |
成功,同时得到偏移是84
这里要说明一下,第一个连接到gdb上会出现错误,无法出现第二个poc的结果,可能是因为在while循环内数据覆盖了某个数值的原因
CVE-2020-13391
漏洞介绍
| 项目 | 内容 |
|---|---|
| CVE编号 | CVE-2020-13391 |
| CNNVD编号 | CNNVD-202005-1141 |
| CNVD编号 | CNVD-2020-31397 |
| 漏洞名称 | 多款Tenda产品缓冲区错误漏洞 |
| 危害等级 | 超危 / 严重 |
| CVSS v3.1评分 | 9.8 (Critical) |
| 漏洞类型 | CWE-120: 未进行输入大小检查的缓冲区拷贝(传统缓冲区溢出) |
| 披露时间 | 2020-05-22 |
| 补丁状态 | 暂无官方补丁 |
| 漏洞根源 | 路由器Web服务器httpd在处理对/goform/SetSpeedWan URL的POST请求时,对参数speed_dir的处理不安全:程序直接使用sprintf函数将用户输入的speed_dir值写入栈上固定大小的局部缓冲区,未进行任何边界检查。当攻击者构造超长的speed_dir参数时,数据会溢出缓冲区并覆盖函数的返回地址,导致函数返回时跳转到攻击者控制的地址,从而实现任意代码执行或服务崩溃。 |
漏洞函数
cgi函数查找,可知访问/goform/SetSpeedWan会执行formSetSpeedWan
formSetSpeedWan:
1 | int __fastcall formSetSpeedWan(int a1) |
漏洞分析
很明显漏洞时出现在 sprintf((char *)s, "{\"errCode\":%d,\"speed_dir\":%s}", v8, v7);,这个函数的意思是将 {"errCode":0,"speed_dir":"用户输入的内容"} 赋值给s,没有检查长度
所以就是怎么执行到那里,发现没有任何条件
poc
1 | from pwn import * |
CVE-2020-13390
漏洞介绍
| 项目 | 内容 |
|---|---|
| CVE编号 | CVE-2020-13390 |
| CNNVD编号 | CNNVD-202005-1140 |
| CNVD编号 | CNVD-2020-31387 |
| 漏洞名称 | 多款Tenda产品缓冲区错误漏洞 |
| 危害等级 | 超危 / 严重 |
| CVSS v3.1评分 | 9.8 (Critical) |
| 漏洞类型 | CWE-120: 未进行输入大小检查的缓冲区拷贝(传统缓冲区溢出) |
| 披露时间 | 2020-05-22 |
| 补丁状态 | 暂无官方补丁 |
| 漏洞根源 | 路由器Web服务器httpd在处理对/goform/addressNat URL的POST请求时,对参数entrys和mitInterface的处理不安全:程序直接使用sprintf函数将用户输入的参数值写入栈上固定大小的局部缓冲区,未进行任何边界检查。当攻击者构造超长的参数时,数据会溢出缓冲区并覆盖函数的返回地址,导致函数返回时跳转到攻击者控制的地址,从而实现任意代码执行或服务崩溃。 |
漏洞函数
寻找cgi处理函数发现访问url会执行fromAddressNat函数
fromAddressNat:
1 | int __fastcall fromAddressNat(int a1) |
漏洞分析
函数直接使用sprint,未进行长度检查
poc
第一个sprintf
1 | from pwn import * |
成功了
第二个sprintf
1 | from pwn import * |