Customizing firmware images can be a very useful skill, allowing you to add or unlock features, fix bugs, and patch vulnerabilities when vendors can’t (or won’t) do so in a timely manner.
A while ago I found that my Trendnet TEW-632BRP and TEW-652BRP routers had a TFTP service running on both the LAN and WAN interfaces that allowed anyone to download the device’s configuration file without authentication:
embedded@ubuntu:~/TEW632$ tftp 192.168.10.1 tftp> get /tmp/etc/nvram.conf Received 19897 bytes in 0.0 seconds tftp> quit embedded@ubuntu:~/TEW632$ head nvram.conf hostname=TEW-632BRP admin_username=admin admin_password=admin user_username=user user_password= default_html=lan.asp lan_mac=00:14:d1:12:5e:7d wan_mac=00:14:d1:12:5e:7e lan_eth=eth0 wan_eth=eth1
After contacting the vendor they verified the vulnerability and issued a firmware update that disables TFTP access from the WAN. However, they insisted on leaving TFTP accessible from the LAN “for repair purposes”. I’d much rather have TFTP disabled completely, so in this tutorial we’ll be patching the Trendnet firmware in order to completely disable TFTP. The patching process for the TEW-632BRP is also pretty simple, so it makes for a good introduction to firmware patching too.
Grab the latest TEW-632BRP firmware from Trendnet’s Web site here. If you don’t have it already, also be sure to grab the latest versions of binwalk and the firmware mod kit.
[NOTE: Although the firmware mod kit allows you to automatically extract and re-build the TEW-632BRP’s firmware, you don’t learn much from that and it would make for a pretty boring tutorial. Instead, we’ll be using some of the SquashFS utilities included in the firmware mod kit in order to patch the firmware manually.]
In order to patch the TFTP vulnerability, we’ll need to edit the system’s start up scripts in order to stop the TFTP server from running on boot. Let’s start out by running binwalk against the firmware image to see if we can identify the file system:
embedded@ubuntu:~/TEW632$ binwalk TEW632BRPA1_FW110B31.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------- 0 0x0 uImage header, created: Wed Jun 8 03:35:19 2011, image size: 813719 bytes, Data Address: 0x80060000, Entry Point: 0x80290000, CRC: 0x15ED049D, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: Linux Kernel Image 64 0x40 LZMA compressed data, dictionary size: 8388608 bytes, uncompressed size: 2429062 bytes 1048576 0x100000 Squashfs filesystem, big endian, version 3.0, 2447513 bytes, 571 inodes, blocksize: 65536 bytes, created: Wed Jun 8 03:35:38 2011
Binwalk identified a uImage header at the beginning of the firmware image, followed by an LZMA compressed kernel and a SquashFS filesystem. Interestingly, the image size reported in the uImage header is 813,719 bytes while the SquashFS file system is located 1,048,576 bytes into the firmware image. This suggests that the checksum in the firmware header is only calculated over the LZMA kernel and not the file system.
Let’s look at a hexdump of the firmware image at offset 1,048,576 (hex 0x100000) to see if there’s a separate header for the file system:
embedded@ubuntu:~/TEW632$ hexdump -C TEW632BRPA1_FW110B31.bin | less 000c6aa0 bf c4 bf 07 c0 64 a9 8b 95 6b 60 69 f4 be 0d ba |.....d...k`i....| 000c6ab0 2a ea 6d 4c 34 e4 8a 03 93 20 d7 34 bf 2b 77 61 |*.mL4.... .4.+wa| 000c6ac0 45 75 40 2b 46 cc c3 0d a2 55 9f 7f d2 2e c7 dc |Eu@+F....U......| 000c6ad0 5b c2 af e1 d0 00 00 00 00 00 00 00 00 00 00 00 |[...............| 000c6ae0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00100000 73 71 73 68 00 00 02 3b 9c bf ac 40 42 bf ac 40 |sqsh...;...@B..@| 00100010 7b 00 81 aa 00 f0 2d 94 00 00 00 00 00 03 00 00 |{.....-.........| 00100020 82 cf 00 10 40 02 02 4d ef 50 7a 00 00 00 00 10 |[email protected].....| 00100030 52 05 e0 00 01 00 00 00 00 00 32 f6 3d 4e 2e 00 |R.........2.=N..| 00100040 00 00 00 00 25 58 99 00 00 00 00 00 25 58 89 00 |....%X......%X..| 00100050 00 00 00 00 25 58 91 00 00 00 00 00 25 32 28 00 |....%X......%2(.| 00100060 00 00 00 00 25 44 16 00 00 00 00 00 25 58 81 ff |....%D......%X..|
There is a big section of null padding immediately before the ‘sqsh’ SquashFS magic bytes, but no header. This indicates that we should be able to replace the existing file system in the firmware image without needing to fix the checksum value in the firmware header. Although uImage headers are well documented and re-generating a valid header for this firmware image would not be difficult, this makes our job that much easier.
The last thing we need to look for is a firmware footer. Looking at the last few lines of the firmware image, we see that there is a footer starting at offset 3,866,624 (hex 0x3b0000):
embedded@ubuntu:~/TEW632$ hexdump -C TEW632BRPA1_FW110B31.bin | tail 00355850 9f 2c 56 03 f0 68 08 a1 67 8d 21 86 9e 72 da bc |.,V..h..g.!..r..| 00355860 4b 73 58 f5 28 2b 68 e8 96 e0 a2 1d 4e 43 f2 22 |KsX.(+h.....NC."| 00355870 a2 61 3e 3a 9a b0 c8 e1 30 57 30 ff ff f0 4a 40 |.a>:....0W0...J@| 00355880 00 00 00 00 00 00 25 57 4f 00 00 00 00 00 00 01 |......%WO.......| 00355890 f4 00 00 00 05 00 00 00 06 00 00 00 00 00 00 00 |................| 003558a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 003b0000 41 50 38 31 2d 41 52 39 31 33 30 2d 52 54 2d 30 |AP81-AR9130-RT-0| 003b0010 37 30 36 31 34 2d 30 30 |70614-00| 003b0018
The footer contains references to the chip sets supported by the firmware; this is usually used to ensure that end users don’t upload incompatible firmware images to the device. We shouldn’t need to change any of this data but we will need to include the footer in our modified firmware image.
OK, now that we’ve identified the major pieces of the firmware image, let’s dd the SquashFS data from the firmware and extract the system files using the unsquashfs utility from the firmware mod kit:
embedded@ubuntu:~/TEW632$ dd if=TEW632BRPA1_FW110B31.bin bs=1 skip=1048576 count=2447513 of=tew632.squashfs 2447513+0 records in 2447513+0 records out 2447513 bytes (2.4 MB) copied, 4.27572 s, 572 kB/s embedded@ubuntu:~/TEW632$ sudo /opt/filesystems/squashfs/unsquashfs3.0-lzma tew632.squashfs Reading a different endian SQUASHFS filesystem on tew632.squashfs created 414 files created 44 directories created 73 symlinks created 40 devices created 0 fifos
Let’s try to find where the tftpd binary is started by grepping through all of the extracted files for references to ‘tftpd’ (be sure to exclude the dev directory!):
embedded@ubuntu:~/TEW632/squashfs-root$ grep --exclude-dir=dev tftpd * -R 2>/dev/null Binary file sbin/tftpd matches Binary file sbin/rc matches
Taking a look inside sbin/rc we quickly find that it is the culprit:
embedded@ubuntu:~/TEW632/squashfs-root$ strings sbin/rc | grep tftp stop_tftpd start_tftpd tftpd killall tftpd & option tftp %s
If the rc file was a start up script it would be easy to edit out the tftpd service, but since it’s an executable ELF file, it will be easier to just replace the tftpd binary:
root@ubuntu:~/TEW632/squashfs-root# echo -e '#!/bin/shecho "Refusing to start TFTPD!"' > sbin/tftpd root@ubuntu:~/TEW632/squashfs-root# cat sbin/tftpd #!/bin/sh echo "Refusing to start TFTPD!"
OK, now we need to re-package our modified file system into a SquashFS image. Again, we’ll use the firmware mod kit’s SquashFS utilities. Note that since the original SquashFS image was big endian, we need to supply the -be flag to mksquashfs in order to build our image in big endian byte order as well:
embedded@ubuntu:~/TEW632$ sudo /opt/filesystems/squashfs/mksquashfs3.0-lzma squashfs-root/ tew632_modified.squashfs -be Creating big endian 3.0 filesystem on tew632_modified.squashfs, block size 65536. Big endian filesystem, data block size 65536, compressed data, compressed metadata, compressed fragments Filesystem size 2381.04 Kbytes (2.33 Mbytes) 27.90% of uncompressed filesystem size (8533.83 Kbytes) Inode table size 4577 bytes (4.47 Kbytes) 25.54% of uncompressed inode table size (17922 bytes) Directory table size 4935 bytes (4.82 Kbytes) 51.80% of uncompressed directory table size (9527 bytes) Number of duplicate files found 24 Number of inodes 571 Number of files 414 Number of fragments 49 Number of symbolic links 73 Number of device nodes 40 Number of fifo nodes 0 Number of socket nodes 0 Number of directories 44 Number of uids 2 root (0) unknown (-201261056) Number of gids 2 unknown (83886080) unknown (100663296) embedded@ubuntu:~/TEW632$ ls -l *.squashfs -rwx------ 1 root root 2441216 2011-06-19 05:59 tew632_modified.squashfs -rw-r--r-- 1 embedded embedded 2447513 2011-06-19 05:41 tew632.squashfs
Now we need to extract the first part of the original firmware image, which includes the firmware header, kernel, and the null byte padding between the kernel and the file system. As we saw earlier, the file system starts at offset 1,048,576, so we we’ll take everything up to that offset:
embedded@ubuntu:~/TEW632$ dd if=TEW632BRPA1_FW110B31.bin bs=1048576 count=1 of=fw.part1 1+0 records in 1+0 records out 1048576 bytes (1.0 MB) copied, 0.00797675 s, 131 MB/s
Now we need to extract the firmware footer, which starts at offset 3,866,624:
embedded@ubuntu:~/TEW632$ dd if=TEW632BRPA1_FW110B31.bin bs=3866624 skip=1 of=fw.part2 0+1 records in 0+1 records out 24 bytes (24 B) copied, 5.463e-05 s, 439 kB/s
Let’s concatenate our modified file system image with the first part of the original firmware:
embedded@ubuntu:~/TEW632$ cp fw.part1 tew632_new.bin embedded@ubuntu:~/TEW632$ sudo cat tew632_modified.squashfs >> tew632_new.bin embedded@ubuntu:~/TEW632$ ls -l tew632_new.bin -rw-r--r-- 1 embedded embedded 3489792 2011-06-19 06:15 tew632_new.bin
Our firmware image is now 3,489,792 bytes long; the footer should be located at offset 3,866,624, so we’ll add 376,832 bytes of padding and then concatenate the footer to our image:
embedded@ubuntu:~/TEW632$ perl -e 'print "x00"x376832' >> tew632_new.bin embedded@ubuntu:~/TEW632$ cat fw.part2 >> tew632_new.bin embedded@ubuntu:~/TEW632$ ls -l *.bin -rw-r--r-- 1 embedded embedded 3866648 2011-06-08 18:35 TEW632BRPA1_FW110B31.bin -rw-r--r-- 1 embedded embedded 3866648 2011-06-19 06:19 tew632_new.bin
Now for the moment of truth! Let’s upload our modified image:
And test the TFTP service:
embedded@ubuntu:~/TEW632$ tftp 192.168.10.1 tftp> get /tmp/etc/nvram.conf Transfer timed out. tftp>
Success! The patched firmware can be downloaded here. Now on to fix the other bugs in the TEW-632…