As someone who has always been fascinated by small-scale embedded computing, I can hardly describe my excitement when I happened across this post on HackerNews: http://haxit.blogspot.com.es/2013/08/hacking-transcend-wifi-sd-cards.html

In short, the author, Pablo, was able to take advantage of vulnerabilities of the poorly coded CGI scripts of the Transcend WiFi SD card's web interface, to examine the filesystem, and ultimately upload his own binaries and modified files.

I, along with many others, were inspired: Wouldn't it be awesome to be able to customize our own Linux system on that device?

It could serve as...

  1. A small portable fileserver that can be powered by batteries and hidden in your wallet.
  2. A network application server run indefinitely off of batteries (and solar panel) without all the power-consuming doodads of a full blown Raspberry Pi.
  3. A discreet portable webserver/router with wiki/forum software to allow political dissidents to organize
  4. It could serve as a remote proxy connected to some free Starbucks Wifi and taped behind some toilet in the restroom... A spy device? etc.
  5. For me, it could serve as a cheap WiFi shield for an Arduino/AVR. The micro-controller could dump text files into the SD card. A script on the card would monitor, parse, and send the data to wherever it needs to go... and vice versa! When range isn't key, this solution is much cheaper than buying this: https://www.sparkfun.com/products/11287

As a 400 MHz Linux system with 32 MB of RAM, using only ~100 mA @ 3.3 V, the possibilities are endless!

Standing on the Shoulders of Giants

EDIT: Scroll down for scripts and program by another author who had came to the same result

As I don't have one of those cards on hand (~$40), I decided to download the firmware and see how far I can get with modifying it.

In the Firmware_V1.7 folder, we see the following:

$ ls -al
total 6524
drwxrwxr-x 2 robert robert    4096 May 15 14:48 .
drwxrwxr-x 7 robert robert    4096 May 22 11:43 ..
-rw-rw-r-- 1 robert robert 2664833 Apr 17 18:03 image3
-rw-rw-r-- 1 robert robert 2807347 May 15 10:33 initramfs3.gz
-rw-rw-r-- 1 robert robert 1048576 May 15 10:33 mtd_jffs2.bin
-rw-rw-r-- 1 robert robert  110660 Apr 17 18:03 program.bin

Cool, some familiar names here... let's see if we can open some of these files:

$ file *
image3:             data
initramfs3.gz:      data
mtd_jffs2.bin:      Linux jffs2 filesystem data little endian
program.bin:        data

Hmm... despite the intuitive filenames, it looks like some of the files may be encrypted or obfuscated in some way. However, the real fruit is in getting access to the contents of initramfs3.gz

After Googling around, I happened across a Japanese blog detailing the hacking of the firmware for various other brands of WiFi SD cards: http://blog.osakana.net/archives/category/minor/flucard

The content looked applicable, so I followed the instructions there. The new insight from the blog was that for whatever arbitrary reason, I had to take off the first 8 bytes of the initramfs3.gz file in order to get the real initramfs3.gz file

$ expr 2807347 - 8
2807339

$ cat initramfs3.gz | tail -c 2807339 > initramfs3-real.gz

$ file initramfs3-real.gz
initramfs3-real.gz: gzip compressed data, from Unix, last modified: Tue May 14 19:33:08 2013

Woah, magic! We have a real gzip file now, this should be familiar territory- let's unzip and get the cpio archive.

$ gzip -dc initramfs3-real.gz > initramfs.cpio
$ file initramfs.cpio
initramfs.cpio: ASCII cpio archive (SVR4 with no CRC)

Cool! Unfortunately, the post on the Japanese blog leaves it at that... Let's keep going further:

$ mkdir root; cd root
$ sudo cpio -i -d -H newc --no-absolute-filenames < ../initramfs.cpio
11783 blocks

... and voila!

$ ls
bin  dev  etc  home  init  lib  linuxrc  lost+found  mnt  proc  root  sbin  sys  tmp  ts_version.inc  usr  var  www

$ cd www; ls
back.gif    blank.html  dir.gif      frame1.html  index.html  multi_download_decode.jar  page       page.jpg  sd        uploadto.html
banner.jpg  cgi-bin     favicon.ico  frame2.html  mtd         nothumb.jpg                page.html  script    text.gif

$ cat ../etc/version.txt
Product Name     : KeyASIC WIFI-SD
Firmware Version : V150
Build Date       : 17 APR 2013
Revision         : V150
WiFi Model       : Atheros AR6003 11n
Linux Kernel     : 2.6.32.28
Busybox          : 1.18.5

Forging New Ground

Can I build my own binaries for this?

I was on my ARMv5 Chromebook running Ubuntu (using crouton) with your standard set of build tools... linking against uClibc would be trivial. The author of the original article was able to upload an ARMv5 busybox binary. I took a quick look at the existing busybox binary.

$ cd ../bin; file busybox
busybox: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, stripped

$ ./busybox
BusyBox v1.18.5 (2013-04-17 18:28:03 CST) multi-call binary.
Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

Looks almost certain, but for a resounding yes, I would have to test my own binaries on a real device.

Can I put it back together again?

$ sudo find . | cpio -H newc -o > ../initramfs-real
$ cd ..
$ gzip -9 initramfs-real

However, recall that to obtain a working gzip file, we had to cut out the first 8 bytes.

Did these first eight bytes specify a checksum, the size of the file, or was it simply padding to prevent prying eyes?

Getting the "original" gzip may not be as simple as pre-pending those 8 bytes again.

To find out, I got an older version of the firmware to compare...

On the version 1.6 firmware:

$ hexdump -n 8 -C initramfs3.gz
00000000 4b 41 47 5a 00 28 a1 98 |KAGZ.(..|
00000008

On the version 1.7 firmware:

$ hexdump -n 8 -C initramfs3.gz
00000000 4b 41 47 5a 00 2a d6 2b |KAGZ.*.+|
00000008

At this point, we see that out of the 8 byte header padding, the difference is in the last four bytes. Let's see if these last four bytes represent the size of the file.

I printed the 4 bytes as a 32 bit int for the version 1.7 firmware:

$ printf "%i\n" 0x002ad62b
2807339

$ ls -al initramfs3-real.gz
-rw-rw-r-- 1 robert robert 2807339 Aug 11 23:15 initramfs3-real.gz

Sweet! Now we know how to construct the header: "KAGZ" + 32bit size of gz

Conclusion

We come to a stop to our journey here... After a bit more Googling around, I happened upon a French blog, where the author, mars, came to the same conclusions with the PQI Aircard (WiFi microSD->SD Adapter Card) (A different product, but with similar hardware/software, and awesome in that you can put in your own microSD). http://lemoidului.wordpress.com/2013/03/18/linux-is-everywhere_pqi-aircard-partie-iv-flash-it/

Huge props to mars, as his/her solution is much more thorough, complete with two scripts to extract and build the initramfs. There is even a small C program to generate and append the header for you little-endian people. (The 4 bytes in the header representing the size of the gzip file is in big-endian format).

The author had the added benefit of having a serial console with which to test and debug his/her findings- the interesting discovery was that the size of the initramfs must remain below 3 MB. (If you have big files to add, do so in the JFFS2 program.bin)

All in all, it was an amazing experience of drawing together information form various sources- initial inspiration from Pablo's blog, insights from a Japanese blog, only to find that this has been fully covered in a French blog. International collaboration FTW!

Transcend WiFi Card Manual:

http://dk.transcend-info.com/support/dlcenter/Manual/WiFiSD_Manual_v11_EN.pdf

Firmware Links

http://dk.transcend-info.com/files/Driver/WiFiSD_v1.7.zip

http://dk.transcend-info.com/files/Driver/WiFiSD_v1.6.zip

I've bought one on Amazon and will update with new discoveries and custom builds!