Reverse engineering Telergy T501 IPTV set top box

Recently I brought home Telergy T501 IPTV set top box. It was with default firmware which actually was something like demo GUI application. It was not customized to be used with any local IPTV provider, neither it had option to customize it using menu / settings. So by default it is useless thing, but I wanted to customize / hack it.

I tried google – no results at all. It is pretty unknown vendor of IPTV set top boxes. There was no information about it at all. I also found out that is quite old model, so it is more difficult to find something about it as everyone write and discuss about newer models.

Ant then I noticed that Firmware upgrade URL is visible in the settings screen. So I downloaded firmware image to my computer and opened it with Hex editor. And here I am lucky – it is not obfuscated or difficult to find something to catch on. I immediately noticed strings like “kernel0” or “vmlinux-strip”. The firmware’s developer name was also here (I suppose so) – “Beijing Yuxing Software CO., Ltd”.

t501_1

Starting at offset 0x11C it looks like archive. Also there are lots of zeros before that, so it looks like beginning of a file. So googling out for “1F 8B” I got to this site where I found that file header “1F 8B” stands for gzip.

Then just to be sure I opened RFC for gzip and analyzed this part a little bit more. It was definitely gzip:

1F 8B – file ID header

08 – This identifies the compression method used in the file. CM = 0-7 are reserved. CM = 8 denotes the “deflate” compression method, which is the one customarily used by gzip and which is documented elsewhere (this is stated in the RFC).

08 – Flags field, looks like 00001000. Where bit 3 (which is active) stands for “has filename”.

69 54 0A 49 – this is archive’s MTIME field, using calculator I got 0x490A5469 = 1225413737 decimal unix timestamp. From this timestamp GMT date and time is Fri, 31 Oct 2008 00:42:17 GMT which looks very similar to that one readable at the start of binary firmware update file. Probably this firmware was generated from script and first visible date shows header generation time in their local time and archive got +1 sec as it was created one second later.

00 – empty extra flags field.

03 – it is operating system type where it was generated. 03 stands for Unix.

76 6D 6C 69 6E 75 78 2D 73 74 72 69 70 00 – here is filename “vmlinux-strip” terminated by zero

All next bits – compressed bits.

With dd I take out the part I am interested in:

[muanton@server ~]$ dd if=t501.bin of=t501.bin.part1.gz bs=1 skip=284
13495824+0 records in
13495824+0 records out
13495824 bytes (13 MB) copied, 40.3846 s, 334 kB/s
[muanton@server ~]$ file t501.bin.part1.gz
t501.bin.part1.gz: gzip compressed data, was “vmlinux-strip”, from Unix, last modified: Fri Oct 31 02:42:17 2008
[muanton@server ~]$ gunzip t501.bin.part1.gz

gzip: t501.bin.part1.gz: decompression OK, trailing garbage ignored

[muanton@server ~]$ ls -lah t501.bin.part1
-rw-rw-r–. 1 muanton muanton 3.0M Sep 15 14:34 t501.bin.part1
[muanton@server ~]$ file t501.bin.part1
t501.bin.part1: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, stripped

Notice “trailing garbage ignored” and ls output. It means we have got something more in that firmware package after kernel archive.

From gzip RFC i know, that there is CRC32 checksum at the end of compressed file.

[muanton@server ~]$ crc32 t501.bin.part1
99dd8c74

I am lucky again:

t501_2

Here it looks like the archive ends. And I again notice similar data like it was in the front of the firmware part – YX5911A, “Beijing Yuxing Software CO., Ltd”, human readable date again. But no more gzip after this.

Actually here 45 3D CD 28 or notice later “Compressed ROMFSBZ” hints that here I had encountered CramFS (from Wikipedia: The compressed ROM file system (or cramfs) is a free (GPL’ed) read-only Linux file system designed for simplicity and space-efficiency. It is mainly used in embeddeds and small-footprint systems.

So I am back to my Linux server:

[muanton@server ~]$ dd if=t501.bin of=t501.bin.part2.cramfs bs=1 skip=1306156
12189952+0 records in
12189952+0 records out
12189952 bytes (12 MB) copied, 35.6865 s, 342 kB/s
[muanton@server ~]$ file t501.bin.part2.cramfs
t501.bin.part2.cramfs: Linux Compressed ROM File System data, little endian size 10170368 version #2 sorted_dirs CRC 0x87135a42, edition 0, 4999 blocks, 211 files

Mount it from root:

[root@server ~]# mount -o loop -t cramfs /home/muanton/t501.bin.part2.cramfs /mnt/

Looks like incomplete linux filesystem:

[muanton@server ~]$ cd /mnt/
[muanton@server mnt]$ lsbin  lib  local.rc  share

Digging out firmware file again, now I know what to look for. It looks like each separate part in the firmware file got header where that Chinese company is mentioned. So searching for “Yuxing”:

t501_3

And here goes another CramFS. By the way, it looks like there are 3 files (parts) in this firmware image as I was not able to find more occurrences of “Yuxing”. Here I also notice that this CramFS looks like full linux filesystem.

Back to linux box:[root@server ~]# umount /mnt[root@server ~]# mkdir /mnt/1[root@server ~]# mkdir /mnt/2[root@server ~]# mount -o loop -t cramfs /home/muanton/t501.bin.part2.cramfs /mnt/1/

[muanton@server ~]$ dd if=t501.bin of=t501.bin.part3.cramfs bs=1 skip=11476780
2019328+0 records in
2019328+0 records out
2019328 bytes (2.0 MB) copied, 6.01123 s, 336 kB/s
[muanton@server ~]$ file t501.bin.part3.cramfs
t501.bin.part3.cramfs: Linux Compressed ROM File System data, little endian size 2019328 version #2 sorted_dirs CRC 0xce305c91, edition 0, 1309 blocks, 464 files

[root@server ~]# mount -o loop -t cramfs /home/muanton/t501.bin.part3.cramfs /mnt/2/

[muanton@server ~]$ cd /mnt/2/
[muanton@server 2]$ ls
bin  dev  etc  home  init  lib  linuxrc  mnt  proc  root  sbin  share  tmp  tmpfsvar.img  usr  var  var.img
[muanton@server 2]$ cd etc/
[muanton@server etc]$ ls
build-date  config  dhcpc  group  host.conf  init.d  inittab  mtab  passwd  profile  protocols  resolv.conf  services  termcap  version

Yeah, it looks like full filesystem.

While looking around the file system at firs I look ant init.d directory, here I have found rcS file. And in this file I notice this:

# Start up services
echo “start services”

case $runlevel in
1|2)
;;
*)
portmap &
utelnetd -d
;;
esac

From this I suppose that box runs telnet daemon. I nmap my set top box:

Starting Nmap 5.51 ( http://nmap.org ) at 2013-09-15 15:11 EEST
Nmap scan report for x.x.x.x
Host is up (0.0063s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE
23/tcp  open  telnet
111/tcp open  rpcbind

Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds

/etc/passwd contains 2 users with password – root and telergy. Both with UID 0. Passwords are DES hashes as they are 13 chars long. This is time to call John to help me.

[muanton@server etc]$ john passwd
Loaded 2 password hashes with 2 different salts (Traditional DES [128/128 BS SSE2-16])
xxx             (root)
xxx           (telergy)
guesses: 2  time: 0:00:01:28 DONE (Sun Sep 15 15:16:25 2013)  c/s: 2089K  trying: xxx
Use the “–show” option to display all of the cracked passwords reliably

I am not going to show passwords here as this might harm lots of Telergy users, but notice that john did it in 88 seconds! It was very weak passwords for both users.

Anyway, I am trying telnet:

(none) login: root

Password:
#
# whoami
root
#
# uname -a
Linux (none) 2.6.12-5.0-yx5911 #171 Fri Oct 31 08:42:15 CST 2008 7402c0-nand unknown
#
# ls
config.txt      rc.user         t               userip.txt
drm             resolv.conf     temp_upgrade    userip.txt.bkp
nvram.bin       settings        tvsystem        vmdrm

Telnet connection works, I am root here.

I am not going to write about how I customized it, but I did it – I use it to watch IPTV which I get from my ISP. This post is not about that. How to customize it I got the idea after digging out that thing’s filesystem and running daemons. It was pretty easy 🙂

 

Posted in IPTV, Linux, MIPS, Reverse engineering | Tagged , , , , , , , , | 12 Comments

CentOS 6, LVM, mdadm, USB stick tricks

Recently I got an idea to reuse my old PC as a Linux server box. The main problem was that I had only PC box left – no mouse, keyboard and monitor (I dumped all this when I was moving to my new flat).

I decided to install CentOS on USB stick, boot it on my old PC, create software raid on it and move everything from USB to permanent storage on old PC. At the end everything ended quite successful – this blog is already running on that old box 🙂

So I am going to describe each step I have done and all the caveats I have encountered.

Step 1: USB stick preparation

Normally at work I use Windows 7 laptop because I haven’t got any other usable PC at the moment (actually, there is no need to have it anyway).

I didn’t want to burn or prepare any media at all. Just to download install image and install OS to USB stick, so for this I used Oracle VirtualBox. I mounted CentOS install DVD as CD-ROM drive and passed through USB flash to the virtualized system. CentOS installer booted and I did Base installation to USB stick.

I am not going to describe all the installation procedure, but there is some installation decisions to highlight:

  • Use VirtualBox with USB 2.0 support or it will be very slow.
  • You’ll need at least 4GB (possibly 2GB is enough too if you are not going to create swap partition) USB stick.
  • When doing partitioning rename standard VolGroup and LogVol to something that makes sense (for example vg_server, lv_root, lv_swap). Do not use whole space. Create 1-2GB swap volume and leave at lease 1.5GB for root). You can leave 500MB for /boot as it is by default. If you are using 2GB flash – you can make it smaller – 200MB is enough.

Step 2: booting from USB first time on my laptop and initial CentOS configuration

Next I booted my Linux from USB stick. Please make sure that you have got USB boot enabled. Next steps:

  1. yum update (to update whole system)
  2. chkconfig iptables off (disabling firewall is easiest way to deal with it – we will need ssh port open)
  3. make sure sshd is enabled and it is allowing root login or you have got user which can do su to root
  4. make sure mdadm, mkinitrd, rsync commands exists (I don’t remember if all of them come in CentOS base installation)
  5. prepare /etc/sysconfig/network-scripts/ifcfg-eth2 with ONBOOT=”yes” and your IP parameters (static or dhcp). You should notice that for every new ethernet interface CentOS discovers the udev renames it to be unique. I use eth2 because eth0 was my VirtulBox and eth1 is my current interface used with laptop. You can change this mappings in /etc/udev/rules.d/70-persistent-net.rules
  6. Reboot to check if everything comes up (try ssh)

Step 3: booting USB stick on my old PC

I knew that USB boot (thankfully) was enabled on my old PC box. That’s why I started all this difficult Linux installation.

I inserted USB flash into USB port, connected network cable and powered on the system.

After a few minutes I checked my Mikrotik router’s DHCP logs to get the IP address of Linux instance.

ssh was a success!

Now I needed to move the system to local physical storage.

The system has 2 same size HDDs, so I decided to go with software RAID1.

Step 4: preparing physical storage devices (software RAID)

  1. Partitioning physical drives. I decided to use 2 partitions on each drive: one for md0 (/boot) and second one for md1 (LVM’s physical storage). Other layouts may include additional raid partition for swap, but I use swap as logical volume. So for md0 – 500M, for md1 – all the rest. Please do not forget change partition type to fd and set bootable flag for first partition.
  2. mdadm –create /dev/md0 –level=mirror –raid-devices=2 –metadata=0.90 /dev/sda1 /dev/sdb1 (you must force older metadata or GRUB will fail to install, GRUB2 doesn’t have this problem but it doesn’t come with CentOS 6)
  3. mdadm –create /dev/md1 –level=mirror –raid-devices=2 /dev/sda2 /dev/sdb2
  4. please wait till md arrays are building. Check status by running cat /proc/mdstat
  5. mdadm –detail –scan > /etc/mdadm.conf
  6. remove rd_NO_MD from /boot/grub/menu.lst (this option disables MD raid detection on boot)
  7. mkinitrd /boot/initramfs-2.6.32-279.22.1.el6.x86_64.img 2.6.32-279.22.1.el6.x86_64 (to have md kernel modules included)
  8. GRUB installation (do not use grub-install, it may be false possitive):
    1. grub
    2. root (hd0, 0)
    3. setup (hd0)
    4. root (hd1, 0)
    5. setup (hd1)
    6. quit (it shouldn’t report any errors)
  9. mount /dev/md0 /mnt
  10. rsync -avz /boot /mnt
  11. umount /mnt
  12. pvcreate /dev/md1
  13. vgextend vg_server /dev/md1
  14. pvmove /dev/sdc2 (USB stick partition)
  15. vgreduce vg_server /dev/sdc2
  16. pvremove /dev/sdc2
  17. edit /etc/fstab: change /boot UUID to md0’s UUID (use blkid to get UUID)
  18. poweroff
  19. remove USB stick
  20. power on the system

And hope you are up and running! I was lucky one 🙂

 

Posted in CentOS, Linux | Tagged , , , , | Leave a comment

Cherokee vs. Apache

Some time ago I discovered a web server called Cherokee. The web server itself is promoted as “The Fastest free Web Server out there!”. So for a while I was just curious to do a benchmarks and compare it with Apache web server and see which one is faster in standard LAMP environment.

Why Apache vs. Cherokee? Because Apache is most common in LAMP environments and most widely used web server around the globe.

The main difference of Cherokee when compared with other web server software is that it is configured using web interface. The configuration file itself has a comment “don’t edit me by hand!” or something like that. Actually I was amazed with web interface, because it was very simple and easy to understand, user friendly and everything just worked 🙂

BTW, for benchmarking I used FreeBSD box, because that’s the only one which I’ve got under my table at home.

I’ve chosen to test newest WordPress version by date (3.1.3) just running ab against index page. Both web applications were clean installs.

I’ve tested these configurations:

  • Apache + mod_php
  • Cherokee + php-cgi (using FastCGI)
  • Apache + mod_php + eAccelerator extension
  • Cherokee + php-cgi (using FastCGI) + eAccelerator extension

ab was doing 1000 requests with different concurrency levels (1, 5, 10, 20, 50 and 100).

Web server software versions (compiled from ports):

  • Cherokee 1.2.2
  • Apache 2.2.19

Web application:

  • WordPress 3.1.3

Test system / environment:

# Aspersa System Summary Report ##############################
Date | 2011-06-21 20:49:12 UTC (local TZ: EEST +0300)
Hostname | mercury.insplash.com
Uptime | 43 days, 16:37, 2 users, load averages: 1.70, 14.19, 14.68
Platform | FreeBSD
Release | 7.4-RELEASE-p1
Kernel | 199506
Architecture | CPU = 64-bit, OS = 64-bit
Virtualized | No virtualization detected
# Processor ##################################################
Processors | virtual = 4
Speeds | 2331
Models | Intel(R) Core(TM)2 Quad CPU Q8200 @ 2.33GHz
# Memory #####################################################
Total | 4.0G
Virtual | 4.8G
Used | 1.9G
UsedRSS | 22.4M

php info (without eAccelerator):

PHP 5.2.17 with Suhosin-Patch 0.9.7 (cli) (built: Jun 15 2011 14:03:49)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
with Zend Extension Manager v1.2.2, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.0, Copyright (c) 1998-2007, by Zend Technologies

php-cgi info (without eAccelerator):

PHP 5.2.17 with Suhosin-Patch 0.9.7 (cgi-fcgi) (built: Jun 15 2011 14:03:49)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
with Zend Extension Manager v1.2.2, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.0, Copyright (c) 1998-2007, by Zend Technologies

The Setup

Cherokee’s and Apache’s configurations are practically default with no performance tuning or any additional modules.

PHP was tested with almost standard module set which is used by common PHP setups. Maybe you could just notice that it is with Suhosin Patch, but this one shouldn’t affect performance significantly. Zend optimizer is also pretty standard in LAMP setups. It is used just for loading encoded files.

eAccelerator configuration:

  • eaccelerator.shm_size = “128”
  • eaccelerator.enable = “1”
  • eaccelerator.optimizer = “1”
  • eaccelerator.shm_only = “1”
  • eaccelerator.compress = “1”
  • eaccelerator.compress_level = “9”
  • eaccelerator.keys     = “shm_only”
  • eaccelerator.sessions = “shm_only”
  • eaccelerator.content  = “shm_only”

The Results

The first table shows how many requests per second each setup could handle by increasing concurrency level.

Requests per second
Concurrency Apache + mod_php Cherokee + php-cgi Apache + mod_php + eA Cherokee + php-cgi + eA
1 4.64 4.99 14.59 19.33
5 16.14 16.97 24.22 62.97
10 15.95 17.33 15.00 62.69
20 15.85 17.22 9.89 61.93
50 15.47 17.17 2.81 62.04
100 15.21* 17.33 2.96** 62.72

This table indicates the longest request time for each benchmark. From this table you can see that Cherokee is handling concurrent requests a lot better than Apache.

Longest request (100%)
Concurrency Apache + mod_php Cherokee + php-cgi Apache + mod_php + eA Cherokee + php-cgi + eA
1 327 230 760 75
5 751 869 3671 146
10 4014 786 7081 235
20 11992 1452 13040 457
50 22081 3147 96152 921
100 29690* 6065 143878** 4560

And the last one shows average request time for each benchmark.

Time per request (mean, across all concurrent requests)
Concurrency Apache + mod_php Cherokee + php-cgi Apache + mod_php + eA Cherokee + php-cgi + eA
1 215.674 200.209 68.549 51.736
5 61.962 58.910 41.285 15.879
10 62.677 57.694 66.679 15.951
20 63.090 58.071 101.140 16.147
50 64.651 58.225 356.294 16.118
100 65.747* 57.715 338.261** 15.945

* – Apache failed to serve 17 requests out of 1000

** – Apache failed to serve 793 requests out of 1000

So those results are not quite correct and influenced by failures.

Conclusions

When running benchmarks without eAccelerator you could see that Cherokee is a little bit faster. As concurrency grows Apache suffers some kind of concurrency / threading problems, because performance is degrading while Cherokee holds almost steady results.

A was very surprised when I saw that eAccelerator gives negative effect on Apache when concurrency level increases. While monitoring the process tree I saw some kind of flock() issues. I’ll try to investigate this deeper in the future.

eAccelerator and WordPress is a very good combination, because eA gives about 4x performance gain.

And yes! I know, I should benchmark some other web applications to get more objective results. I’ll do it in near future.

Posted in FreeBSD, Performance | Tagged , , , , , | 2 Comments