TerraStation NAS 5400D Firmware Customization

Overview

I have purchased second-hand Buffalo Terrastation NAS 5400D last year. It costed me some hundred bucks but it is still far cheaper than the brand new one. I just configured it for a home nas and I was really happy with its performance. However, the firmware is locked and I do not able to install any custom application or I was too busy at that time to dig into it. Now is the time. While working at home to isolate from nCOVID-19, I have an opportunity to play with it.

That is interesting that there is a new firmware from Buffalo to upgrade too so I can take this opportunity to upgrade new firmware and customize it. The new firmware is

VERSION=4.06-0.02
KERNEL=2020/02/04 18:07:14
INITRD=2020/02/04 18:39:47
ROOTFS=2020/02/04 18:39:38
NO_FILE_BOOT = 1
FILE_KERNEL = uImage.img
FILE_INITRD = initrd.img
FILE_ROOTFS = hddrootfs.img 

That firmware is released for TS5000 and TS4000 series. So let play with it. Here are list of stuffs:

  1. Upgrade new firmware -> just easy stuff, extract it and run the TSUpdate.exe tool which will download firmware to target and update.
  2. Enable SSH service to login
  3. Install aMule tool

Customizing firmware

Hardware configuration:

  • CPU: Intel Atom D2550 @ 1.86 GHz, 2 cores 4 threads (support hyperthreading). The GPU is PowerVR. Codename is cedartrail. More information about CPU is cedartrail CPU. Intel also released the Yocto SDK
  • RAM: DDR3 2GB, 64bit, 1066MHz
  • 4 bays HDD

The stock firmeware is linux based and using Grub 1.9, linux kernel 3.10.69-atom_usi.

The root password is randomly generated so we need a work-around solution. First, we need to extract the firmware and get needed stuff. The firmware is password protected, however, the information is leaked here.

Unzip the firmware file and locate the directory containing LSUpdater.exe or TSUpdater.exe locate the correct initrd.img and uImage.img for your device (usually there is only one, if there are more they typically include the corresponding device model in the name).
These files are actually password protected zip files, the password will be one of the following:

1NIf_2yUOlRDpYZUVNqboRpMBoZwT4PzoUvOPUp6l
aAhvlM1Yp7_2VSm6BhgkmTOrCN1JyE0C5Q6cB3oBB
YvSInIQopeipx66t_DCdfEvfP47qeVPhNhAuSYmA4
IeY8omJwGlGkIbJm2FH_MV4fLsXE8ieu0gNYwE6Ty

Enable root shell on serial port

The content of firmware update package includes:.

.
└── ts5000_4000-v406
├── img
│ └── firm_confirm.png
├── TS5000_4000-v406
│ ├── hddrootfs.img
│ ├── initrd.img
│ ├── linkstation_version.ini
│ ├── linkstation_version.txt
│ ├── TSUpdater.exe
│ ├── TSUpdater.ini
│ └── uImage.img
└── TS5000_4000-v4.06.html

Using zcat to decompress the initrd.img to enable the root console without prompt us the password:

$ cd ts5000_4000-v406/TS5000_4000-v406
$ unzip initrd.img
//using password: YvSInIQopeipx66t_DCdfEvfP47qeVPhNhAuSYmA4 to unzip
password incorrect--reenter:
inflating: initrd-atom_d510.buffalo
inflating: initrd-atom_usi.buffalo
$ zcat initrd-atom_usi.buffalo > initrd-atom_usi.buffalo.uncompress
$ mkdir initrd
$ sudo mount -o loop initrd-atom_usi.buffalo.uncompress ./initrd

We need to update initrd /usr/local/bin/buffalo_consoled.sh. We want to force the firmware always open the shell to start root console without asking password

diff --git a/initrd/usr/local/bin/buffalo_consoled.sh b/initrd/usr/local/bin/buffalo_consoled.sh
index 8e9418e..32127a0 100755
--- a/initrd/usr/local/bin/buffalo_consoled.sh
+++ b/initrd/usr/local/bin/buffalo_consoled.sh
@@ -49,9 +49,9 @@ Daemon()
        while [ 1 ] 
        do
-               [ "${ENV_FORCE}" != "yes" ] && CheckRequirement
+               #[ "${ENV_FORCE}" != "yes" ] && CheckRequirement
                LogPrintOut "Starting getty on ttyS0."
-               /sbin/getty -L ttyS0 115200 vt100 &
+               /sbin/getty -n -l /bin/bash -L ttyS0 115200 vt100 &
                PID_CHILD=$!
                wait ${PID_CHILD}
        done

So we skip the CheckRequirement and execute getty without asking password and execute bash immediately! DONE, just finish and repack the zip file then execute update.

$ sudo umount ./initrd
$ gzip -9 initrd-atom_usi.buffalo.uncompress
$ mv initrd-atom_usi.buffalo.uncompress.gz initrd-atom_usi.buffalo
$ rm -f initrd.img
$ 
$ zip -e initrd.img initrd-atom_usi.buffalo initrd-atom_d510.buffalo
Enter password: 
Verify password: 
  adding: initrd-atom_usi.buffalo (deflated 1%)
  adding: initrd-atom_d510.buffalo (deflated 1%)

There you go, flashing new firmware to the NAS and we will have root console at com port. The com port baudrate is 115200n8

Enable SSH

The SSH service is enabled if you enable sftp but the you will not able to login via ssh because Buffalo change the code base to drop connection! We need to use another sshd server. There is many ways to work-around this: using a pre-built ssh from your PC using chroot to execute it or rebuilt the sshd by your self.I build a new sshd and copy it to NAS. So, we need to build a toolchain. The toolchain used by Buffalo is:

  • GCC 4.4.6
  • glibc 2.14.1
  • crosstool-NG 1.13.2 – 01122012
bash-3.2# /lib/libc.so.6
GNU C Library stable release version 2.14.1, by Roland McGrath et al.
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.6.
Compiled on a Linux 2.6.39 system on 2012-01-13.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

Here you go, I use docker ubuntu12.04 and crosstool-ng 1.20 to build the toolchain. Here is the configuration

$ ct-ng menuconfig

Select glibc 2.14.1

We select gcc version 4.4.6

Enable C/C++

Select companion libraries:

  • GMP 4.3.1
  • MPFR 2.4.2
  • PPL 0.10.2
  • CLooG 0.15.11
  • libelf 0.8.13

We must enable Check the companion libraries builds so that ct-ng will try to run library checking for us. Other combinations may fail as I have tried and come with this configuration.

Optional: compile other tools and libraries but you can skip it.

About 15 minutes to run and compile the toolchain on my machine (it is quite strong with 64GB RAM + Ryzen 3 3800x) but yours maybe faster or slower.Here is my docker file

# NOTE: This docker image must be created with selinux disabled:
#
# sudo setenforce Permissive
# docker build -t yoctobuild/precise:2 -f Dockerfile.precise .
# sudo setenforce Enforcing
#
# Additionally, for non-root podman images, the fuse package
# must be held.


FROM ubuntu:precise
MAINTAINER Quan Cao <caoducquan@gmail.com>
ENV DEBIAN_FRONTEND noninteractive
WORKDIR /tmp


# Need i386 arch and update repos
RUN apt-get update -qq && \
apt-get upgrade -y -qq


# Need default shell to be bash
ENV LANGUAGE en_US.UTF-8
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8


RUN ln -sf /bin/bash /bin/sh


RUN apt-get -qq update \
&& apt-get -qq install locales apt-utils python-software-properties \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y locales \
&& locale-gen en_US.UTF-8 && dpkg-reconfigure locales && /usr/sbin/update-locale LANG=en_US.UTF-8 \
&& apt-get install -y -qq \
binutils \
dos2unix \
file \
libxml2-utils \
m4 \
make \
rsync \
zip \
libssl-dev \
gawk wget git-core diffstat unzip texinfo gcc-multilib \
build-essential chrpath socat cpio python python3 \
xz-utils debianutils iputils-ping libsdl1.2-dev xterm autoconf libtool automake


# i386
RUN apt-get install -y -qq \
libc6:i386 \
libstdc++6:i386 \
zlib1g:i386 \
build-essential \
perl


RUN apt-get install -y -qq bison flex libtool libncurses-dev curl wget gperf libcrypto++-dev


RUN useradd -ms /bin/bash yoctobuild
USER yoctobuild
WORKDIR /home/yoctobuild

Then you can have toolchain to compile openssh. Just compile and put it to NAS at /usr/local/sbin/sshd.strict and update the /etc/init.d/sshd.sh

SSHD_EXT=/usr/local/sbin/sshd.strict

sshd_stop()
{
        killall sshd
        killall sshd.strict //added
}
sshd_start()
{
.....
        
        ${SSHD_EXT} -f /etc/sshd_config.nopam
}

Install aMule

$ cd aMule-2.3.2
$ mkdir build.noguid
$ cd build.noguid
$ ../configure --enable-amule-daemon --enable-amulecmd --enable-webserver --disable-amule-gui --disable-monolithic --prefix=/
$ make -j8
$ 
$ ldd src/amuled
        linux-vdso.so.1 (0x00007ffc001ff000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007efbfecee000)
        libcrypto++.so.6 => /usr/lib/x86_64-linux-gnu/libcrypto++.so.6 (0x00007efbfe772000)
        libwx_baseu_net-3.0.so.0 => /usr/lib/x86_64-linux-gnu/libwx_baseu_net-3.0.so.0 (0x00007efbfe52e000)
        libwx_baseu-3.0.so.0 => /usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0 (0x00007efbfe09f000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007efbfdd16000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efbfd978000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007efbfd760000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007efbfd541000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efbfd150000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007efbfcf4c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007efbff4d7000)
 
$ ldd src/webserver/src/amuleweb
        linux-vdso.so.1 (0x00007ffc001ff000)
        libwx_baseu_net-3.0.so.0 => /usr/lib/x86_64-linux-gnu/libwx_baseu_net-3.0.so.0 (0x00007efbfefa7000)
        libwx_baseu-3.0.so.0 => /usr/lib/x86_64-linux-gnu/libwx_baseu-3.0.so.0 (0x00007efbfeb18000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007efbfe8fb000)
        libpng16.so.16 => /usr/lib/x86_64-linux-gnu/libpng16.so.16 (0x00007efbfe6c9000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007efbfe340000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efbfdfa2000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007efbfdd8a000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007efbfdb6b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efbfd77a000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007efbfd576000)
        /lib64/ld-linux-x86-64.so.2 (0x00007efbff4d7000)

$ tree aMule
aMule
├── bin
│   ├── amuled
│   ├── amuled.sh
│   ├── amuleweb
│   ├── amuleweb.sh
│   ├── bash
│   └── ls
├── dev
│   └── tty
├── home
│   ├── aMule
│   │   ├── amule.conf
│   │   ├── amule.conf.bak
│   │   ├── Incoming
│   │   └── Temp
│   └── amule.conf
├── lib
│   ├── ld-linux-x86-64.so.2
│   └── x86_64-linux-gnu
│       ├── libcrypto++.so.6
│       ├── libc.so.6
│       ├── libdl.so.2
│       ├── libgcc_s.so.1
│       ├── libm.so.6
│       ├── libpng16.so.16
│       ├── libpthread.so.0
│       ├── libstdc++.so.6
│       ├── libtinfo.so.5
│       ├── libwx_baseu-3.0.so.0
│       ├── libwx_baseu_net-3.0.so.0
│       └── libz.so.1
├── lib64 -> lib
├── root
├── share
│   ├── amule
│   │   └── webserver
│   ├── applications
│   ├── doc
│   │   └── amule
│   ├── locale
├── usr
│   └── local
│       └── share -> ../../share
└── var
    └── log
        ├── amuled.log
        └── amuleweb.log

Create a script to start amuled. Please note that, starting amuled will also start amuleweb for us.

bash-3.2# cat /etc/init.d/amuled.sh 
#!/bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin/:/usr/local/sbin/

CHROOTDIR=/mnt/array1/worknas/jail/aMule
CMD="/bin/amuled -c /home/aMule"
LOGFILE="var/log/amuled.log"
SRVNAME=amuled
KILLSIG=2

cd $CHROOTDIR

service_start()
{
    pid=`pidof ${SRVNAME}`
    echo "$pid is running for ${SRVNAME}"
    if [[ -n "$pid" ]]; then
        echo "Service is running! No need to start!"
        exit 0
    fi
    echo "Starting service ${SRVNAME} ..."
        cd $CHROOTDIR
        /usr/sbin/chroot ${CHROOTDIR} ${CMD}  > ${LOGFILE} 2>&1 &
        echo $! > /var/run/${SRVNAME}.pid
}

service_stop()
{
        #Sending SIGINT for gracefull stop!
    killall -${KILLSIG} ${SRVNAME}
}


case $1 in
start)  
        service_start
        ;;
stop)   
        service_stop
        ;;
restart)
        service_stop
        sleep 10
        service_start
        ;;
reload) 
        service_stop
        sleep 10
        service_start
        ;;
*)
        echo "Unknown argument"
        ;;

Then we need to execute this script when starting/shutdown NAS. For starting, hook the script to /etc/init.d/rcS

/etc/init.d/wol.sh start wol_ready_check

echo "****** START AMULE **************"
/bin/mount --bind /dev /mnt/array1/worknas/jail/aMule/dev
/etc/init.d/amuled.sh start
exec_sh consoled.sh

For shutdown, creating a symbolic link

$ cd /etc/rc.d/extensions.d/
$ ln -s ../../init.d/amuled.sh K20_amuled.sh

Here you go, the amule daemon will start/stop as your epxectation. Enjoy!

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.