Friday, May 30, 2014

Debian on the Intenso Memory 2 Move

Debian on the Intenso Memory 2 Move


Intenso Gmbh distributes a line of cheap, battery -powered portable 2.5'' external USB hard-drives which furthermore include WiFi and Ethernet capability. Such devices are very interesting for a variety of applications beyond those envisioned by the manufacturer, and would make for an ideal "PirateBox" among other things.

These notes refer in particular to the 1TB "Black" model:

Basic operating modes:

As described in the manual (mirrored here for convenience), the device has at least two operating modes. When connected via USB to a computer in the initial "power off" state, it behaves as a simple USB-to-SATA bridge, making the whole hard-disk externally accessible.

When indipendently switchted on, the internal embedded SoC Linux system takes over, and after a relatively fast booting sequence it will make a series of services available through the WiFi / Ethernet ports, while using any later USB connection only as a power source for topping up the internal battery of about 3000 mAh.

The SoC is rated for a typical power load of about 3W, to which the hard-disk consumption must be added - see below. If the chemistry would be a standard 3.7 V one, we would have 3.7*3=11.1 Wh of energy, or little more than 2 hours of continuous, standalone use once the top disk load of about 2 W is also accounted for.

Notice that while the hard-disk is properly spinned down after 3 minutes of uninterrupted idle, the default kernel appears to be compiled without any power management support, see below. Longer running time than the advertised 5 hours may be achievable.

Hardware description and default working modes:

The internal hard-disk seems to be a Seagate / Samsung part:
# hdparm -I /dev/sdb:
[...]
Model Number:           ST1000LM024 HN-M101MBB
[...]

... which should have the following specifications:
  • Form factor: 2.5", 9.5mm
  • Rotation speed: 5400rpm
  • Cache: 8MB
  • Power consumption: 2.20W (load), 0.70W (idle)
  • Loudness: 26dB(load), 24dB (idle)
  • SMART feature set: supported.
There have been reports of possible replacement with other disks, but even larger capacities than 1 TiB, despite possibly working, are normally thicker and don't fully fit within the case. Some rough ideas about performances:

  • When driven in standalone mode, from the embedded SoC Linux system:
    # hdparm -tT /dev/sda
    /dev/sda:
     Timing cached reads:   114 MB in  2.03 seconds =  56.21 MB/sec
     Timing buffered disk reads:   28 MB in  3.10 seconds =   9.04 MB/sec
  • When driven from the USB bridge mode, from an external PC:
    [...]

The internal SoC is very flexible, if somehow resources -limited. 
The devices uses a Ralink RT5350 MIPS24 KEc (cat /proc/cpuinfo: MIPS 24 Kc V4.12, corresponding to gcc -march=24kec switch, see below) with 32MiB of RAM, in a little-endian layout. As remarked here, this particular CPU variant lacks a hardware floating point unit (FPU), which has to be emulated in software. This is fine for the current deployment as portable NAS unit, or for the other common usage in routers etc. More demanding mathematical tasks, such as video compression in IP cameras etc., are based on variant with FPU included.

Some device -specific details are also tabulated on https://wikidevi.com/wiki/Intenso_Memory_2_Move_1TB_White.

Default services in the stock firmware ver. 1.1 are based on ulibc (the system will also re-create, if needed, and use an extra 64MiB of swap as a rather inefficient ".vst/swapfile" on the first VFAT/NTFS partition /dev/sda1 of the internal hard-disk) and include:

  • minidlna: DLNA (via UPnP) multimedia files serving, for instance to clients such as Android WonderShare player or Apple IOS analogus;
  • smbd: SMB protocol support for filesystem access from Microsoft Windows / Apple OSX / Linux;
  • lighttpd: HTTP protocol support for configuration and/or filesystem access from standard browsers
  • ...
Source code for all the GPL components is available as an archive from the manufacturer, and is mirrored here (MD5SUM: 296fce876c589c181aeabd1dcdcdb127) for convenience.

These notes report on the installation of a complete, if slightly out-of-date, Debian MIPSEL distribution "Lenny". This makes readily available for installation and use all packages listed i.e. here.

Compiling and running standalone code:

It is possible to develop and cross-compile standalone programs for the default embedded Linux system, working i.e. on a standard x86 Debian PC and just copying the resulting MIPS executables on the device as generic files.

This requires availability of a cross-compilation toolchain. A suitable one for Jessie/Sid may be installed by adding to /etc/apt/sources.list the lines:

# INTENSO MIPS
deb http://www.emdebian.org/debian/ squeeze main

Then simply:
apt-get install gcc-4.3-mipsel-linux-gnu

...will pull in all required dependencies.

A nice example of what can be compiled and run this way is the CLI "Tetris" game by Victor Nilsson.

Installing a full, ready-to-use Debian release:

Better capabilities can be made accessible through installation of a complete Debian environment.

"Lenny" i.e. Debian release 5.0 is the latest release that can run with the stock kernel 2.6.21. This allows in particular easiest and safest deployment on top of the existing firmware, as the whole system can work in a "chroot" jail with no risk of bricking the device.

Gaining root:

The stock firmware ver. 1.1 (mirrored here for convenience, MD5sum: 8acc9d9bbb8d18d5da2ad6b6a20a043d ) contains a backdoor. To my eyes this is by the way very useful, but an extremely dangerous data securety issue too.

In practice the system will boot in standalone mode with a telnetd daemon running on default port 23, and offering root login with:

username: root
password: 20080826

The instructions below mitigate the problem by switching off such daemon, and offering instead SSH access with a chosen password instead. This must however be repeated at every reboot, as by default the system starts in insecure mode.

Further notes below document a different attempt to address the issue by rebuilding the embedded Linux firmware. One should consider the security implication of the classic "Trusting trust", and more recent discussions such as this post by Bruce Schneier.

Choosing a suitable Debian version:

After logging in as root through the stock firmware telnet backdoor, the system reveals itself as:

  • Processor brand and featurs:
    # cat /proc/cpuinfo
    system type             : Ralink SoC
    processor               : 0
    cpu model               : MIPS 24K V4.12
    BogoMIPS                : 239.61
    wait instruction        : yes
    microsecond timers      : yes
    tlb_entries             : 32
    extra interrupt vector  : yes
    hardware watchpoint     : yes
    ASEs implemented        : mips16 dsp
    VCED exceptions         : not available
    VCEI exceptions         : not available
     
  • The physical RAM is:
    # free
    free 
                 total       used       free     shared    buffers     cached
    Mem:         28008      26028       1980          0       2016      13384
  • The kernel version in use is:
    # uname -a
    Linux M2M 2.6.21 #256 Thu Apr 25 09:35:37 CST 2013 mips GNU/Linux
  • The default booting arguments were:
    # cat /proc/cmdline
    console=ttyS1,57600n8 root=/dev/mtdblock8 rootfstype=squashfs quiet

    (a serial console should in other words be available for debugging, if interfacing with the appropriate pins on the mainboard);
  • The default flash memory layout reads:
    # cat /proc/mtd
    dev:    size   erasesize  name
    mtd0: 00800000 00010000 "ALL"
    mtd1: 00030000 00010000 "Bootloader"
    mtd2: 00010000 00010000 "Config"
    mtd3: 00010000 00010000 "Factory"
    mtd4: 00180000 00010000 "Kernel_RootFS"
    mtd5: 00010000 00010000 "params"
    mtd6: 00010000 00010000 "user_backup"
    mtd7: 00010000 00010000 "user"
    mtd8: 00600000 00010000 "Rootfs
All the above points to the conclusion that a viable option for full Linux environment installation will be Debian 5.0.10 "Lenny", in the little endian "MIPSEL" architecture.

A later, more up-to-date distribution release will not be compatible with the stock firmware kernel.

Debian root filesystem option 1: As a loopback image within the default hard-disk partion scheme:

Advantages:
  • Simplest deployment;
  • Safer against unmounting;
Disadvantages:
  • Fairly inefficient I/O, which makes many operations painful to use on the rather resources -starved SoC;
In view of the above considerations, a different installation scheme based on proper hard-disk re-partitioning and ext2 formatting (outlined  below) is preferred. In either cases, the first steps of passing through a loopback image are shared, and detailed in the instructions below:

  1. Prepare and mount an image filesystem to work on:
    # dd if=/dev/zero of=/tmp/debianfs bs=1M count=2000

    (something smaller than 2GiB may also be sufficient);

    # mkfs.ext2 /tmp/debianfs

    mount /tmp/debianfs /tmp/db -o loop

    (modprobe loop may be required);
  2. Fill the image filesystem with a basic Debian "Lenny" installation:
    # apt-get install debootstrap

    # debootstrap --foreign --verbose --arch=mipsel lenny /tmp/db/ http://archive.debian.org/debian-archive/debian/

    (apt-get install debootstrap may be required);
  3. Transfer the image filesystem to the device:
    # umount /tmp/db ; mount -t cifs //10.10.10.254/WiFiDisk1_Volume1/ /mnt -o username=admin

    (or just switch the disk off and connect & mount it as USB mass storage, to perform a faster copy);
  4. Log on the stock firmware Linux system through the backdoor:
    # telnet 10.10.10.254

    (default IP assignment for WiFi connection),
    username: root
    password: 20080826
  5. Mount the empty filesystem image to complete the Debian base installation, automatically downloading all the needed "base" packages from the network:
    # mount data/UsbDisk1/Volume1/debianfs /mnt/ -o loop

    (on a single line:)
    # DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt /debootstrap/debootstrap --second-stage
    DEBIAN_FRONTEND=noninteractive

    (on a single line:)
    # DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot /mnt dpkg --configure -a
  6. Set up the Debian system network and virtual filesystems: verify that its /etc/resolv.conf points to a proper nameserver, i.e. contains something like:
    # cat /mnt/etc/resolv.conf
    nameserver 192.168.43.1

    ...and that these mountpoints are present and properly populated:
    # mount none /mnt/proc -t proc
    # mount -t sysfs sysfs /mnt/sys/
    # mkdir /mnt/dev/pts
    # mount -t devpts devpts /mnt/dev/pts/
    # mount -t usbfs usbfs /mnt/proc/bus/usb/

    Further useful devices may be creted with:
    # mknod /dev/sda b 8 0
    # mknod /dev/sda1 b 8 1
    # mknod /dev/sda2 b 8 2

    ... and the default VFAT partition may be made visible to the Debian system too with:
    # mount /dev/sda1 /mnt/mnt
  7. Set up the correct time zone:
    # dpkg-reconfigure tzdata

    The command:
    # ntpdate-debian
    ... may later be used for precise NTP clock syncronization.
  8. Install any other needed Debian package as usual. At the very least, a SSH server is advised, such as dropbear:
    # apt-get install dropbear
  9. Verify SSH is working:
    # netstat -tan
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State     
    tcp        0      0 *:8200                  *:*                     LISTEN    
    tcp        0      0 *:netbios-ssn           *:*                     LISTEN    
    tcp        0      0 *:www                   *:*                     LISTEN    
    tcp        0      0 *:81                    *:*                     LISTEN    
    tcp        0      0 10.10.10.254:5880       *:*                     LISTEN    
    tcp        0      0 192.168.43.246:5880     *:*                     LISTEN    
    tcp        0      0 localhost:6010          *:*                     LISTEN    
    tcp        0      0 *:microsoft-ds          *:*                     LISTEN    
    tcp        0      0 10.10.10.254:www        10.10.10.2:56894        ESTABLISHED
    tcp        0      0 localhost:81            localhost:3122          TIME_WAIT 
    tcp6       0      0 [::]:ssh                [::]:*                  LISTEN    
    tcp6       0      0 10.10.10.254:ssh        10.10.10.2:35305        ESTABLISHED
  10. close the stock firmware backdoor:
    # killall telnetd

    (the backdoor will be automatically re-opened upon rebooting, until the "rootfs" default initrd squashfs flashed on the NAND memory is customized as per instructions below)

Debian root filesystem option 2: as a standalone ext2 partition within  a re-partitioned hard-disk

The stock kernel has been compiled with no more modern filesystem capabilities than "ext2".

Advantages:
  • faster;
  • slightly safer from accidental erasure when using the system as a dumb USB external disk;
This latter method is preferred, and better described below.

Repartition:
  • The stock firmware Linux system is set up to assume that a (ex)VFAT or NTFS partition should be present as /dev/sda1, and be used for all the default standalone device services.
  • Create a swap partition. Suggested size is just 64MiB, i.e. twice as big as the physical RAM; for better performances it is best to set it up as close as possible to hard disk cylinder 0, i.e. as /dev/sda2 just after the resized /dev/sda1;
  • Create a ext2 partition for the new Debian MIPSEL installation. Suggested size is about 3GBi, as /dev/sda3;
  • Create a ext2 partition with the rest of the unallocated space, i.e. as /dev/sda4.
This step can be carried out via i.e. the Gnome Partition Editor "http://gparted.org/liveusb.php", available as standard Linux application or a standalone, bootable USB image.
Install the base system:
Same as for the method above. At the end of it, simply copy everything to the desired ext2 partition, such as /dev/sda3 in the scheme above (make sure not to unnecessarily copy bare devices themselves from /dev !).
Prepare an automatic Debian launcher script
The following "~/bin/autolog.sh" may be used to semi-automatically boot the Debian system after each device reboot. It assumes the "telnet" client and "expect" interpreter being available, and works through the default firmware ver. 1.1 backdoor:

#!/usr/bin/expect
# Script to deploy the Debian chroot and close the default telnet backdoor.

# Access the backdoor:
spawn "telnet" "10.10.10.254"

expect "M2M login:"
send "root\r"
expect "Password:"
send "20080826\r"
# expect "BusyBox"
expect "#"

# We are in. Switch from the VFAT -hosted swapfile to a swap partition (faster):
send "swapon /dev/sda2\r"
expect "#"
send "swapoff /data/UsbDisk1/Volume1/.vst/swapfile\r"
expect "#"

# Mount the Debian and leftover storage partition. Sync mode is used, even if slower (the SoC offers limited performances anyway, we are limited by it rather than the I/O subsystem) to afford a margin of safety against sudden switching off.

send "mount /dev/sda3 /mnt/ -o sync\r"
send "mount none /mnt/proc -t proc\r"
expect "#"

# Populate the virtual filesystem:
send "mount -t sysfs sysfs /mnt/sys/\r"
expect "#"
# send "mkdir /mnt/dev/pts\r"
send "mount -t devpts devpts /mnt/dev/pts/\r"
expect "#"
send "mount -t usbfs usbfs /mnt/proc/bus/usb/\r"
expect "#"


# Start the chroot. WARNING: no standard services are initialized, this saves resources but breaks some Debian available services assumptions.
send "chroot /mnt /bin/bash\r"
expect "#"


# Before mounting the leftover partition, the Debian fsck.ext2 tool is used to check it for errors in case it has not been properly unmounted before:
send "fsck.ext2 -p -v -C0 /dev/sda4\r"
expect "#"
send "mount /dev/sda4 /home/ -o sync\r"
expect "#"

# Mount everything else may have been configured:
send "mount -a\r"
expect "#"


# Launch the SSH server: either Dropbear (fewer resources) or OpenSSH:
send "/etc/init.d/dropbear start\r"
expect "Starting Dropbear SSH server: dropbear."
# send "/etc/init.d/ssh start\r"
# expect "Starting OpenBSD Secure Shell server: sshd."

# Close this telnet backdoor, leaving only SSH (and other stock firmware services such as UPnP i.e. minidlna, SAMBA i.e. smbd etc.) access:
send "killall telnetd\r"

# interact

Prepare a custom firmware:

Temporary notes, high risk of bricking the device. Proceed with caution! No kernel upgrade has been tried yet, only userspace modifications.

Analysis of a stock firmware image and the flashing process:

The following notes apply to the stock firmware ver. 1.1:
$ unzip 1389341356.zip gives a license, and the actual firmware image fw-M2M-1.100.000

fw-M2M-1.100.000 is a peculiar UNIX self-extracting archive.
$ file fw-M2M-1.100.000 returns:
fw-M2M-1.100.000: POSIX shell script executable (binary data)

$ binwalk fw-M2M-1.100.000 returns:

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
4326            0x10E6          gzip compressed data, was "initrdup", from Unix, last modified: Mon Jul  1 09:44:07 2013, max compression
1539822         0x177EEE        LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 65536 bytes
[...]

In practice, the first 170 ASCII text lines are a shell script that instruct on how to unpack (and flash) the rest. Following these, we begin with:

tail -n +171 fw-M2M-1.100.000 > upfs.gz

which gives:
$ file upfs.gz
upfs.gz: gzip compressed data, was "initrdup", last modified: Mon Jul  1 09:44:07 2013, max compression, from Unix

$ gunzip upfs.gz
gives a upfs file, which is a standard ext2 filesystem image:

$ file upfs
upfs: Linux rev 1.0 ext2 filesystem data, UUID=48ee846c-1fa2-4ad2-a3d0-692446b63b1f

This can be mounted as loopback device for further analysis:
# mount upfs initdup/ -o loop

initdup# ls -l
total 15
drwxr-xr-x 2 root root 2048 Mar 21  2013 bin
drwxr-xr-x 3 root root 1024 Jul 15  2012 boot
drwxr-xr-x 3 root root 1024 Jul 15  2012 config
drwxr-xr-x 5 root root 1024 Jul 15  2012 dev
drwxr-xr-x 2 root root 1024 Jun  9  2013 etc
drwxr-xr-x 2 root root 1024 Jul  1  2013 firmware
drwxr-xr-x 5 root root 2048 Jul 15  2012 lib
drwxr-xr-x 3 root root 1024 Jul 15  2012 mnt
drwxr-xr-x 2 root root 1024 Jul 15  2012 proc
drwxr-xr-x 2 root root 1024 Jul 15  2012 sys
-rwxr-xr-x 1 root root 1151 Nov 21  2012 update.sh
drwxr-xr-x 5 root root 1024 Jul 15  2012 var

The "update.sh" script does the flashing of the MTD NAND, as directed by its numerical argument. In particular, it takes versioning informations, the kernel binary, its rootfs and the U-Boot bootloader from the "firmware" subdirectory:
# cat firmware/firmware.conf
NEWFILE=M2M
NEWVER=1.100.000
NEWBUILD=7

# file firmware/kernel
firmware/kernel: u-boot legacy uImage, Linux Kernel Image, Linux/MIPS, OS Kernel Image (lzma), 1439867 bytes, Thu Apr 25 03:35:52 2013, Load Address: 0x80000000, Entry Point: 0x8043F000, Header CRC: 0x6A7044ED, Data CRC: 0x652C3C28

The first difficulty appears in interpreting the firmware/rootfs file. At first its magic is not recognized:
# file firmware/rootfs
firmware/rootfs: data
but binwalk reveals:
# binwalk firmware/rootfs

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
0               0x0             Squashfs filesystem, little endian, non-standard signature,  version 3.0, size: 5167458 bytes,  926 inodes, blocksize: 65536 bytes, created: Mon Jul  1 09:44:02 2013

As shown by hexedit, the file begins with "shsq" rather than the usual "hsqs", thus the "non-standard signature" statement. This denotes a LZMA compression scheme with SWAPPED fields, which is not yet supported by Debian "unstable" unsquashfs-tools ver. 1:4.0-8 :

# unsquashfs -h
[...]
Decompressors available:
        gzip
        lzo
        xz

To unpack this, a later version of the squashfs tools may be downloaded from SourceForge via GIT (apt-get install git may be needed):
$ git clone git://git.code.sf.net/p/squashfs/code squashfs-code

It must be compiled with the new compression scheme enabled, but also a patch to support this particular deployment.
  1. Download a patch from: http://sourceforge.net/p/squashfs/patches/20/, and apply it:
    $ git apply --stat ~/Downloads/0001-unsquashfs-add-support-for-LZMA-magics.patch

    ...will show:

    $ cd .. ; git apply --check ~/Downloads/0001-unsquashfs-add-support-for-LZMA-magics.patch

    squashfs-tools/squashfs_fs.h |    6 ++++++
    squashfs-tools/unsquashfs.c  |   24 ++++++++++++++++++------
     2 files changed, 24 insertions(+), 6 deletions(-)

    ... should show no output (i.e. no errors or conflicts, the patch may be applied cleanly);
  2. Actually apply the patch; either via git, or by hand (removing all lines before:
    --- a/squashfs-tools/squashfs_fs.h
    +++ b/squashfs-tools/squashfs_fs.h , and issuing a simple:
    patch -p1 < 0001-unsquashfs-add-support-for-LZMA-magics.patch )
  3. Edit the squashfs-tools/Makefile and make sure that it reads (apt-get install liblzma-dev may be needed):
    [...]
    ########### Building XZ support #############
    #
    # LZMA2 compression.
    #
    # XZ Utils liblzma (http://tukaani.org/xz/) is supported
    #
    # To build using XZ Utils liblzma - install the library and uncomment
    # the XZ_SUPPORT line below.
    #
    XZ_SUPPORT = 1
    [...]
    and further below:
    [...]
    ########### Building LZMA support #############
    #
    # LZMA1 compression.
    #
    # LZMA1 compression is deprecated, and the newer and better XZ (LZMA2)
    # compression should be used in preference.
    #
    # Both XZ Utils liblzma (http://tukaani.org/xz/) and LZMA SDK
    # (http://www.7-zip.org/sdk.html) are supported
    #
    # To build using XZ Utils liblzma - install the library and uncomment
    # the LZMA_XZ_SUPPORT line below.
    #
    # To build using the LZMA SDK (4.65 used in development, other versions may
    # work) - download and unpack it, uncomment and set LZMA_DIR to unpacked source,
    # and uncomment the LZMA_SUPPORT line below.
    #
    LZMA_XZ_SUPPORT = 1
    #LZMA_SUPPORT = 1
    [...]
  4. Alternatively, an archive of the patched & configured snapshot of the tools is made available here. Simply unpack and issue a:
    make
Now the root filesystem may be unpacked and studied in full detail:
# unsquashfs -li /tmp/initdup/firmware/rootfs

For instance, the default passwords for the "admin" user, and the "root" backdoor may be brute-forced via John the Ripper (apt-get install john may be needed):
# john etc/passwd
Created directory: /root/.john
Loaded 2 password hashes with 2 different salts (md5crypt [MD5 32/64 X2])
Press 'q' or Ctrl-C to abort, almost any other key for status
00000            (admin)

This will be the default configuration password for the stock firmware HTTP interface.

Some additional information for this firmware release can be found in the etc/versioninfo file:
[...]
uboot=5350/bootloader-mt5350-32M-2013-04-25-09-25.img
kernel=5350/kernel-rt5350-32M-2013-04-25-09-31

... which would point to a Ralink 5350 part running at 360MHz, and confirming availability of 32MiB RAM.

Customizing a stock firmware image:

When rootfs modifications are satisfactory, the new filesystem can be re-squashed via:
mksquashfs . ../new_rootfs -comp lzma

The mksquashfs compiled above, or the default Debian "Jessie" ver. 4.0, will however not be suitable for re-compressing the image before flashing. Besides compressor support for other algorithms such as LZMA, the squashfs binary format has been changed before vanilla kernel inclusion, and is not backwards compatible with the patched support of stock firmware kernel ver. 2.6.21, which will not mount our new new_rootfs file with error message:
SQUASHFS error: Major/Minor mismatch, trying to mount newer 4.0 filesystem
SQUASHFS error: Please update your kernel

Upgrading kernel at the same time as the root filesystem on an embedded system is risky, we may lose all access to the device if something goes wrong.

We can however simply produce a vintage format of our modified rootfs, using obsolete versions of the mksquashfs as available from i.e. the Debian archive. After unpacking the original firmware rootfs through the patched, latest unsquashfs v4.0, it doesn't really matter if the new, modified rootfs will be compressed via gzip rather than the more space efficient LZMA method.

The mksquashfs utility compiled from squashfs_3.1r2.orig.tar.gz works:
# mksquashfs squashfs-root/ new_rootfs_v3.1_format

...gives a file in the older ver.3.0 format:
$ binwalk new_rootfs_v3.0_format

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
0               0x0             Squashfs filesystem, little endian, version 3.0, size: 6043973 bytes,  920 inodes, blocksize: 65536 bytes, created: Fri May 30 17:14:40 2014


...which the stock firmware kernel ver. 2.6.21 can mount without problems, for instance as loopback filesystem just for testing before flashing:
# mount /mnt/new_rootfs_v3.0_format /opt/ -o loop
M2M:/# ls /opt/
bin  boot  data  dev  etc  etc_ro  home  lib  media  mnt  opt  proc  sbin  sys  tmp  usr  var  www

The standard magic "hsqs" header will now denote in particular reliance on the older, less efficient compression algorithm.

When all customizations are satisfactory, the "new_rootfs" can replace the original "firmware/rootfs":
$ mv new_rootfs_v3.0_format firmware/rootfs

The whole pre-flashing filesystem can then be unmounted:
# umount initdup

...and re-compressed via gzip:
# gzip initdup

As a last step a self-extracting firmware file has to be created. In particular, the modified ext2 initdup.gz payload will have a different CRCSUM, as computed by the standard 'cksum' utility after some file massaging by sed.

Following the original firmware file scripted lines, the checksum is computed as:

$ sed '1,3d' fw-M2M-1.100.000 |cksum|sed -e 's/ /Z/' -e 's/   /Z/'|cut -dZ -f1
3696346624

... which matches the expected value as listed within the self-extracting archive:

$ head fw-M2M-1.100.000
#!/bin/sh
# constant
CRCSUM=3696346624
[...]

The new self-extracting firmware can be assembled as follows:
  1. Extract the unpacking and flashing script lines:
    $ head -n 170 fw-M2M-1.100.000 > self_extracting_fw_header.sh
  2. Prepare a temporary firmware (complete payload, but still invalid CRCSUM) with:
    $ cp self_extracting_fw_header.sh self_extracting_fw.sh
    $ cat upfs.gz >> self_extracting_fw.sh
  3. Compute the valid CRCSUM via:
    $ sed '1,3d' self_extracting_fw.sh |cksum|sed -e 's/ /Z/' -e 's/   /Z/'|cut -dZ -f1

    ...and replace the resulting value inside the new self_extracting_fw.sh file.

    Normally, more than a single iteration can be required: the CRCSUM field is also part of the file content, for which the CRC is calculated, hence it changes as the field is updated. Such CRC calculation procedure is however a sort of lossy compression scheme. As such, modification of a few bytes, like the CRCSUM=... constant, will not change the outcome dramatically. Recalculation a second time is typically sufficient; just repeat this step 3) until the check value is stable and matches the file content.
The customized firmware is now ready for flashing, simply using the default HTTP interface and internal tools. Be aware that this will also reset the WiFi network configuration options.

Building a complete alternative:


A custom embedded Linux image may be assembled ("backed", in Android jargon...) via the BuildRoot system. This allows a great amount of customization, as it provides a set of rules and Makefiles to download, configure and cross-compile only the needed package and specifically supporting the device hardware, for a more efficient usage of the available SoC resources.

Apparently, Ralink also provides a customized BuildRoot SDK. A mirror copy of ver. 4.0.1.0 (including a more recent, but patched for a later board, Linux kernel 2.6.36 besides an older, patched ver. 2.6.21) is available for download for instance here.

The SDK above still needs an external cross-compilation toolchain. The oldish kernel version provided looks in particular not compatible with later GCC developments, such as ver. 4.4 included in the above MIPS(el) toolchain.

It would fail with error:
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  CC      arch/mips/kernel/asm-offsets.s
arch/mips/kernel/asm-offsets.c: In function 'output_mm_defines':
arch/mips/kernel/asm-offsets.c:233: error: invalid 'asm': invalid use of '%X'
arch/mips/kernel/asm-offsets.c:234: error: invalid 'asm': invalid use of '%X'
arch/mips/kernel/asm-offsets.c:235: error: invalid 'asm': invalid use of '%X'
/tmp/rt5350_GPL_source/kernel/linux-2.6.21.x/./Kbuild:42: recipe for target 'arch/mips/kernel/asm-offsets.s' failed
make[1]: *** [arch/mips/kernel/asm-offsets.s] Error 1
Makefile:863: recipe for target 'prepare0' failed
make: *** [prepare0] Error 2


It seems the SDK refers to a specific GCC version, gcc-3.4.2. This is available from a study of another Ralink -based product, the Coolcam NIP-09 NIP-02, also based on the RT5350 (in the F = FPU variant). And also, by the way, including a telnet backdoor! (username: root, password: 123456) and is mirrored here for convenience.

Instructions on how to use the SDK and toolchain are available from here, and have been also mirrored here for convenience. In practice, the content of buildroot-gcc342.tar.bz2 should be placed within /opt, and one may issue:
$ export MANPATH=$MANPATH:/opt/buildroot-gcc342/man

... to furthermore have access to the included manpages.

Another, slightly more up-to-date version of the SDK (ver. 4.1.1.0) has been also made available online, and is mirrored for convenience here (including compiler toolchain etc.).

Further packages which may require installation are, for instance:
# apt-get install flex bison

... and so on, as per list of dependencies.

LZMA compression:
  • Beside that toolchain, a (patched up) standalone LZMA compressor is also needed, if one wants to follow the default SDK build process. It seems slightly different from this version, and should be provided as part of the RT288X_SDK for instance. The utility "lzma_alone" must be compiled and placed in /opt/buildroot-gcc342/bin/
  • Alternatively, it seems possible to switch to the older, less space efficient but far more established gzip compression scheme. The crucial stage where the rootfs is compressed, as part of the kernel building process, is controlled by the scrip linux-2.6.21.x/scripts/gen_initramfs_list.sh, which can be modified not to use the (vendor -patched) lzma_alone compressor by changing interpretation of option use_lzma to "n":
    [...]
                    "-l")
                            use_lzma="n"
                            ;;
    [...]
To use the SDK, unpack it and enter the "source" subdirectory. Issue a:
$ make menuconfig

... command (apt-get install libncurses5-dev may be needed) and press Enter on the "Select the Product you wish to target", then select "Ralink Products", and "RT5350". Then select "Default configuration file" and choose "4M/32M(AP+NAS), and exit repeteadly.

The item "Kernel/Library/Defaults Selection" allows to change what cross-compiler chain to use, which parts of the BuildRoot distribution will be included in the firmware, which libc will these linked with, and which Linux kernel should drive the whole.

Even if no parameters will at first be changed, it is crucial to let BuildRoot scripted process take care of setting up the right cross-compiler toolchain in all subdirectory. This can be achieved by selecting for customization all the fields:
  • Customize Kernel Settings
  • Customize Vendor/User Settings
  • Customize Busybox Settings
  • Customize uClibc Settings
  • Customize uClibc++ Settings
... so that each one sub-menu will be brought up at least once, and updated with the right parameters from the main menu upon saving.


Once happy with all selection, save and exit the main menuconfig interface, and issue a simple:

# make

The build will take a few minutes but succeed without errors. The (safer) default BuildRoot behaviour has been modified in the SDK version, so as to try and create device files too under /dev in the rootfs. This will fail if the user is not root.
The outcome is stored in the images/ subdirectory, and attempts are made to also copy it as a /tftboot file in the host root filesystem (!). In particular, even after swiching off usage of the lzma_alone utility, a images/zImage.lzma file gets created and may be decompressed via:
$ unlzma ralink_sdk-master/source/images/zImage.lzma

Again binwalk provides better insight on its content:
$ binwalk zImage
$ binwalk zImage

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
752777          0xB7C89         LZMA compressed data, properties: 0x88, dictionary size: 1048576 bytes, uncompressed size: 4608 bytes
940089          0xE5839         LZMA compressed data, properties: 0x38, dictionary size: 1048576 bytes, uncompressed size: 4160 bytes
950753          0xE81E1         LZMA compressed data, properties: 0x30, dictionary size: 524288 bytes, uncompressed size: 992 bytes
2261044         0x228034        Linux kernel version "2.6.21 (root@t420) (gcc version 3.4.2) #2 Sat May 31 21:56:45 C 3.4.2) #2 Sat May 31 21:56:45 CEST 2014CEST 2014"
2267836         0x229ABC        LZMA compressed data, properties: 0x02, dictionary size: 16777216 bytes, uncompressed size: 50331648 bytes
2424580         0x24FF04        ASCII cpio archive (SVR4 with no CRC), file name: "sh entry"
2875460         0x2BE044        LZMA compressed data, properties: 0x02, dictionary size: 16777216 bytes, uncompressed size: 512 bytes
2875541         0x2BE095        LZMA compressed data, properties: 0x02, dictionary size: 131072 bytes, uncompressed size: 33620481 bytes
2887043         0x2C0D83        LZMA compressed data, properties: 0x02, dictionary size: 65536 bytes, uncompressed size: 32 bytes
2887067         0x2C0D9B        LZMA compressed data, properties: 0x02, dictionary size: 65536 bytes, uncompressed size: 128 bytes
2887259         0x2C0E5B        LZMA compressed data, properties: 0x02, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887283         0x2C0E73        LZMA compressed data, properties: 0x02, dictionary size: 65536 bytes, uncompressed size: 128 bytes
2887307         0x2C0E8B        LZMA compressed data, properties: 0x31, dictionary size: 65536 bytes, uncompressed size: 32 bytes
2887331         0x2C0EA3        LZMA compressed data, properties: 0x30, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887355         0x2C0EBB        LZMA compressed data, properties: 0x31, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887379         0x2C0ED3        LZMA compressed data, properties: 0x30, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887427         0x2C0F03        LZMA compressed data, properties: 0x30, dictionary size: 65536 bytes, uncompressed size: 128 bytes
2887451         0x2C0F1B        LZMA compressed data, properties: 0x40, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887475         0x2C0F33        LZMA compressed data, properties: 0x30, dictionary size: 65536 bytes, uncompressed size: 64 bytes
2887499         0x2C0F4B        LZMA compressed data, properties: 0x40, dictionary size: 65536 bytes, uncompressed size: 128 bytes
2887523         0x2C0F63        LZMA compressed data, properties: 0x40, dictionary size: 65536 bytes, uncompressed size: 256 bytes
2892036         0x2C2104        LZMA compressed data, properties: 0x01, dictionary size: 131072 bytes, uncompressed size: 2 bytes
2892136         0x2C2168        LZMA compressed data, properties: 0x09, dictionary size: 131072 bytes, uncompressed size: 2 bytes
2892156         0x2C217C        LZMA compressed data, properties: 0x0A, dictionary size: 131072 bytes, uncompressed size: 2 bytes
2894087         0x2C2907        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2894107         0x2C291B        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2894127         0x2C292F        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2894147         0x2C2943        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2894167         0x2C2957        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2894187         0x2C296B        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 896 bytes
2905944         0x2C5758        LZMA compressed data, properties: 0x01, dictionary size: 16777216 bytes, uncompressed size: 16777473 bytes
3084288         0x2F1000        gzip compressed data, from Unix, last modified: Sat May 31 21:56:39 2014, max compression

The crucial information is at the end. As a result of the gen_initramfs_list.sh script modification, the rootfs archive has been appended at the end of the file in gzip format. It can be extracted for verification by skipping all preceeding parts of the file:
$ dd if=zImage of=rootfs_recomp.gz seek=3084288 bs=1
and simply:
$ gunzip rootfs_recomp.gz
... to reveal a standard CPIO archive:
$ file rootfs_recomp
rootfs_recomp: ASCII cpio archive (SVR4 with no CRC)

As per standard Linux kernel documentation, this can be opened via:
$ cpio -i -d -H newc -F rootfs_recomp --no-absolute-filenames

(again, attempts at creating special /dev files will fail, without root permission)

In other words, we should be able to check that this SDK -recompiled CPIO archive of a rootfs matches the stock firmware "firmware/rootfs" ext2 image, which is itself normally shipped within the initrdup.gz payload of a ready-to-flash self-extracting firmware file.
This allows to upgrade the userspace parts of the embedded Linux environment, without changing yet the default kernel. It is possible in particular to close the default telnet backdoor; add other packages such as i.e. like the Snort NIDS to better monitor the network; and provide i.e. a out-of-the-box dropbear SSH server for better local access security.

One problem with the old GCC toolchain that Ralink SDK would use by default is lack of support for better CPU optimization. Contrary to the more up-to-date compiler that even Debian "Lenny" ships, GCC ver. 3.4.2 supports at most a:
 -mips32r2 -O3
... optimized build target, thereby not really exploiting more advanced capabilities of the SoC MIPS_24KEc processor.


Another alternative worthy considering would be plain adoption of an embedded Linux distribution such as OpenWRT, see for instance their useful explanation of the flash memory layout.

Support for the base mainboard was added with this commit, and compatibility with the hardware should only improve with time, as it is officially adopted for further deployments of Ralink RT5350 "router on a chip" such as this one.

Extra safety before flashing firmware from a completely different codebase would suggest first gaining access to the "Das U-Boot" bootloader serial console (and before that, the Linux getty login which appears running in the standard firmware), by opening the device as illustrated here, and connecting a TTL <-> 5V level converting serial cable to the appropriate pins. One suitable adapter should be for instance the very common, USB-ready CP2102 module, or clones.

[...continues...]

Cool tricks:

Access through SSH:

  • SSH client for various Windows versions: try PuTTY;
  • Konqueror "FISH" sshfs -lookalike access: just use fish://root@10.10.10.254/ address in the address bar;
  • Automatic, incremental backup (Apple "Time Capsule" -alike functionality) via Back In Time, relying on the rsync protocol to reduce network traffic, SSH for data encryption during the transfer, and ext2 hard-links (as opposed to the cruder VFAT capabilities) to save disk space by only storing changes.

    "Back In Time" and rsync in particular would also work, with the stock firmware and through the SAMBA interface, making the exported VFAT partition accessible on Linux via a CIFS mountpoint. This introduces however extra overhead.
Non-interactive, safe SSH access may be configured with public key authentication.

Non-interactive CIFS access from a Linux system to the default /dev/sda1 partition made available through the SMB daemon may be set up with the "/etc/fstab" line:

//10.10.10.254/WiFiDisk1_Volume1/  /mnt/M2M_Backup  cifs  credentials=/home/[USERNAME]/.smbcredentials,users,iocharset=utf8,sec=ntlm,noauto 0 0

... which points to the /home/[USERNAME]/.smbcredentials file (with Samba crentials in clear text!):
username=admin
password=[password chosen through the unit HTTP interface]

Package recompilation with enhanced CPU support:

Even without switching to a fully custom firmware via i.e. BuildRoot above, some critical Debian packages may easily be recompiled on the unit itself with optimization options better geared to the available hardware. Options:

-O3 -march=24kec -mdsp -mips32r2

... show some speedup.

It is sufficient to include the appropriate APT source line in /etc/apt/sources.list:
[...]
deb-src http://archive.debian.org/debian-archive/debian/ lenny main contrib non-free
[...]

... getting sources (and build dependencies) via:

apt-get source [packagename]

The package compilation flags may be changed within its debian/rules file, and a customized version prepared via:

dpkg-buildpackage -b

therefore installing the resulting pacakgename.deb via:

dpkg -i packagename.deb

...as usual. Since the "Lenny" distribution suggested above is in "Archived" status, there will not be later package revisions from the central repository to overcome local preferences.

Alternatively, the more complete apt-build solution may also be used.

Even with these optimization, the choking point in network backups appears to be the SSH server. The embedded CPU is just not powerful enough to handle on-the-fly strong encryption at the speed otherwise supported by the WiFi network, or the local hard-disk.
Using "Back in Time" CLI interface shows:
$ backintime --benchmark-cipher 20
Back In Time
Version: 1.0.34

Back In Time comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; type `backintime --license' for details.

create random data file
20+0 records in
20+0 records out
20971520 bytes (21 MB) copied, 1.61118 s, 13.0 MB/s

  • 3des-cbc: 20MB 585.1KB/s   00:35 
                     20MB 640.0KB/s   00:32 
  • aes128-cbc: 20MB   1.1MB/s   00:19   
                         20MB   1.1MB/s   00:18
  • aes256-cbc: 20MB   1.1MB/s   00:18   
                         20MB   1.1MB/s   00:19
  • blowfish-cbc: 20MB   1.1MB/s   00:18
                           20MB   1.1MB/s   00:18
... while the plain, unencrypted rsync protocol could be used by launching the utility in daemon mode with:
$ rsync --daemon --no-detach --port=2000 -vvv --config=rsyncd.conf

and benchmarked from the client with:
  • Highest compression, no SSH:
    $ time rsync -vvv -az --compress-level=9 /tmp/re rsync://m2m:2000/pub
    sent 20,983,554 bytes  received 34 bytes  1,678,687.04 bytes/sec
    total size is 20,971,520  speedup is 1.00
    [sender] _exit_cleanup(code=0, file=main.c, line=1183): about to call exit(0)

    real    0m11.875s
  • No compression, no SSH:
    $ time rsync -vvv -a /tmp/re rsync://m2m:2000/pub
    sent 20,976,730 bytes  received 34 bytes  1,824,066.43 bytes/sec
    total size is 20,971,520  speedup is 1.00
    [sender] _exit_cleanup(code=0, file=main.c, line=1183): about to call exit(0)

    real    0m11.107s
  • No compression, SSH (twice as slow!):
    $ time rsync -vvv -e ssh /tmp/re m2m:/tmp/testrsync
    sent 20,976,707 bytes  received 437 bytes  975,681.12 bytes/sec
    total size is 20,971,520  speedup is 1.00
    [sender] _exit_cleanup(code=0, file=main.c, line=1183): about to call exit(0)

    real    0m21.642s
[continues...]

22 comments:

  1. What a faschinating write down.

    I bought this device by Chance two saturdays ago and have since then been looking for a way to open it up and "hack" it.

    I also saw the same enclosing somewhere online without a disk and there it was mentioned that once you build in a disk and close it, you cannot open it again without damage.
    So i was afraid i might never see and debug its UART-Interface without damaging it.

    Your Blog Post gives me the hope that i might have fun tinkering with this nice litte Gadget.

    Would you eventually help me if i had questions when trying to build the chroot stuff and using apt-get to install and run my favourite Debian CLI apps on it?

    Did you actually work with the intenso Team that designed and implemented it or are you just a versatile binwalk-Soc-Firmware-Analyst-or-engineer?

    ReplyDelete
  2. Thanks for the comment; the writeup is unfortunately still rather messy.

    I've only played a bit with the device; I haven't physically opened it yet, and can't comment on how hard to put it back together may be. I may proceed to do that in order to physically connect to the serial port, and really get U-Boot prompt menu for debugging when trying a new kernel.

    On the software side things are a bit scattered around, and you should be careful not to mess up with basic functionality. However it can be fun to tinker, and the backdoor left by the company should really be closed. Keep in mind that Lenny is a retired Debian version, not receiving securty updates any more, while a more up-to-date kernel would allow to use a more recent, properly maintained release.

    I can try to help if you have specific questions but I've only tried to understand a little how the device works on my own, as a hobby. I can't offer any guarantee things would work the same way for others too. But it can be instructive; have fun!

    ReplyDelete
  3. Wow... This is fantastic work. I have to try it out myself ... actually all that I wanted to do seems possible now. Bravo ;-)

    ReplyDelete
  4. Thanks, just some tinkering and looking around. Somebody with real OpenWRT experience could probably help a lot.
    I'm waiting for a TTL-to-serial levels converter over USB to arrive, then I'll try to open the case, and connect to the serial port which should be there: it would allow to follow the stock firmware boot process, and actually upgrade the kernel with some degree of fail-safe.

    If you do carry on with your own tests, please do let us know how they go!

    ReplyDelete
    Replies
    1. Hijo, .... looking forward to read about your progress with the fail-safe kernel upgrade . And as soon I manage to replicate what you did (which could take some time :-P), I will certainly share whatever i find out on the way.

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Good trick!
      There is indeed a CRC check, be careful with new firmwares creation (see notes). However is pretty easy to get into a hash collision scenario, the payload is big with respect to small changes of few bytes.

      When I reflash, I typically have to do a couple of CRC passes or so, to find a "stable" CRC that can be included inside the file for which it is itself computed, and still not be sensitive to the variation (think of it as if it were a sort of lossy compression scheme...). It also means however, that a slightly corrupted firmware also has high changes not to trigger the CRC validation, thus bricking the device.

      Have fun, happy hacking!

      Delete
  6. Hi, nice findings!

    I found the telnet daemon too, but I didn't know the root password... What I did, was to export the configuration and check it with a hex editor. I found the shadow file inside, so I copy/pasted the MD5 of the admin password in place of that of the root password.

    When I reimported the configuration I thought I would brick the device or that it would not work because of a CRC check, but it worked...

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. I suppose one way to conceive checksumming is along lossy compression. Think of it like this: you could double check that a payload is not corrupted, by uploading it twice and asking both copies to be identical, before flashing one.

    Then you could compress the second copy in a non-lossy way: it would occupy less space, but still give you full redundancy.

    Then you could compress it in a lossy way: it would occupy arbitrarily less space, down to the handful of bytes used for the CRC string, and give correspondingly less and less redundancy. An extreme case would be using a single bit for validation, 0 or 1, corresponding to have an even or odd total number of bits set to 1 in the payload: in such example, two completely different payloads with the same bit parity would both pass the validation test, or in other terms generate a hash collision.

    The CRC in use in not so crude, but not too advanced either. It has few bits alltogether to keep track of a relatively big payload. If you change it only a little bit, you can "get lucky". Or if you proceed with the checksum calculation a few times until stability as in the quick notes above, what you're actually doing is to crudely deploy dynamical systems theory to identify a fixed point, see for instance the quick notes here: http://www2.maths.ox.ac.uk/chebfun/examples/veccalc/html/DynamicalSystems.shtml

    This should be a pretty general way to put the problem, in practice the solution is so easy to find because of the crude implementation adopted as hash function.

    ReplyDelete
  9. Thanks for the info! So I was lucky :D
    I don't have too much time to dedicate to this, but I would like to input the modified package to the checksum function.

    Please continue to work on it. It would be nice to have the box with OpenWrt running!

    ReplyDelete
  10. The checksum function in use is a combination of sed handling case etc., and the cksum UNIX utility, see above. In practice, you can compute it from a shell via:

    $ sed '1,3d' PAYLOAD |cksum|sed -e 's/ /Z/' -e 's/ /Z/'|cut -dZ -f1

    I am still waiting for a USB TTL-to-serial interface to arrive, I'd like to really monitor the boot process. Have you ever tried to open the device case, can you comment perhaps on possible screws location / other interlock mechanisms?

    ReplyDelete
  11. Yes I opened it because I bought the cheap 320GB version and I tried a 1TB hard drive on it. It worked!

    It's quite challenging to open it. It's easy if you have one of that plastic thing used to open the old mobile phones, because the case has no screws, only plastic pins. To open it with generic tools you need a couple of useless plastic cards (don't use credit cards or useful cards) and a small knife with a sharp blade:

    1. Put the entire knife blade in the long side opening, lift the upper part a little and insert the plastic card. Do the same on the other side.
    2. On one side, insert the plastic card deeper on the upper part and move it slowly until you hear a click, that means you disengaged the plastic pin.
    3. Continue until you disengage all plastic pins (3 on each long side and 2 on each short side).

    It's difficult, but I managed to do it without external damage and only 1 internal pin broken, fixed later with some loctite.

    The inside reveal a decoupled hard drive, with a rubber envelope on each screw (nice). Below the hard drive there is the battery on the back and the board on the front. The board is insulated by a sticky sheet of black plastic. If you remove the plastic sheet, you find the 3 screws that must be unscrewed to remove the board.

    Unluckily there is no presoldered pin for a serial interface so I think that you must use your soldering skills...

    If you have any question let me know!

    ReplyDelete
  12. I want to add, to anyone who wants to try to change the hard drive, that NTFS formatted disks are automatically detected, courtesy of the tntfs.ko module (Tuxera NTFS driver).

    ReplyDelete
    Replies
    1. Thanks for the tips on opening the case!

      Today I've received the cheap CP2102 USB-to-TTL serial adapter I was waiting for (about 2 Eur via Amazon), and could indeed open the device, find the appropriate pads on the circuit board, solder some pins and gain serial access.

      I'll put down some more notes when time allows to play a bit more. In practice, I can confirm there is a UART interface, easy to access through the 4 pads close to the battery, where +Vcc 3.3 Vdc is the square one, to its left lies Rxc, then Txc, then Gnd.

      Here the booting process dumps all its debug informations, and at the end a standard "getty" is waiting for log in. The default root account and password works there too.

      Happy hacking!

      Delete
  13. This comment has been removed by the author.

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hi,

    I have Verbatim Mediashare device. It has one USB and one SDCARD slot. It has a web interface and Android interface to manage content via Wifi.
    I have connected a usb splitter. When I connect only one Flashdisk it works fine (like without splitter).
    When I connect two flash drives I see two drives but I see the last attached drive two times.

    I logged into with telnet as root and have checked the mounting.
    It looks like the following

    /dev/sda1 /data/UsbDisk2/Volume1
    /dev/sdb1 /data/USbDisk2/Volume1

    I have remove the last mount and I have remounted a last one like:
    /dev/sdb1 /data/UsbDisk3/Volume1

    From command like the both mounting works well. I can copy from the one flash drive to the other the files with bash.

    But the GUI does not lising well the two devices.

    I have cheked the device /www folder and I have finded a index.js (and more).

    for the copy I found the following snippet:

    function qCopy(url,target,ov){
    var head = {
    "Destination":iHost + encodeURL(target),
    "Depth":1
    };
    ov || (head.Overwrite = "F");
    qExplor.flag = true;
    $.Ajax.load({
    ovTime:0,
    url: encodeURL(url),
    method:"COPY",
    dataType:"text",
    onCensor:"xx",
    callBack:function(){

    When I copy one file, the server communication is the following:

    Request URL:http://10.10.10.254/data/UsbDisk3/Volume1/img_4121.jpg
    Request Method:COPY
    Status Code:201 Created
    Remote Address:10.10.10.254:80
    Response Headers
    view source
    Content-Length:0
    Date:Sat, 31 Dec 2011 16:24:49 GMT
    Server:lighttpd/1.4.28-devel-78M
    Request Headers
    view source
    Accept:*/*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:hu,en-US;q=0.8,en;q=0.6,de;q=0.4
    Connection:keep-alive
    Content-Type:application/x-www-form-urlencoded
    Cookie:Language=us; SESSID=SPf9Zx78rgWMMDU7AuWS6CwwpDeSftAYhG76d6dEd4iWH
    Depth:1
    Destination:http://10.10.10.254/data/UsbDisk3/Volume1/dcim/img_4121.jpg
    Host:10.10.10.254
    Method:COPY /data/UsbDisk3/Volume1/img_4121.jpg HTTP/1.1
    Origin:http://10.10.10.254
    Overwrite:F
    Referer:http://10.10.10.254/
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36

    ReplyDelete
  16. for listing the drives I found:

    #SD USB oMain
    void function(H){
    var iStorage;
    function getStorage(){
    $.Ajax.getXML("/protocol.csp?fname=storage&opt=listen_disk&function=get",function(flg,v,hq){

    if(flg>0){
    var storage = {
    _text:hq.responseText
    },csd,cusb;
    var items = $.xjson(v,"item");
    storage._items = items;
    for(var i = 0,n;i<items.length;i+=1){
    n = (items[i].type).toLowerCase().replace(/\s/g,"");
    storage[n] = items[i];
    }
    if(iStorage && iStorage._text != storage._text){
    var isd = iStorage.sdcard || iStorage.sdcard1 || iStorage.sdcard2 || iStorage.sdcard3,
    sd = storage.sdcard || storage.sdcard1 || storage.sdcard2 || storage.sdcard3;
    if(isd && sd){
    //两次请求数据都存在,比较两项属性,有差异,说明换卡了
    if(isd.name != sd.name || isd.type != sd.type ){
    csd = 2;
    Msg.prompt(Language.getHTMLValue("HotPlug_SDCard_in"));
    }
    }
    else if(isd){
    csd = -1;
    Msg.prompt(Language.getHTMLValue("HotPlug_SDCard_out"));
    }
    else if(sd){
    csd = 1;
    Msg.prompt(Language.getHTMLValue("HotPlug_SDCard_in"));
    }

    var iusbmemory = iStorage.usbdisk1 || iStorage.usbdisk2 || iStorage.usbdisk3,
    usbmemory = storage.usbdisk1 || storage.usbdisk2 || storage.usbdisk3;
    if(iusbmemory && usbmemory){
    //两次请求数据都存在,比较两项属性,有差异,说明换卡了
    if(iusbmemory.name != usbmemory.name || iusbmemory.type != usbmemory.type ){
    cusb = 2;
    Msg.prompt(Language.getHTMLValue("HotPlug_USBDevice_in"));
    }
    }
    else if(iusbmemory){
    cusb = -1;
    Msg.prompt(Language.getHTMLValue("HotPlug_USBDevice_out"));
    }
    else if(usbmemory){
    cusb = 1;
    Msg.prompt(Language.getHTMLValue("HotPlug_USBDevice_in"));
    }
    }
    iStorage = storage;
    if(csd || cusb){
    try{
    oMain.HotPlug.storageChange(iStorage,csd,cusb);
    }catch(e){}
    }
    }
    setTimeout(getStorage,5*1000);
    });
    }
    H.getStorage = getStorage;
    }(window.HotPlug = {});


    Request URL:http://10.10.10.254/protocol.csp?fname=storage&opt=listen_disk&function=get
    Request Method:GET
    Status Code:200 OK
    Remote Address:10.10.10.254:80
    Response Headers
    view source
    Cache-Control:no-cache
    Content-length:241
    Content-type:text/xml;charset=UTF-8
    Date:Mon, 10 Oct 2016 16:16:16 GMT
    Expires:0
    Pragma:no-cache
    Server:vshttpd
    Set-cookie:SESSID=SPf9Zx78rgWMMDU7AuWS6CwwpDeSftAYhG76d6dEd4iWH;
    Request Headers
    view source
    Accept:*/*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:hu,en-US;q=0.8,en;q=0.6,de;q=0.4
    Connection:keep-alive
    Cookie:Language=us; SESSID=SPf9Zx78rgWMMDU7AuWS6CwwpDeSftAYhG76d6dEd4iWH
    Host:10.10.10.254
    Referer:http://10.10.10.254/
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
    Query String Parameters
    view source
    view URL encoded
    fname:storage
    opt:listen_disk
    function:get

    payload:

    <root>
    <storage>
    <listen_disk>
    <item>
    <name>sda</name>
    <type>USBDisk1</type>
    <plugflag>1</plugflag>
    </item>
    <item>
    <name>sdb</name>
    <type>USBDisk1</type>
    <plugflag>1</plugflag>
    </item>
    <errno>0</errno>
    </listen_disk>
    </storage>
    </root>

    for both drives it is listing USBDisk1!!

    ReplyDelete
  17. And for the listing the content:

    Request URL:http://10.10.10.254/data/UsbDisk3/Volume1
    Request Method:PROPFIND
    Status Code:207 Multi-status
    Remote Address:10.10.10.254:80
    Response Headers
    view source
    Content-Length:3498
    Content-Type:text/xml; charset="utf-8"
    Date:Mon, 10 Oct 2016 16:17:58 GMT
    Server:lighttpd/1.4.28-devel-185:188M
    Request Headers
    view source
    Accept:*/*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:hu,en-US;q=0.8,en;q=0.6,de;q=0.4
    Connection:keep-alive
    Content-Type:text/xml; charset="utf-8"
    Cookie:Language=us; SESSID=SPf9Zx78rgWMMDU7AuWS6CwwpDeSftAYhG76d6dEd4iWH
    Depth:1
    Host:10.10.10.254
    Method:PROPFIND /data/UsbDisk3/Volume1 HTTP/1.1
    Origin:http://10.10.10.254
    Referer:http://10.10.10.254/apps/explorer/explorer.html
    User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36

    <?xml version="1.0" encoding="utf-8"?>
    <D:multistatus xmlns:D="DAV:" xmlns:ns0="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
    <D:response>
    <D:href>http://10.10.10.254/data/UsbDisk3/Volume1/</D:href>
    <D:propstat>
    <D:prop>
    <D:getcontentlength>16384</D:getcontentlength><D:getcontenttype>httpd/unix-directory</D:getcontenttype><D:getlastmodified ns0:dt="dateTime.rfc1123">Mon, 10 Oct 2016 18:17:58 GMT</D:getlastmodified><D:resourcetype><D:collection/></D:resourcetype><D:user>root</D:user></D:prop>
    <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
    </D:response>
    <D:response>
    <D:href>http://10.10.10.254/data/UsbDisk3/Volume1/ftptls%7e1.msu</D:href>
    <D:propstat>
    <D:prop>
    <D:getcontentlength>2314805</D:getcontentlength><D:getcontenttype>application/octet-stream</D:getcontenttype><D:getlastmodified ns0:dt="dateTime.rfc1123">Fri, 05 Aug 2016 17:55:32 GMT</D:getlastmodified><D:user>root</D:user></D:prop>
    <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
    </D:response>
    <D:response>
    <D:href>http://10.10.10.254/data/UsbDisk3/Volume1/vst%7e1</D:href>
    <D:propstat>
    <D:prop>
    <D:getcontentlength>32768</D:getcontentlength><D:getcontenttype>httpd/unix-directory</D:getcontenttype><D:getlastmodified ns0:dt="dateTime.rfc1123">Mon, 10 Oct 2016 17:40:36 GMT</D:getlastmodified><D:resourcetype><D:collection/></D:resourcetype><D:user>root</D:user></D:prop>
    <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
    </D:response>
    <D:response&gt
    ..

    On the device run: lighthttpd and vshttpd and more apps.

    My questions are:
    What kind of app replies that xmls? How the cgi works?
    Can I modify somewhere to get the proper drive informations in the xml accoring to the current mounting?
    I tried to modify one file in /www , but the whole /www is readonly. How can I modify it to rw?
    I did not finded a mounting point for /www.
    I has samba server support also. It is working. It shares the whole content of /data folder. When I try to http://10.10.10.254/data/UsbDisk3/Volume1/img_4121.jpg , I get it, but at sambe listing it does not list automaticaly the USBDisk3 folder. Or it is a different issue?

    ReplyDelete
  18. protocol.csp contains only:
    <%{%>

    <%}%>

    Whait is it , jsp?

    ReplyDelete
  19. Are there possibilities to use this device as a NAS drive? I bought one but I noticed that is not possible to write data over LAN to the device! Only over USB but I want to change the autorisations to Read/Write

    ReplyDelete