Tenda AC9 Firmware Analysis
Reverse Engineering the Tenda AC9 Firmware
Routers are the unsung heroes of our connected lives—quietly humming away, keeping us online. But what’s really going on inside them? I recently got curious about my Tenda AC9 router and decided to crack open its firmware—US_AC9V1.0BR_V15.03.05.15_multi_TDE01.bin
—to see what secrets it holds. Spoiler: it’s a mix of the expected, the quirky, and the slightly unsettling. Here’s what I found, how I got there, and why it might matter.
Step 1: Cracking the Shell with Binwalk
First things first—I needed to unpack the firmware. It’s a 7.4MB file, a u-boot uImage for a Linux/ARM kernel, timestamped October 29, 2020. Sounded like a job for binwalk
, a go-to tool for firmware analysis. After installing it (sudo apt install binwalk
), I ran a quick scan:
wget https://github.com/mrxehmad/Tenda-AC9-Firmware-Analysis/raw/refs/heads/main/US_AC9V1.0BR_V15.03.05.15_multi_TDE01.zip
binwalk US_AC9V1.0BR_V15.03.05.15_multi_TDE01.bin
The output revealed a TRX header, an LZMA-compressed kernel, and a SquashFS filesystem. To get inside, I extracted it:
binwalk -e US_AC9V1.0BR_V15.03.05.15_multi_TDE01.bin
This gave me a folder with a compressed kernel (5C.LZMA
) and a filesystem (18EB48.squashfs
). One more command to decompress the filesystem:
unsquashfs -f -d squashfs-root 18EB48.squashfs
And voilà—a treasure trove of files in squashfs-root/
. Time to explore.
Step 2: Open Ports and a Network Surprise
Before diving into the files, I scanned my router (10.1.15.1
) with Nmap to see what it’s exposing:
PORT STATE SERVICE
80/tcp open http
5500/tcp open hotline
8180/tcp open unknown
9000/tcp open cslistener
10004/tcp open emcrmirccd
Port 80? Expected for the web interface. 8180? Probably a secondary UI (more on that later). But 5500, 9000, and 10004? Those raised eyebrows. “Hotline” and “emcrmirccd” didn’t scream “router,” so I knew I had some digging to do.
Step 3: The Filesystem Tells a Story
Inside squashfs-root/
, I found a mix of binaries, libraries, and configs. Nginx was running on port 8180 (/usr/bin/nginx
), serving a Luci interface with a FastCGI backend on 8188 (/usr/bin/app_data_center
). Port 80 was handled by httpd
—standard stuff. But then things got interesting.
Hardcoded Connections
Grepping through the files, I spotted hardcoded IPs and domains:
cloud.tenda.com.cn
182.254.148.51
download.cloud.tenda.com.cn
182.254.218.214
182.254.136.200
These popped up in files like ./bin/auto_discover
, which sends your MAC address and timestamp to api.cloud.tenda.com.cn/route/mac/v1
. Device tracking, perhaps? Meanwhile, httpd
fetches ad URLs from api.cloud.tenda.com.cn/route/adverts/v1
, defaulting to www.tenda.com.cn
if it fails. An old-school User-Agent (MSIE 5.01
) hinted this code hasn’t been touched in years.
Quirky Binaries
./bin/speedtest
: Pings domains likewww.taobao.com
andwww.google.com
—likely a bandwidth test../bin/88ip
: Sends XML tolink.dipserver.com
for dynamic DNS../bin/logserver
: Tries (and often fails) to ship logs somewhere external../usr/sbin/telnetd
: A Telnet server! No startup script activated it, but its presence felt like a debug leftover.
Firewall Rules
Hardcoded iptables
commands caught my eye:
iptables -A OUTPUT -p udp --dport %d -m state --state NEW -j %s
iptables -A %s -o %s -j DROP
These seem to manage outbound traffic—maybe to those Tenda cloud servers?
Step 4: What Does It Mean?
This firmware is chatty. It phones home to Tenda’s cloud, potentially sharing device info, fetching ads, and running services on non-standard ports (5500 and 10004 still elude me—debug backdoors?). The Telnet binary is dormant but tempting for anyone with root access. And those hardcoded IPs? A security researcher’s red flag—perfect for spoofing or tracking.
Why It Matters
Routers like the Tenda AC9 are everywhere, yet we rarely peek inside. This little adventure showed me how much they’re doing behind the scenes—some useful, some questionable. I’ve dumped my findings on GitHub (link below) with extraction steps, hoping others might join the fun. Could 5500 be a mislabeled Telnet port? Is libupnp.so
behind 9000? I’m a newbie at this, but tools like Ghidra are calling—I’ll dive deeper if you do.
What do you think? Ever analyzed your own gear? Let’s swap notes!