Tachyon-Networks TNA-30X Research
Introduction
Kicking off a series of blog posts, we will take a nose dive into the research on the Tachyon-Networks TNA-30X series devices.
In the coming weeks further posts will provide details on the various vulnerabilities discovered during this research, these vulnerabilities were disclosed in early June and were quickly patched by the vendor.
Tear Down
With physical access to a device, a great starting point is to open it up and see how the device is built, it may also lead to options to dump firmwares or obtain a terminal interface to the device.
Removing the 12x hex screws on the front cover quickly reveals the internals of the device, with a main PCB attached to a Peraso PRM2143-01 antenna PCB via ribbon cable, reviewing the data sheet suggests this ribbon cable is a USB3 interface.
The remaining components on this side appear to be mostly ethernet and support systems for power, there does appear to be what looks like an unpopulated M.2 PCIe interface (unconfirmed).
Removing the screws from the main PCB and flipping over, reveals the core components
- CPU - Cortina CA8289
- Quad-core ARM (Cortex-A55) CPU @1.5GHz (64-bit)
- Integrated SerDes and xPON MAC
- Dual 10Gbps XFI/USXGMII interfaces
- Multiple USB 3.0 ports and PCIe ports
- RAM - 2x Winbond W632GU6NB-12
- 2G bits DDR3L SDRAM
- Total 512MB RAM
- Storage - Micron 29F1G08ABAEAWP:E
- 128MB
Finding UART
During the tear down we noted 4 unpopulated pin headers, UART is a common console port which consists of 3 or 4 pins, matching what we appear to have found.
With the device off, using a multimeter in continuity mode we are able to identify the GND (ground) pin by checking for continunity between a known ground point on the device and going through each pin until continunity is found.
Next we power the device up and using the multimeter in voltage mode, we check the remaining pins for a constant voltage of usually 3.3V or 5V, this is likely to be the VCC pin.
The two remaining pins are likely to be RX and TX, with the multimeter in voltage mode, monitor each of the pins during startup, the pin with a voltage that flucates is likely to be TX and the pin with a stable or no voltage is likely to be the RX pin.
Getting console
Using a USB TTL/UART adapter and some pogo pins, attach to the device
Device | Adapter |
---|---|
TX | RX |
RX | TX |
GND | GND |
VCC | N/C |
Using a serial terminal (eg. PuTTY) connect at 11500 baud, this is a common baud rate and is a great starting point.
With this serial connection we discover that the device boots direct into a root shell! Allowing for quick extraction of the firmware and exploration of the device.
U-Boot 2020.04-g1ee45d52 (Jul 18 2022 - 13:48:03 +0000)Venus-SoC
CPU: Cortina Venus
DRAM: 496 MiB
WDT: Started with servicing (60s timeout)
NAND: Configure DMA ordering
ONFI
P-NAND : MT29F1G08ABAEAWP
Chip Size: 128MB
Block Size: 128KB
Page Size: 2048B
OOB Size: 64B
128 MiB
Loading Environment from NAND... OK
...
Hit ESC key to stop autoboot: 0
Booting from partition: 2
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.14.172 (builder@hoss2) (gcc version 8.3.0 (OpenWrt GCC 8.3.0 r12467-ac9fc6b983)) #0 SMP Tue Dec 13 16:16:47 2022
[ 0.000000] Boot CPU: AArch64 Processor [411fd050]
[ 0.000000] Machine model: Tachyon Networks TNA-110
...
[ 0.000000] Kernel command line: console=earlycon=serial,0xf4329148 console=ttyS0,115200 mtdparts=ca_nand_flash:4M@0x0(u-boot),2M(u-boot-env),2M(hwinfo),8M(config),16M(persist),48M(ubi1),48M(ubi2) ubi.mtd=6
...
[ 4.219858] 7 cmdlinepart partitions found on MTD device ca_nand_flash
[ 4.226317] Creating 7 MTD partitions on "ca_nand_flash":
[ 4.231666] 0x000000000000-0x000000400000 : "u-boot"
[ 4.237129] 0x000000400000-0x000000600000 : "u-boot-env"
[ 4.242712] 0x000000600000-0x000000800000 : "hwinfo"
[ 4.247991] 0x000000800000-0x000001000000 : "config"
[ 4.253248] 0x000001000000-0x000002000000 : "persist"
[ 4.258598] 0x000002000000-0x000005000000 : "ubi1"
[ 4.263799] 0x000005000000-0x000008000000 : "ubi2"
...
Press any key to enter console..
..
BusyBox v1.31.1 () built-in shell (ash)
___ ____ ____ _ _ _ _ ____ _ _ _ _ ____ ___ _ _ _ ____ ____ _ _ ____ ®
| |__| | |__| \_/ | | |\ | |\ | |___ | | | | | | |__/ |_/ [__
| | | |___ | | | |__| | \| | \| |___ | |_|_| |__| | \ | \_ ___]
Tachyon Networks® (c) 2020-2023
https://tachyon-networks.com
1.11.1 rev 53981
root@(none):~#
Running Processes and listening ports
Using the usual netstat -tunelp
and ps -w
we can see the device has a minimal network exposure by only listening on TCP 80 & 443, along with UDP 514.
Looking at the program for TCP 80 & 443, we can see its LUA based, and when referencing the process list we can observe the full command {wsxavante} /usr/bin/lua /usr/sbin/wsxavante /var/etc/http
revealing the webserver is based on a deriative of xavante
root@tachyon-ptmp:/tmp# netstat -tunelp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 500/lua
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 500/lua
tcp 0 0 :::80 :::* LISTEN 500/lua
tcp 0 0 :::443 :::* LISTEN 500/lua
udp 0 0 0.0.0.0:514 0.0.0.0:* 260/rsyslogd
udp 0 0 :::514 :::* 260/rsyslogd
root@tachyonp:/tmp# ps -w
PID USER VSZ STAT COMMAND
1 root 4076 S /sbin/init
2 root 0 SW [kthreadd]
4 root 0 IW< [kworker/0:0H]
6 root 0 IW< [mm_percpu_wq]
7 root 0 SW [ksoftirqd/0]
8 root 0 IW [rcu_sched]
9 root 0 IW [rcu_bh]
10 root 0 SW [migration/0]
11 root 0 SW [cpuhp/0]
12 root 0 SW [cpuhp/1]
13 root 0 SW [migration/1]
14 root 0 SW [ksoftirqd/1]
16 root 0 IW< [kworker/1:0H]
17 root 0 SW [cpuhp/2]
18 root 0 SW [migration/2]
19 root 0 SW [ksoftirqd/2]
20 root 0 IW [kworker/2:0]
21 root 0 IW< [kworker/2:0H]
22 root 0 SW [cpuhp/3]
23 root 0 SW [migration/3]
24 root 0 SW [ksoftirqd/3]
25 root 0 IW [kworker/3:0]
26 root 0 IW< [kworker/3:0H]
27 root 0 SW [kdevtmpfs]
28 root 0 IW< [netns]
29 root 0 IW [kworker/0:1]
30 root 0 SW [oom_reaper]
31 root 0 IW< [writeback]
32 root 0 SW [kcompactd0]
33 root 0 IW< [crypto]
34 root 0 IW< [kblockd]
35 root 0 IW< [cfg80211]
36 root 0 IW< [watchdogd]
37 root 0 SW [kswapd0]
43 root 0 IW [kworker/2:1]
57 root 0 IW [kworker/3:1]
72 root 0 IW [kworker/1:1]
73 root 0 IW< [nvme-wq]
74 root 0 SW [spi0]
75 root 0 SW [kpktgend_0]
76 root 0 SW [kpktgend_1]
77 root 0 SW [kpktgend_2]
78 root 0 SW [kpktgend_3]
79 root 0 IW [kworker/0:2]
80 root 0 IW< [ipv6_addrconf]
81 root 0 SW [ubi_bgt0d]
83 root 0 IW< [kworker/0:1H]
84 root 0 IW< [kworker/1:1H]
85 root 0 SW [ubifs_bgt0_2]
88 root 1292 S /bin/ash --login
89 root 4092 S launchd
90 root 0 IW< [kworker/3:1H]
91 root 0 IW< [kworker/2:1H]
104 root 1248 S watchdog -T 30 -t 10 /dev/watchdog
105 root 1160 S ubusd
108 root 0 DW [IROS-Timer]
109 root 0 IW< [PERI_TMR1_WQ]
234 root 0 SW [ubi_bgt1d]
240 root 1664 S /usr/sbin/haveged -w 1024 -d 32 -i 32 -v 1 -F
259 root 2140 S logd -S 1024
260 root 16108 S rsyslogd -n -i/var/run/rsyslogd.pid
261 root 5304 S {ledd} /usr/bin/lua /usr/share/config/ledd
262 root 1944 S {signal_updater} /usr/bin/lua /usr/share/config/signal_updater
277 root 0 DW [unsync_reset_th]
278 root 0 IW< [PLOAM_WQ]
279 root 0 IW< [PLOAM_KEY_CTRL_]
280 root 0 IW< [PLOAM_KEY_TK4_W]
281 root 0 IW< [PLOAM_KEY_TK5_W]
282 root 0 IW< [PLOAM_RGST_WQ]
283 root 0 IW< [ACTIVATE_WQ]
284 root 0 IW< [PON_MISC_INTR_W]
288 root 0 SW [sw_aging]
289 root 0 DW [port_scan]
290 root 0 SW [NETLINK RX]
291 root 0 DW [ca_ni_netlink]
292 root 0 IW< [CA_NI_FILL_EQ_P]
339 root 0 IW [kworker/1:2]
359 root 0 IW< [CA_NI_GPHY0_WQ]
360 root 0 IW< [CA_NI_GPHY1_WQ]
361 root 0 IW< [CA_NI_GPHY2_WQ]
362 root 0 IW< [CA_NI_GPHY3_WQ]
415 root 8992 S /usr/sbin/lldp-server
467 root 5668 S /usr/sbin/wpa_supplicant -P /var/run/wpa_supplicant-wlan0.pid -D nl80211 -i wlan0 -c /var/run/wpa_supplic
479 root 1248 S udhcpc -p /var/run/udhcpc-br-wan.pid -s /usr/share/config/dhcpscript.lua -f -t 4 -i br-wan -x hostname:ta
482 root 2168 S {snmp_traps.lua} /usr/bin/lua /usr/share/lua/snmp_traps.lua /var/run/snmp-traps.json
500 root 12708 S {wsxavante} /usr/bin/lua /usr/sbin/wsxavante /var/etc/http
501 root 1248 S< ntpd -n -N -p time.google.com -p time.cloudflare.com
502 root 4076 S /usr/sbin/stsd -i prs0
508 root 4092 S /usr/sbin/bwmonitor -d -p 5
513 root 1248 S /bin/sh /usr/sbin/prs-events-processor
516 root 1124 S prs-events-parser --structured-mode
517 root 2008 S lua /usr/share/lua/prs-events/prs-events-processor.lua
11328 root 0 IW [kworker/u8:1]
12575 root 3020 S ash
14420 root 2148 S {phymond} /usr/bin/lua /usr/sbin/phymond
16126 root 0 IW [kworker/u8:0]
16849 root 2348 S {usbwatchd.lua} /usr/bin/lua /usr/share/config/usbwatchd.lua
17516 root 0 IW [kworker/u8:2]
17827 root 4076 S /usr/sbin/cpustat -l -c 7
17833 root 1248 R ps -w
Web Server
Digging into the /var/etc/http
folder from the wsxavante
process we discovered, we can observe more details on the web server configuration.
In this configuration we can see static content being served from /tmp/www/active
, but more interesting there is a CGI interface providing dynamic content for url paths under /cgi.lua/
which call upon the /usr/libexec/cgi/main.lua
handler.
/var/etc/http/web-ssl.json
{
"ssl": {
"key": "/usr/lib/server.key",
"certificate": "/usr/lib/server.crt"
},
"hosts": [
{
"host": "*",
"port": 443
},
{
"host": "::",
"port": 443
}
],
"serve": {
"files": {
"root": "/tmp/www/active",
"pattern": [
"%.gif$",
"%.ico$",
"%.png$",
"%.html$",
"%.css$",
"%.js$",
"%.jsx$",
"%.svg$",
"%.ttf$",
"%.otf$",
"%.woff$",
"%.woff2",
"%.eot$",
"%.bin$",
"download/%$"
]
},
"websock": {
"prefix": "/ws.lua/",
"pattern": "^/ws.lua/.+$"
},
"redirect": [
{
"pattern": "^.*/$",
"destination": "index.html?h=57fa0c61"
},
{
"pattern": "^/(.+)$",
"destination": "%s/index.html?h=57fa0c61"
}
],
"luacgi": {
"pattern": "^/cgi%.lua/.+$",
"prefix": "/cgi%.lua/",
"handler": "/usr/libexec/cgi/main.lua"
}
}
}