D-Link DGS-1250 series

Th D-Link DGS-1250 series are Realtek RTL93xx based switches and consist of the following models

  • DGS-1250-28X : 24xGBit, 4x SFP+ 10GBit
  • DGS-1250-52X : 48xGBit, 4x SFP+ 10GBit
  • DGS-1250-28XMP : 24xGBit, 4x SFP+ 10GBit, 370W POE
  • DGS-1250-52XMP : 48xGBit, 4x SFP+ 10GBit, 370W POE

The devices have a Cisco style RJ45 serial console with 115200 baud and coding 8N1.

The U-Boot on these switches is quite hidden. The configuration is hardcoded into the bootloader and the U-boot environment partition is empty (all 0xff). The devices normally boot directly into the Switchlinux operating system. No sign of U-Boot is given. To open up the U-Boot proceed as follows.

  • Press “&” during boot to enter U-Boot
  • Delete silent mode flag with “setenv silent”
  • Store hardcoded environment into partiton with “saveenv”

From now on one will see the U-Boot logs during startup. To get the hardcoded U-Boot settings dump the loader partition.

# strings /dev/mtd0 | grep -i boot
...
U-Boot 2011.12.(3.3.0.31-13) (Oct 16 2019 - 17:11:31)
bootargs=console=ttyS0,115200 boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13
bootcmd=mtdparts default; ubi part fs; ubifsmount fs;ubifsload 0x87000000 uImage;bootm 0x87000000;
bootdelay=1
...

By spamming CTRL+C during the boot of the vendor firmware one gets root access to the embedded Linux distro.

Please wait for loading...
^C^C^C^C^C^C
#
#
# dmesg
Linux version 3.18.24-18 (mouan_liao@lanbuild02) (gcc version 4.9.4 (switchlinux-1.0-4) ) #3 Mon Mar 25 22:31:47 CST 2019
MIPS: machine is RTL9300
bootconsole [early0] enabled
CPU0 revision is: 00019555 (MIPS 34Kc)
[cpu0, rtl9300_auto_probe_memsize:274]: AUTO byte_size = 0x10000000 Byte
...

/mnt/flash # df
Filesystem           1K-blocks      Used Available Use% Mounted on
devtmpfs                118288         4    118284   0% /dev
tmpfs                   121632         4    121628   0% /dev/shm
tmpfs                   121632         0    121632   0% /tmp
/dev/ubi0_0              45220     24948     20272  55% /mnt/flash

The 64MB NOR flash chip has the following layout.

root@OpenWrt:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00100000 00004000 "u-boot"
mtd1: 00080000 00004000 "u-boot-env"
mtd2: 00080000 00004000 "u-boot-env2"
mtd3: 03e00000 00004000 "ubi"

Important! The vendor firmware uses a erasesize of 16K. That is different from OpenWrt 64K.

The last partition contains an UBIFS with the following structure.

+ uImage (initial Linux Linux-3.18.24-18 uImage)
+ switchfs
  + Image1 (encrypted image)
  + Image2 (encrypted image)
  + Config1 (ASCII configuration)
  + Config2 (ASCII configuration)
  + system
    + <several langague files>.lang
    + self-signed.crt
    + self-signed.pem
    + image.ini
    + sys_lang.cfg
    + cfg.ini
    + syslog

Access from within U-Boot

Get mtdparts default and set it as U-boot environment variable.

RTL9300# # mtdparts
mtdparts variable not set, see 'help mtdparts'
no partitions defined
defaults:
mtdids  : nor0=nor0
mtdparts: mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs)

RTL9300# # setenv mtdparts mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs)

Look around.

RTL9300# # mtdparts
device nor0 <nor0>, # parts = 4
 #: name                size            offset          mask_flags
 0: uboot               0x00100000      0x00000000      0
 1: env                 0x00080000      0x00100000      0
 2: sys                 0x00080000      0x00180000      0
 3: fs                  0x03e00000      0x00200000      0
active partition: nor0,0 - (uboot) 0x00100000 @ 0x00000000
defaults:
mtdids  : nor0=nor0
mtdparts: mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs)

RTL9300# # ubi part fs
Creating 1 MTD partitions on "nor0":
0x000000200000-0x000004000000 : "mtd=3"
UBI: attaching mtd1 to ubi0
UBI: physical eraseblock size:   16384 bytes (16 KiB)
UBI: logical eraseblock size:    16256 bytes
UBI: smallest flash I/O unit:    1
UBI: VID header offset:          64 (aligned 64)
UBI: data offset:                128
UBI: attached mtd1 to ubi0
UBI: MTD device name:            "mtd=3"
UBI: MTD device size:            62 MiB
UBI: number of good PEBs:        3968
UBI: number of bad PEBs:         0
UBI: max. allowed volumes:       94
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     1
UBI: available PEBs:             0
UBI: total number of reserved PEBs: 3968
UBI: number of PEBs reserved for bad PEB handling: 0
UBI: max/mean erase counter: 3/1

Access on foreign system

Dump /dev/mtd3 and copy the image to some linux machine. Mount it with

# load modules
modprobe -r block2mtd nandsim mtdram ubi ubifs 2>/dev/null
modprobe mtdram total_size=65536 erase_size=16
modprobe ubi
modprobe ubifs

# write image
dd if=dgs-1250-mtd3.dd of=/dev/mtd0

# attach image
ubiattach /dev/ubi_ctrl -m 0 -O 64

# mount
mkdir -p /mnt/ubifs
mount -t ubifs ubi0:fs /mnt/ubifs

Vendor

The switch runs a dual image configuration. The boot sequence basically runs as follows.

  • U-Boot starts
  • U-Boot mounts ubifs
  • U-Boot reads Linux kernel from file uImage inside ubifs
  • Linux starts
  • Linux mounts ubifs
  • Kernel calls loader binary
  • depending on current configuration first (Image1) or second firmware image (Image2) is loaded and decrypted
  • Inside the decrpyted firmware image there is a executable named “switch”
  • This is run and the switch comes alive

OpenWrt

During installation of OpenWrt the boot sequence is adapted so U-Boot can directly boot the kernel from the flash.

  • The first 12 MB of flash partition /dev/mtd3 are copied to memory address 0x84000000 (should be sufficient for kernels of any size)
  • uImage is started from address 0x84000000
bootcmd 'cp.l 0xb4200000 0x84000000 0x300000; bootm 0x84000000'

DGS-1250 firmware images are encrypted. They have a 512 byte header and multiple OpenSSL encrypted files.

$ binwalk 01_DGS-1250_Run_2_00_013_middle.had

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
512           0x200           OpenSSL encryption, salted, salt: 0x341AA3E4AB8CA371
5134656       0x4E5940        OpenSSL encryption, salted, salt: 0x5511393F1C318CB6
8739408       0x855A50        OpenSSL encryption, salted, salt: 0x378FCCAC861B6BE9
...

The key to such a firmware archive can be extracted with the following python script.

Click to display ⇲

Click to hide ⇱

#!/usr/bin/env python3
import struct
import sys

PASSPHRASE = "0123456789ABCDEFDGS-1250SmartManagedSwitch"
PASSPHRASE_BASE_INDEX = 16

def get_key_string(filepath: str) -> str:
    with open(filepath, "rb") as f:
        header = f.read(512)

    crypto_data = struct.unpack_from(">I", header, 20)[0]

    print(f"crypto_data (hex) : 0x{crypto_data:08X}")
    print(f"crypto_data (bin) : {crypto_data:032b}")

    shifted_left = (crypto_data << 0x14) & 0xFFFFFFFF
    print(f"nach << 0x14 (hex): 0x{shifted_left:08X}")

    startpos = (shifted_left >> 0x1c) & 0xF
    print(f"startpos          : {startpos}")

    index_in_passphrase = PASSPHRASE_BASE_INDEX + (1 - startpos)
    print(f"Passphrase-Index  : {index_in_passphrase}")

    key_string = PASSPHRASE[index_in_passphrase:]
    print(f"Key-String        : {key_string}")

    return key_string

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Verwendung: {sys.argv[0]} <datei>")
        sys.exit(1)

    get_key_string(sys.argv[1])

Inside the archive there are some fields around the encrypted data that describe the content (e.g. data length of each chunk). The length field (big endian) of the first chunk is at offset 12 (0xc) in the header. After carving out the salted files these can be decrypted with

openssl enc -d -aes-256-cbc -md md5 -pass pass:"<key_from_above>" -in salted.data -out decrypted.data

The loader binary and two sample images are stored at https://github.com/plappermaul/realtek-doc/tree/main/DGS-1250

Linux version 3.18.24-18 (mouan_liao@lanbuild02) (gcc version 4.9.4 (switchlinux-1.0-4) ) #3 Mon Mar 25 22:31:47 CST 2019
MIPS: machine is RTL9300
bootconsole [early0] enabled
CPU0 revision is: 00019555 (MIPS 34Kc)
[cpu0, rtl9300_auto_probe_memsize:274]: AUTO byte_size = 0x10000000 Byte
[cpu0, prom_memory_size_get:378]: Get total memory size by auto probe result
[cpu0, prom_memory_size_get:381]: Get dma size from kernel commnad line
[cpu0, prom_meminit:429]: DMA size=0xc00000(B)
[cpu0, prom_meminit:457]: mem zone0: Base=0x0, size=0xf400000(B)
Determined physical RAM map:
 memory: 0f400000 @ 00000000 (usable)
[cpu0, plat_remove_mem_parameter:248]: cmdline=console= boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13  console=ttyS0,115200 mem=256M rtk_dma_size=12M, 80436160, 804361de
[cpu0, plat_remove_mem_parameter:253]: cmdline=console= boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13  console=ttyS0,115200  rtk_dma_size=12M
[cpu0, plat_remove_mem_parameter:248]: cmdline=console= boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13  console=ttyS0,115200 mem=256M rtk_dma_size=12M, 80431f94, 80432012
[cpu0, plat_remove_mem_parameter:253]: cmdline=console= boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13  console=ttyS0,115200  rtk_dma_size=12M
Initrd not found or empty - disabling initrd
Zone ranges:
  Normal   [mem 0x00000000-0x0f3fffff]
  HighMem  empty
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x00000000-0x0f3fffff]
Initmem setup node 0 [mem 0x00000000-0x0f3fffff]
On node 0 totalpages: 62464
free_area_init_node: node 0, pgdat 80416940, node_mem_map 81000000
  Normal zone: 488 pages used for memmap
  Normal zone: 0 pages reserved
  Normal zone: 62464 pages, LIFO batch:15
Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes.
Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
pcpu-alloc: [0] 0
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 61976
Kernel command line: console= boardmodel=28 mtdparts=nor0:1M(uboot),512K(env),512K(sys),-(fs) loglevel=1 bootldr=3.3.0.31-13  console=ttyS0,115200  rtk_dma_size=12M
PID hash table entries: 1024 (order: 0, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Writing ErrCtl register=0003aef1
Readback ErrCtl register=0003aef1
Memory: 236580K/249856K available (2994K kernel code, 154K rwdata, 1032K rodata, 6688K init, 167K bss, 13276K reserved, 0K highmem)
NR_IRQS:128
console [ttyS0] enabled
bootconsole [early0] disabled
Calibrating delay loop... 530.43 BogoMIPS (lpj=265216)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
NET: Registered protocol family 16
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
TCP established hash table entries: 2048 (order: 1, 8192 bytes)
TCP bind hash table entries: 2048 (order: 3, 40960 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP: reno registered
UDP hash table entries: 256 (order: 1, 12288 bytes)
UDP-Lite hash table entries: 256 (order: 1, 12288 bytes)
NET: Registered protocol family 1
futex hash table entries: 256 (order: 0, 7168 bytes)
msgmni has been set to 462
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
start plist test
end plist test
Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
serial8250: ttyS0 at MMIO 0x0 (irq = 39, base_baud = 10764700) is a 16550A
serial8250: ttyS1 at MMIO 0x0 (irq = 38, base_baud = 10908700) is a 16550A
RTK_SPI_FLASH_MIO driver is bypassed
RTK_NORSFG3 driver is used
=================================================================
init_luna_nor_spi_map: flash map at 0xb4000000
SPI NOR driver probe...
MXIC/C2201A/MMIO32-4/ModeC
4 cmdlinepart partitions found on MTD device nor0
add SPI NOR partition
MTD partitions obtained from kernel command line
Creating 4 MTD partitions on "nor0":
0x000000000000-0x000000100000 : "uboot"
0x000000100000-0x000000180000 : "env"
0x000000180000-0x000000200000 : "sys"
0x000000200000-0x000004000000 : "fs"
=================================================================
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
rtk_gen1_hcd_cs_init: rtk_gen1_hcd_cs_init()!
rtk_gen1_hcd_cs_init: register rtk_gen1_ehci ok!
usb_phy_configure_process: usb_phy_configure_process()!
rtk_gen1-ehci rtk_gen1-ehci: Realtek On-Chip EHCI Host Controller
rtk_gen1-ehci rtk_gen1-ehci: new USB bus registered, assigned bus number 1
rtk_gen1-ehci rtk_gen1-ehci: irq 25, io mem 0x18021000
rtk_gen1-ehci rtk_gen1-ehci: USB 2.0 started, EHCI 1.00
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver usbtmc
usbcore: registered new interface driver usb-storage
TCP: cubic registered
NET: Registered protocol family 17
Freeing unused kernel memory: 6688K (80418000 - 80aa0000)
UBI: attaching mtd3 to ubi0
UBI: scanning is finished
UBI: attached mtd3 (name "fs", size 62 MiB) to ubi0
UBI: PEB size: 16384 bytes (16 KiB), LEB size: 16256 bytes
UBI: min./max. I/O unit sizes: 1/1, sub-page size 1
UBI: VID header offset: 64 (aligned 64), data offset: 128
UBI: good PEBs: 3968, bad PEBs: 0, corrupted PEBs: 0
UBI: user volume: 1, internal volumes: 1, max. volumes count: 94
UBI: max/mean erase counter: 3/1, WL threshold: 4096, image sequence number: 1654326921
UBI: available PEBs: 0, total reserved PEBs: 3968, PEBs reserved for bad PEB handling: 0
UBI: background thread "ubi_bgt0d" started, PID 698
UBIFS: background thread "ubifs_bgt0_0" started, PID 702
UBIFS: mounted UBI device 0, volume 0, name "fs"
UBIFS: LEB size: 16256 bytes (15 KiB), min./max. I/O unit sizes: 8 bytes/8 bytes
UBIFS: FS size: 64194944 bytes (61 MiB, 3949 LEBs), journal size 8111744 bytes (7 MiB, 499 LEBs)
UBIFS: reserved for root: 0 bytes (0 KiB)
UBIFS: media format: w4/r0 (latest is w4/r0), UUID 7FEA79B7-56E5-49B5-893F-03E4342DBF03, big LPT model
syslogd started: BusyBox v1.24.1
init: starting pid 730, tty '': '/sbin/mdev -s'
NET: Registered protocol family 10
init: starting pid 733, tty '/dev/ttyS0': '/bin/login -f root'
login[733]: root login on 'ttyS0'
random: nonblocking pool is initialized
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2026/03/23 15:51
  • by plappermaul