Synology NAS DS220j. Physical Security

Andrey Lovyannikov
7 min readFeb 3, 2021

Privacy and security are the main reasons why people choose self-hosted NAS over cloud-based solutions. This article is about Synology NAS DS220j security against attacks with physical access (e.g. as the result of supply chain attacks).

Note: This article was originally written in Feb 2021 and based on some DSM v6 image. Some information here can be outdated (especially if you’re on DSM 7).

General Info

Synology NAS DS220j is based on SoC Realtek RTD1296, 512 MB DDR4 and some eMMC storage.

There is no public datasheet for this SoC all over the Internet. But there is BPI-W2 on the same SoC and it has some source code in public.

I’ve checked boot process without device disassembly, so no photos of PCB or boot logs from UART.

TL;DR

Synology DS220j isn’t secure to attacker with physical access. On the earliest phase (on EL3, before running secure monitor) it loads 2nd bootloader from flash and runs it without any security related checks and operations (like decryption and signature checks).

Anyone can backdoor this NAS and there is no easy way to detect or prevent it: Synology neither provide you with firmware attestation tools nor ship an authentic flash image.

Gathering Info

Thankfully Synology NAS are Linux based and allow user to enable great number of services, including SSH. With SSH access we can easily analyze file system and external devices.

There were 2 interesting findings:

  1. /.syno folder, where we can see some U-Boot binary, updater and kernel image (see screen shoot below);
  2. dev/md0 device, wich contains our root filesystem.

Using strings from /.syno/patch/uboot_DS220j.bin I found 2 interesting boot logs (for RTD1295, but still):

  1. boot log of RTD1295 SoC
  2. WD My Cloud Home Boot Log

Also we can get burning image and some instructions for BPI-W2:

NOTE: you can download Synology NAS update image and grab the same uboot_DS220j.bin file from there.

Analyzing

Reconstructing Boot Flow

From logs above we get the next boot flow:

Legend:

  • blue — wasn’t dumped and hence analyzed;
  • green — was found and analyzed;
  • red — wasn’t used during DS200j boot;
  • yellow — out of scope, at least for this article.

Getting Firmwares

From the legend above you already know, that I was able to find only some bootloaders.

By grepping strings from boot logs I’ve found that almost all of them are in /.syno/patch/uboot_DS220j.bin. I was lazy to analyze flashing process (where it was possible to find how to dissect this file) and decided to extract all firmwares from binary image only (because why not: it’s neither encrypted nor compressed).

Some time later I got device tree, FSBL, bootcode (U-boot 32), 2nd bootloader (U-Boot 64) and audio/video firmware (A/V firmware). If you have the same uboot_DS220j.bin with MD5: FFB76FF54B1EBC147A7BC948528B904D you can use the commands below:

We can see that almost all parts are not page aligned, this means that either we work with custom binary format or they have some headers at the beginning (or both).

Now we have binary images and we need their RAM addresses to load them in IDA Pro. We can get them from boot logs and U-Boot’s envs. You can see them in the table below.

Now let’s start from the early beginning.

FSBL

On this stage bootloader takes config from SRAM or eFUSE, initialize different things (like AES key for further FW decryption, calculated from value in eFUSE). After that it loads “firmwares” to RAM (from flash or just copies it from another RAM address). Those “firmwares” can be one of the following type:

As you can see “firmware” can be of almost any type, from BOOTCODE, BL31, UBOOT and TEE to kernel images, filesystems, hypervisor and even some RSA keys.

All these “firmwares” can be loaded in almost secure way (with AES-128-ECB decryption and signature check), keys are stored in eFUSEs. Secure loading happens if special flag is set in eFUSEs. No version checking was noticed (thus no anti-rollback).

During DS220j boot FSLB loads RSA keys (both FW and TEE) from boot drive to known SRAM region. When RSA keys were successfully loaded, it loads TEE, BL31 and BOOTCODE “firmwares”. On success, control flow is transferred to bootcode (U-Boot 32).

Bootcode (U-Boot 32)

Bootcode is U-boot 2012.07-g9f8956c. At the beginning it configures VBAR table, switches execution mode to 32 bit and runs common to U-Boot stuff. U-boot environments are shown below.

bootargs= 
bootcmd=run syno_bootargs;run rtk_spi_boot;env set bootcmd bootr;bootr
bootdelay=0
baudrate=115200
ethaddr=00:10:20:30:40:50
ipaddr=192.168.100.1
serverip=192.168.100.2
gatewayip=192.168.100.254
netmask=255.255.255.0
rescue_vmlinux=sata.uImage
rescue_dtb=rescue.sata.dtb
rescue_rootfs=rescue.root.sata.cpio.gz_pad.img
rescue_audio=bluecore.audio
bootcode2ndtmp_loadaddr=0x01500000
bootcode2nd_loadaddr=0x00021000
kernel_loadaddr=0x03000000
rootfs_loadaddr=0x02200000
mtd_part=mtdparts=rtk_nand:
fdt_loadaddr=0x01F00000
syno_boot_dev=/dev/md0
syno_hw_version=DS220j
syno_hdd_powerup_seq=2
syno_net_if_num=1
syno_extra_args=syno_spinup_group=1,1 syno_spinup_group_delay=5
ata_hdd_detect=syno_hdd_detect=4,5
ata_hdd_enable=syno_hdd_enable=85,86
rtk_spi_boot=rtkspi read 0x00100000 0x0b000000 0x00350000;rtkspi read 0x00450000 0x02200000 0x00427000;if syno_checksum 0x0b000000 && syno_checksum 0x02200000;then echo Image OK;rtkspi read 0x00100040 0x0b000000 0x0034ffc0;mw.l 0x02200000 0x0 0x109C00;rtkspi read 0x00450040 0x02200000 0x00426fc0;else echo Image Corrupted, Load Backup Image...;rtkspi read 0x00887040 0x0b000000 0x0034ffc0;mw.l 0x02200000 0x0 0x109C00;rtkspi read 0x00bd7040 0x02200000 0x00426fc0;fi;lzmadec 0x0b000000 0x03000000 0x0034ffc0;rtkspi read 0x000c0000 0x0b000000 0x00040000;lzmadec 0x0b000000 0x01b00000 0x00040000;rtkspi read 0x00000000 0x01f00000 0x00010000;
syno_vbus_setting=syno_usb_vbus_gpio=23@xhci-hcd.2.auto@0,22@xhci-hcd.5.auto@0
syno_castrated_xhc_setting=
syno_phys_memsize=
syno_ahci_remap=
syno_bootargs=env set bootargs ip=off console=ttyS0,115200 root=$syno_boot_dev rw $ata_hdd_detect $ata_hdd_enable $syno_usb_vbus_setting $syno_castrated_xhc_setting $syno_extra_args $syno_vbus_setting syno_hw_version=$syno_hw_version hd_power_on_seq=$syno_hdd_powerup_seq ihd_num=$syno_hdd_powerup_seq netif_num=$syno_net_if_num swiotlb=1 $syno_phys_memsize $syno_ahci_remap audio_version=1012363 syno_fw_version=M.811

Summing up, it configures bootargs, executes rtk_spi_boot and runs bootr command to start next boot stage.

rtk_spi_boot

rtk_spi_boot command is quite interesting:

  • it reads 2 binary blobs (compressed kernel and rootfs) from SPI flash to RAM;
  • these blobs are checked with syno_checksum (this check will be passed if blob has valid magic and CRC32 for header and data);
  • if any of the checks fail, two backup binary blobs are read from another location on SPI flash (without any further checks);
  • if both checks succeeded, those two blobs are reread from SPI flash, missing header (hi, TOCTOU);
  • decompress kernel blob;
  • read 3rd blob (compressed audio FW) from SPI flash;
  • decompress audio FW;
  • read device tree.

Here is annotated version of rtk_spi_boot command in the listing below.

bootr

This command is executed after rtk_spi_boot. Without arguments bootr:

  1. Try to run audio/video firmware (it’s started on another core, they communicate via some shared memory region).
  2. On normal boot it prepares some dynamic parameters to kernel command line and runs U-Boot command b2ndbc (see below).
    - If execution flow returns from b2ndbc, U-Boot 32 moves to rescue mode with USB boot and repeat attempt.
    - If execution flow returns from b2ndbc one more time, it jumps to the step 3 (below) with RESCUE_MODE.
  3. On any other boot it goes to RESCUE_MODE and finally drops to interactive U-Boot shell.

b2ndbc

This command has four stages:

  1. try to import U-Boot environments from address 0x10000000;
  2. read 2nd bootcode (U-Boot 64) and BL31 from SPI flash without any checks;
  3. set mark about “gold boot” and run second bootcode (U-Boot 64) if “gold boot” wasn’t set;
  4. if “gold boot” mark was set, just return.

Bellow you can see the code of the second stage.

We can see that there are blob sizes at the beginning of the SPI flash (address 0). Changing these sizes makes it possible to control BL31 and U-Boot 64 read addresses, and hence force U-Boot 32 read our code and execute it on EL3 (in NS world, but there is still no restrictions to switch back to Secure world).

U-Boot 64

Ok, we can run any code but it was quite surprising for me to see one more U-Boot. So I decided to analyze it and check when actually BL31 is executed.

At the early beginning U-Boot 64 configures VBAR and some other system registers, does common U-Boot staff with environments below and… boots Linux (bootr runs booti which prepares FDT and kernel image then jumps to the kernel entry point)!

bootcmd=bootr
bootdelay=0
baudrate=115200
kernel_loadaddr=0x03000000
fdt_loadaddr=0x01F00000
fdt_high=0xffffffffffffffff
rootfs_loadaddr=0x02200000
mtd_part=mtdparts=rtk_nand:

So, yes, we don’t even have secure storage on this NAS =(.

NOTE: In BPI-W2 source code it’s possible to jump to BL31 (kernel entry point and FDT addresses are passed as arguments to BL31 entry point) from this point. But this code is completely removed from firmware.

P.S.

Do you remember Audio/Video firmware?

It’s binary blob with about 600KB of MIPS BE code and some strings, this code executes on another core (yep, it’s hard to execute ARM and MIPS on the same core =)). MIPS core has access to UART (some strings in one of the boot logs are from this firmware), video and audio ports, can at least partially access DRAM and no one knows what else (I really hope that OEMs know).

So this firmware looks quite interesting even if we forget about the insecure way it is loaded (read from SPI flash, LZMA decompress and start execution). I think the most interesting directions are:

  • can it access devices and memory which belongs to ARM secure world?
  • does it work in low power mode?
  • is all video and audio data goes through this firmware?

I’ll be glad to hear from you if you know/find something interesting about this firmware.

--

--

Andrey Lovyannikov

There are three universal gates: NAND, NOR and Intel 8051 microcontroller