Hacking the HNAS1 Network Attached Storage Unit

by Michael Saarna

The HNAS1 is a Network-Attached Storage (NAS) unit from Hawking Technologies.

Basically it's a mini-computer with a small IDE bay set up for file-sharing.  It runs μClinux on MIPS and has a quite nice web-based admin interface.

I ordered one of these units thinking that it would be great to share files with family and friends.  I figured that I'd just forward HTTP from the firewall and set up a user for each of them.  Simplicity!  As an added bonus, it appeared that nobody had hacked them yet - I filed that away as a back burner project.

The unit arrived later that week and I had one of those "Uh oh..." moments.

It appears that the HNAS1 only supports FTP and Samba.

What the hell...  It has an httpd right, so why no HTTP access?!?  Guess I should have read the feature list a bit more carefully.

Trying it out, I found that I loved everything else about this unit.  It took up barely any room, the interface was straightforward, and it barely drew any power.

I resolved to hack it so I would be able to improve the feature-set.

First Hack Whack

First some reconnaissance was in order.

I started with a bit of Googling and learned that the HNAS1 runs BRECIS Linux, a MIPS μClinux distribution.  Unlike most μClinux distributions, this one has a working fork() system call.

Next came the obligatory Nmap portscan:

Starting nmap 3.93 (http://www.insecure.org/nmap) at 2005-09-20 17:13 EDT
Interesting ports on I-DRIVE (192.168.1.100):
(The 1662 ports scanned but not shown below are in state: closed)
PORT        STATE               SERVICE
21/tcp      open                ftp
24/tcp      open                priv-mail
80/tcp      open                http
139/tcp     open                netbios-ssn
445/tcp     open                microsoft-ds
1720/tcp    filtered            H.323/Q.931
MAC Address:00:08:54:D6:90:F8 (Netronix)

The Netronix ownership of the MAC address is interesting.

It appears the HNAS1 is a rebranded Netronix box.  Judging by the specs at the Netronix website, it looks like an NH-210.

The port 24 part caught my eye too.  A quick Telnet to port 24 later and the following banner printed out on my term:

www.brecis.com
28 July 2003
Welcome to linux 2.4.20-br251 by BRECIS (Release 2.5.1)

BRECIS linux incorporates changes  from
kernel.org, and uclinux.org as well as
locally derived features to provide a
robust environment for the embedded BRECIS
MIPS chip. Almost any program that
can run with less than 64k of stack
should work. Most all features  of the
Linux kernel are provided

The "c" runtime library originated at
uclibc.org. One nice feature is that the
fork() system call works (although
slowly) for this MMU-less chip.

For more information...

It goes on for a while, but you get the idea.  After the banner was displayed, the telnet session was terminated.

Then I started to poke around the web administration interface, trying out the standard httpd exploits.  A directory backup attempt with the URL http://192.168.1.100/.. resulted in just the index page, not a previous directory.

Thinking that perhaps the httpd devs might have missed a bounds check somewhere, I attempted to overflow the httpd/CGI with various artificially long URLs, modified form submissions with abnormally long fields, etc., with no luck.  Again, it always just returned the main index page.

I then tried entering some shell-interruption into the form submissions, in hopes that some of the admin interface did a system call somewhere without sanitizing the input.

So for the timezone interface I tried: ntp0.fau.de; /bin/cat /etc/passwd

And the like.  The web interface returned to the same page with sanitized fields.

I was actually pleased at this point.  These were some pretty standard attacks to guard against, but a lot of manufacturers seem to slip up somewhere, as in the Linksys WRT54G ping vulnerability.  The fact that the developers had avoided these pitfalls gave me some confidence in the custom software running on the HNAS1.

Try Try Again

Since the front door was secure, I decided it was time to take a different approach.

In my web research I had found that some people had problems with earlier firmware and Windows XP systems.

I sent the following mail to techsupport@hawkingtech.com:

Hi,

I just recently purchased your HNAS1 product and am generally happy.

I have an issue accessing it via my one XP system, and was just wondering if
there's a site that I can download updated firmware for it. 

I've read on the Internet that other users have encountered problems with XP, 
and you've sent them updated firmware to fix the issue.

O.K., well I was technically having a problem accessing the HNAS1...  I just didn't mention that it was a problem with HTTP access of the shares!

Hawking support eventually replied a couple of days later with an attached firmware update.  Sweet!

Firmware Analysis

The firmware update file was just over three megs, so I assumed it was a full flash update rather than a selective file update.

Firing up the hex editor revealed some interesting stuff.  First, there was a 512-byte header.  The initial 99-bytes consisted of ASCII text, followed by zeros:

MAGICNUM=ADx023spFc0Mn6li8SCq9kEr.PRODUCT_ID=NH200.
CUSTOMER=HAWKING.VERSION=v1.02(06-07-2005)-ext3

The rest of the file looked fairly randomish, except for some interesting strings in the middle:

vfprintf: out of memory........unzip - Unknown header at address %x, %0x, %0x..unzip - Unknown compression method, should be 8...

and a bit later, surrounded by more randomish bytes was the text: image.bin

This gave me great hope that I'd find some compressed image data in the firmware update.

What a Tool

I decided in order to aid my analysis I'd write a tool that wrapped the UNIX file command.

For those of you unfamiliar with file, it takes a look at certain signature bytes within a file and reports to you what it believes the file is.

$ file somefile.tar
somefile: POSIX tar archive

What I needed was a tool that would run the file command at various offsets within an image file and log the results.

A quick bit of coding yielded fsearch.c:

// fsearch.c: runs the "file" command on all byte offsets in an image file

// license: GPL. See gnu.org for details
// requires: an external "file" command and a Unixable OS (cygwin works)
// caution: fsearch yeilds lots of false positives.
// compile: cc fsearch.c -o fsearch
// usage: fsearch imagefile


#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  FILE *in, *out;
  int t;
  char *buffer;
  char syss[1024];
  char resultsfile[1024], fname[1024];

  int fsize, wsize;

  if (argc < 2) {
    fprintf(stderr, "%s must be called with a filename argument\n", argv[0]);
    exit(1);
  }
  // the name of the results file
  snprintf(resultsfile, 1024, "%s.results.txt", argv[1]);

  // zero out the results file if it exists
  out = fopen(resultsfile, "wb");
  if (out == NULL) {
    fprintf(stderr, "couldn't write to filesystem\n");
    exit(1);
  }
  fclose(out);

  strcpy(fname, argv[1]);

  in = fopen(fname, "rb");
  if (in == NULL) {
    fprintf(stderr, "couldn't read %s\n", fname);
    exit(1);
  }
  // fetch the filesize
  fseek(in, 0, SEEK_END);
  fsize = ftell(in);
  fclose(in);

  buffer = malloc(fsize);
  if (buffer == NULL) {
    fprintf(stderr, "couldn't allocate buffer memory\n");
    exit(1);
  }
  in = fopen(fname, "rb");
  if (in == NULL) {
    fprintf(stderr, "couldn't open %s for reading\n", fname);
    free(buffer);
    exit(1);
  }
  if (fread(buffer, 1, fsize, in) < fsize) {
    fprintf(stderr, "trouble reading %s\n", fname);
    free(buffer);
    exit(1);
  }
  fclose(in);
  for (t = 0; t < fsize - 1; t++) {
    out = fopen("filetype-guess", "wb");
    if (out == NULL) {
      fprintf(stderr, "couldn't open 'filetype-guess' for writing\n");
      free(buffer);
      exit(1);
    }
    if (fsize - t > 512)
      wsize = 512;
    else
      wsize = fsize - t;
    fwrite(buffer + t, 1, wsize, out);
    fclose(out);
    sprintf(syss, "echo 0x%x - $(file filetype-guess) >> %s", t, resultsfile);
    system(syss);
  }
  free(buffer);

#ifdef WIN32
  system("del filetype-guess 2> NUL");
#else
  system("rm filetype-guess 2> /dev/null");
#endif

  exit(0);
}

Firmware Analysis Part II: The Legend of Curley's Gold

I then ran fsearch against the firmware update and waited a while for it to build up its log.

Being impatient, I stopped it when it had passed the interesting "unzip" area.

Bingo - at offset 0x3A28, fsearch had some interesting information:

0x3a28 - filetype-analysis: gzip compressed data, was "image.bin", from Unix, max compression

It turns out from 0x3A28 to the end of the file is just one big gzip file that gets used for filesystem update.

On to image.bin

I extracted the gzip with the following command:

$ dd if=update-file-from-hawking of=image.bin.gz bs=1 skip=14888

which creates image.bin.gz, which I gunzipped with:

$ gunzip image.bin.gz

Which creates the uncompressed image.bin, which I then loaded up into the hex editor.

image.bin appears to be a raw flash image, ripe for editing.  It begins with what I believe is a kernel (and possibly so me other data), followed by a ROMFS filesystem at 0x18E060.

I managed all of my initial hacks with just a hex editor, but I've since extracted the ROMFS, created a replacement, and stuck it back on.  I leave this as an exercise to the reader.

The Edits

The first order of business was adding a root shell.

Investigating the image contents revealed that although there was a commented-out inet.conf entry for telnetd, no such binary existed.  Not a problem, since you can always run a shell from inetd for a quick-and-dirty telnetd.

There were actually three inetd.conf type files, inetd.conf itself, and two other prototype inetd.conf files that are used by the configuration scripts to build inetd.conf.

I edited all of them so the line that used to read:

uptime stream tcp nowait root /bin/cat /proc/uptime /etc/issue

now reads:

uptime stream tcp nowait root /bin/sh -i

Since this line was shorter than the original, I changed extra characters into 0A newlines, so as not to goo up inetd.

After adding the root shell to the image, I then changed one of the comments in the /etc/rc startup script to call my own /mnt/sys/etc/init.sh script.

/mnt is where the IDE hard disk gets mounted, so this would allow me to add additional scripts and binaries on the hard disk without any messy firmware updates.

The last few lines used to read:

/etc/rc.d/init.sh start || "Can't start init.sh!"
exit
# End of file /etc/rc

I changed them to now read:

/etc/rc.d/init.sh start || "Can't start init.sh!"
/mnt/sys/etc/init.sh &
exit

Putting It Together and the Acid Test

Putting it back together was fairly easy...

$ gzip -9 image.bin
$ (dd if=update-file-from-hawking bs=1 count=14888; cat image.bin.gz) > hacked-update.web

I held my breath as I sent the update to the HNAS1 via the browser-based admin tool.

The tool counted down from 150 seconds.  Would I brick my $90 investment?  Would the update fail due to some checksum I hadn't tracked down?

Nope!  A telnet to port 24 now gave me:

Connected to 192.168.1.155.
Escape character is '^]'
BusyBox v0.60.3 (2005.06.07-05:49+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.
#

Yay, a prompt!

I then added a test init.sh script to /mnt/sys/etc/ that just contained the following:

/bin/touch /mnt/sys/etc/I_RAN

A reboot later revealed the creation of the I_RAN file in the /mnt/sys/etc directory.  The box was mine.

I set up a cross-compiler and built thttpd.  The details are long and boring, and documented elsewhere on the web.  Just Google "gcc mips cross-compiLer" and you should be able to find your way.

After building thttpd, I then put it in the /mnt/sys/bin directory and added a command to launch it from: /mnt/sys/etc/init.sh

Another reboot later and I had my web server sharing out files.  Mission complete!

Postscript

After hacking this thing wide open I discovered some interesting news.

Some hackers in Germany have been providing replacement firmware for some of the other rebranded units (though not the HNAS1).  As far as I can tell, they haven't released the details of the firmware update file as I've done here.

While these firmware updates aren't directly applicable to the HNAS1 - not without ripping the update apart and changing the internal signatures - they are a great source of pre-compiled MIPS binaries.  The same hackers have also seen fit to share some individual pre-compiled binaries on their site as well.

Links

Code: fsearch.c

Return to $2600 Index