Modifying a Linksys EFG120 firmware


The EFG120 is a so called Network Area Storage (short NAS). It is very similiar to the famous NSLU2 but has (an) internal harddisk(s). Like the NSLU2 the EFG120 runs an embedded Linux and thus could easily be used for additional purposes.
The problem is the folowing: The system saves only those configuration files onto the harddisk which can be altered by the intened configuration interface (e.g. the Webinterface). If another file is altered by using a telnet session or tweaking the shares to access the config files, the altered file won't be written to the disk, causing the device to revert to old state.
The goal of this page is to describe the process we have developed to overcome this problem.


Keep in mind that this is no beginner's guide. To do this modifications yourself, you are required to know how to use a Unix/Linux system, compile programs from source and you need to be familiar with the basic system tools (dd, mount, cp, gcc, ...). Note that if something goes wrong, you will be responsible for your mistakes and even ours, if we got something wrong.
By the way, we suggest to use a real Unix/Linux system to do the modifications of the firmware itself (which are done on a PC and not on the EFG120 itself) or at least a Cygwin environment, to keep all newlines in the config files Unix compliant.


You have been warned.

Step 0: Prerequisites

Step 1: Gaining Telnet access

  1. Backup the configuration. You should get a file named configfile.bin.
  2. The configfile.bin is acutally a tar archive. (tar only, not gzipped.) Extract it.
  3. Cd into the extracted directory into hd~2/conf, edit the file share.info, modify the line which contains ADMIN as follows: ADMIN=:/../../..:administrators:7
  4. Edit the passwd file. Because you don't have access to shadow, take the encoded password from a login from which you know the password and replace root's password in the passwd file with the encoded known one. This is necessary because you need a known password for the telnet login.
  5. To get write access to the necessary directories, change the user and group id of the user administrator to 0.
  6. Tar the modified configuration files together again, and upload ot onto the EFG120.
  7. Now you should have full access to the directory Admin 1 if you open the share via SMB on Windows or Unix. Note that you have to login with the admin-account, not with the root-login.
  8. To start the telnet daemon, you need to do the following trick: If you have a close look at the configuration interface of the EFG120, you should notice that on restart and shutdown a script has to be executed. You can find it in /etc/rc.d/.
  9. Modify /etc/rc.d/rc.reboot the following way:
    echo "telnet stream tcp nowait root /usr/sbin/telnetd" >> /etc/inetd.conf
    killall inetd
    /usr/sbin/inetd &
  10. Switch to the configuration interface in your browser and click "restart"
  11. Now you should be able to telnet into the EFG120 as root.
Note: Old versions of the firmware had a telnet_enable.cgi which you could execute by browsing to http://192.168.xxx.yyy/Management/telnet_enable.cgi. This worked on the NSLU2 and the EFG120. Anyways, you had to hack the root password like described above to gain access. It seems that this CGI script doesn't exist on newer versions of the firmware.

Step 2: Reading the current ramdisk image

The EFG120 runs entirely from RAM including the filesystem. On bootup it loads the filesystem contents from the flash memory. The are two different approaches:

At first, we tried the first approach. We downloaded the splitnslu utility and had a look at the sourcecode. It didn't take us long to realize that the NSLU2 has another flash size (8MB while the EFG120 has 16MB). Thus the sizes defined in the utitlity would have to be altered. We managed to do that and got the sections out. The problem was, that there was no way to verify that the splitted files were correct, except for the ramdisk image which can be uncompressed and loopback mounted. We decided, that it was to dangerous to simply try, because we didn't know how we could recover from a screwed up firmware in flash. We read on NSLU2-Bootflash that the splitnslu utitily seems to have a bug which might cause incorrect flash images on reassembling altered files. It wouldn't have been wise to rely on this utility.
A short look at the dmesg output while having telnetted into the EFG120 shows that the device has 4 mtdblocks - exactly like the NSLU2 where mtdblock3 contains the ramdisk image. (See NSLU2-Bootflash for further details) Additionally, the dmesg output told us that the size of this block is 0xD80000. Now we could use dd to read the contents and put it into a file on the internal harddisk from where it could be accessed from a PC:
# dd if=/dev/mtdblock3 of=/harddisk/somepath/somedir/somefile.img bs=1
The dd command aborted with an I/O Error but a ls -l told us that the filesize was 14155776 bytes (= 0xD80000 in hex) so we had good chances that the I/O error was only due to reaching the end of the device.

Step 3: Splitting the flashblock into its contents

As mentioned above, the splitnslu utility is only good for splitting the whole firmware image. We had to make our own utilities to accomplish the task of extracting only the data of the ramdisk block. We wrote ripdata.c which can split the ramdisk image and assembledata.c for combining the parts to a new image. By using some parts of the splitnslu it didn't take long to write the new tools. Our tools don't have any parameters and work on fixed file names. This could be changed, but I think it's not really necessary. You can compile them by running:

# gcc -o ripdata ripdata.c
# gcc -o assembledata assembledata.c
ripdata requires the mtdblock file which we obtained in "Step 2" to be named input.raw the filenames of the two utilities are hardcoded in source so be sure to get the names right. Rename the output file which was generated by dd to input.raw. Then run:
# ./ripdata
(Assuming that the two tools are placed in the current working directory.) After (hopefully successfully) running the utility you have two additional files which are called output.gz and trailer.bin. output.gz is the extracted compressed ramdisk image. That's the file we are going to work on. trailer.bin is the Sercomm flash trailer which the utility saved into that file, because the trailer is needed by assembledata later to build a new valid flash image. You should not change anything in this file.

Step 3.1: Be on the safe side

Well. This is a step we did, because we didn't know whether we could write the image back and whether it would be successful and if the EFG120 would still boot. At first we checked if our two tools worked correctly. We splitted the flash image with ripdata as described above and used assembledata to combine the unchanged ramdisk image and the trailer into a new flash image. Afterwards we ran cmp to verify that the newly created flash image and the original one were the same. They were, so our tools seemed to work.
The next step was trying to write the image into the EFG120 flash. We decided to try it first with the original, unchanged flash image. Thus in a telnet session to the EFG120 we did.

# dd if=original_flash_img of=/dev/mtdblock3 bs=1024
We chose a blocksize of 1k, because at this point we knew that the size of the flashblock image was divideable by 1024. After pressing enter it took about 3 nerve straining minutes until the process had competed. A reboot showed that the device was still fully functional.

Step 4: Modifying the ramdisk contents

We used gunzip to decompress the file output.gz and creates the file output. gunzip completed without errors, and that's how it should be. If you get errors from gunzip, something went wrong in the preceding steps and you have a corrupted output.gz.
The ramdisk filesystem of the EFG120 is an ext2 filesystem and we could loopback mount it. (You could even do a bare losetup before and fsck the ramdisk image to make double-sure everything is right and the image is not corrupted. We did that.) We mounted it:

# mount -t ext2 output any_mount_point -o loop
And Tadaa! We could cd into any_mount_point and see the root filesystem of the EFG120.
Note: If you have ever created a Linux bootdisk by hand before, you know that you should change as little as possible on the loopback-mounted filesystem. E.g. don't copy lots of files onto it and delete them afterwards. The reason is the following: The filesystem parts which are unused are zeroed out (have zeroes written to them) to make sure that they compress well. If you copy files onto the filesystem, parts of the zeroes will be overwritten with the files's contents. If you delete the files, the "links" to the file-data-block will be deleted but the blocks won't be zeroed out, reducing the compressibility of the filesystem image.

The only modification we did was to modify a startup script. We wanted the EFG120 to run a script from the harddisk after successful bootup. With this script we could overwrite or change any configuration files we wanted, and the script, hence on the harddisk, won't be lost on power down. So there was no reason to change more. This modification is quite similiar to the RamHackU2 for the NSLU2.
We modified the file /etc/rc.d/rc.local of the EFG120, simply adding the following lines:
if [ -f /harddisk/hd~2/scripts/custominit.sh ]; then
/bin/sh /harddisk/hd~2/scripts/custominit.sh > /harddisk/hd~2/scripts/logfile.txt
(The scripts subdirectoy was created by us.) which caused the EFG120 to have a look at the harddisk and if a script file was present, it executed it. The output is redirected into a file which might be useful for debugging purposes.

Step 5: Creating the new mtdblock3 flash image

Having modified the firmware, we unmounted the EFG120 filesystem:

# umount any_mount_point
assembledata requires as input files newdisk.gz and trailer.bin.
# mv output newdisk
# gzip -9 newdisk
The first command renamed the changed ramdisk image and the second compressed the image and gave us the desired newdisk.gz. The next substep is to run assembledata
# ./assembledata
The newly created flash image is called newimg.raw which is the file we have written back into the EFG120's flashblock. The newimg.raw should be exactly as big as the original flash image. If not, something went wrong.

Step 6: Writing the modified flash image

We copied the newimg.raw file onto the EFG120's harddisk and telneted into the device. The last thing to do was to write the modified flashblock image back into mtdblock3:

# dd if=newimg.raw of=/dev/mtdblock3 bs=1024
This took about three to five minutes or so, I don't remember exactly. Anyways, it feels like an eternity. After the command had completed, we rebooted the device and -- TADA!! -- the EFG120 executed our custom script from the harddisk. Now we could make all custom changes permanent.

Step 7: Filling /harddisk/hd~2/scripts/custominit.sh with something useful

This activity is left over to the motivated reader. We put the same lines into it as we added to the /etc/rc.d/rc.reboot file mentioned in "Step 1", to make the telnet access permanent:

echo "telnet stream tcp nowait root /usr/sbin/telnetd" >> /etc/inetd.conf
killall inetd
/usr/sbin/inetd &
Of course, you can add whatever you want.

Last change: 21st October 2006

EFG120 hacked by Beisteiner Christoph (christoph(at)beisteiner.net) and Wiesner Thomas (w15mail(at)yahoo.de).
Summary written, copyright and brought to you by Wiesner Thomas