D-Link 816-A2 路由器研究分享
1. 设备基础信息
2. 基础准备工作
2.1. 焊接UART接口获取shell
通过拆卸焊接UART接口并测量电压后可以得到如下图所示的UART接口线序。


sudo ptftpd -p 69 en7 -D ./static_tools
sudo ptftpd -r -p 69 en7 -D ./# 上传静态编译的mips工具
tftp -g -r mips/busybox.mipsel 192.168.0.200
tftp -g -r mips/gdbserver.mipsle 192.168.0.200# 赋予工具可执行权限
chmod +x ./*
./busybox-mipsel tar -cvf ./system_backup.tar / --exclude=proc --exclude=run -
-exclude=dev --exclude=mnt --exclude=sys# 回传打包的数据
# 在自己本机上运行
nc -l 8080 > system_backup.tar# 在路由器上执行
./busybox-mipsel nc 192.168.0.200 8080 < system_backup.tar
3. D-Link web管理页面分析
3.1 管理页面权限验证方法分析
D-Link的登录页面如下图所示。
输入账号密码后,将会向goform/formLogin接口发送如下图所示的数据包进行验证。从数据包中可以看到关键的参数有username,password以及tokenid,其中username使用了base64进行编码,password则进行了某种加密。
有趣的是在成功认证后,服务器并没有返回session或者Cookie相关的数据,仅仅返回了一个重定向到index页面的数据包。
通过对goahead程序的goform/formLogin接口函数进行分析可以看到在验证过程中函数首先会从nvram中读取Login及Password等参数。
随后调用websGetVar函数从我们发送的请求数据中获取username,password,tokenid参数的值。
之后将解析完成的,账号密码信息与nvram中保存的账号密码信息进行比对。
如下图所示,当判断认证成功时将会记录用户的IP地址至BSS区的变量load_host中并修改login变量为1,失败则会将1写入/etc/RAMConfig/confirmlogin文件中,并重定向用户到登录页面。
在更新BSS区的变量load_host后则会检测lan口和wan口的状态并返回对应的登录页面,随后将0写入/etc/RAMConfig/confirmlogin文件中。










3.2 form越权漏洞利用



4. 固件升级流程分析

/cgi-bin/upload.cgi
接口。
goahead
的分析,cgi-bin
目录所对应的Handler
函数为websCgiHandler
该函数最后会通过调用websLaunchCgiProc
函数执行对应的cgi-bin
文件。
websLaunchCgiProc
函数中将会fork一个子进程,随后调用execve
来执行cgi-bin文件。



SERVER_SOFTWARE=lbp_server UPLOAD_FILENAME=/var/cgiHNYyMd /etc_ro/web/cgi-bin/upload.cgi



4.2 imgdecrypt分析
imgdecrypt比较有趣,他会根据自身文件名来判断执行镜像的解密或加密操作。
在decrypt_firmare函数头部,首先会将0123456789ABCDEF字符串写入到栈中。
随后调用sub_40266C函数计算用于解密镜像的key。
通过对在sub_40266C 函数进行分析后,可以发现改函数主要从地址0x403010处开始获取用于aes解密的key,iv等一系列的数据。随后调用decryptData函数进行解密。













5. 自定义固件写入研究
5.1 防砖准备工作
------------------output------------------
dev: size erasesize name
mtd0: 00400000 00010000 "ALL"
mtd1: 00030000 00010000 "Bootloader"
mtd2: 00010000 00010000 "Config"
mtd3: 00010000 00010000 "Factory"
mtd4: 003b0000 00010000 "Kernel"
------------------------------------------/home/busybox.mipsel dd if=/dev/mtd4 of=/etc_ro/web/mtd4_Kernel.dump
------------------output------------------
7552+0 records in
7552+0 records out
3866624 bytes (3.7MB) copied, 1.412360 seconds, 2.6MB/s
------------------------------------------
备份完固件后若测试中出现系统异常,只要uboot部分没有被破坏,即可使用路由器uboot引导界面的第二个菜单功能,进行固件的刷写还原。通过配置tftp服务器及文件名称后即可通过tftp进行固件的还原。
5.2 linux kernel image分析

dd if=mtd4_Kernel.dump of=kernel_image.lzma bs=1 skip=64 count=3772774


~/IoT/tool/bin/xz -l root_fs.xz
------------------output------------------
Strms Blocks Compressed Uncompressed Ratio Check Filename
1 1 2,328.9 KiB 9,294.0 KiB 0.251 CRC32 root_fs.xz
------------------------------------------
# 解压xz文件
~/IoT/tool/bin/xz -d root_fs.xz
通过使用file命令可以得知解压后的xz数据是一个cpio归档文件,进一步查看后可以确认这个文件就是我们所需要修改的root_fs文件。
# 确认解压后的文件类型
file root_fs
------------------output------------------
root_fs: ASCII cpio archive (SVR4 with no CRC)
------------------------------------------
# 使用cpio命令查看归档的文件列表
cpio -tv -F root_fs|more
------------------output------------------
drwxrwxr-x 2 541 541 0 Aug 24 19:30 /sys
drwxrwxr-x 2 541 541 0 Aug 24 19:30 /mnt
drwxrwxr-x 2 541 541 0 Aug 24 19:30 /dev
crw--w--w- 1 root 541 240, 0 Aug 24 19:30 /dev/ac0
crw-rw---- 1 root 541 90, 8 Aug 24 19:30 /dev/mtd4
crw--w--w- 1 root 541 217, 0 Aug 24 19:30 /dev/spiS0
crw--w--w- 1 root 541 4, 64 Aug 24 19:30 /dev/ttyS0
brw-rw---- 1 root 541 31, 1 Aug 24 19:30 /dev/mtdblock1
brw-rw---- 1 root 541 31, 6 Aug 24 19:30 /dev/mtdblock6
crw--w--w- 1 root 541 251, 0 Aug 24 19:30 /dev/nvram
crw-rw-rw- 1 root 541 5, 2 Aug 24 19:30 /dev/ptmx
crw-rw-rw- 1 root 541 1, 3 Aug 24 19:30 /dev/null
crw--w--w- 1 root 541 218, 0 Aug 24 19:30 /dev/i2cM0
crw-rw---- 1 root 541 90, 1 Aug 24 19:30 /dev/mtd0ro
crw-rw-rw- 1 root 541 1, 2 Aug 24 19:30 /dev/kmem
crw--w--w- 1 root 541 253, 0 Aug 24 19:30 /dev/rdm0
brw-rw---- 1 root 541 31, 2 Aug 24 19:30 /dev/mtdblock2
------------------------------------------
下一步就是提取cpio中的文件了,提取命令如下。
创建目录rootfs
mkdir rootfs
cd rootfs
# 解压root_fs归档中的文件到rootfs目录中
cat ../root_fs | cpio -idmvH newc --no-absolute-filenames
# 成功解压后即可在目录中看到归档中的文件了。
ls -la
------------------output------------------
total 64
drwxr-xr-x 16 hack hack 4096 1月 16 11:55 .
drwxr-xr-x 4 hack hack 4096 1月 16 11:55 ..
drwxrwxr-x 2 hack hack 4096 1月 16 11:55 bin
drwxrwxr-x 3 hack hack 4096 1月 16 11:55 dev
drwxrwxr-x 2 hack hack 4096 1月 16 11:55 etc
drwxrwxr-x 9 hack hack 4096 1月 16 11:55 etc_ro
drwxrwxr-x 2 hack hack 4096 1月 16 11:55 home
lrwxrwxrwx 1 hack hack 11 1月 16 11:55 init -> bin/busybox
drwxr-xr-x 4 hack hack 4096 1月 16 11:55 lib
drwxrwxr-x 2 hack hack 4096 8月 24 19:30 media
drwxrwxr-x 2 hack hack 4096 8月 24 19:30 mnt
drwxrwxr-x 2 hack hack 4096 8月 24 19:30 proc
drwxrwxr-x 2 hack hack 4096 1月 16 11:55 sbin
------------------------------------------
5.3 重打包linux kernel image
cd rootfs# 归档rootfs下的所有文件
find . |cpio -H newc -o > ../root_fs.cpio
# 查看归档的结果,可以发现文件归档的路径是相对路径。
cpio -tv -F ../root_fs.cpio|more
------------------output------------------
drwxr-xr-x 16 hack hack 0 Jan 16 11:55 .
drwxrwxr-x 2 hack hack 0 Jan 16 11:55 sbin
-rwxr-xr-x 1 hack hack 29541 Aug 24 19:29 sbin/internet.sh
-rwxr-xr-x 1 hack hack 3073 Aug 24 19:29 sbin/config-powersave.sh
lrwxrwxrwx 1 hack hack 14 Jan 16 11:55 sbin/poweroff -> ../bin/busybox
-rwxr-xr-x 1 hack hack 7356 Aug 24 19:29 sbin/lan.sh
-rwxr-xr-x 1 hack hack 8981 Aug 24 19:29 sbin/virtual_server_dmz_s
------------------------------------------
此时有个小技巧,可以使用pax命令行工具进行重打包, 利用pax工具的-s参数将路径名进行替换操作。
使用pax打包rootfs目录,并对文件路径使用-s参数替换,替换语法和sed命令的替换方法相同。
pax -w -x sv4cpio -s '/rootfs//' rootfs > root_fs.cpio
# 查看归档的结果,可以发现文件归档的路径已被改写为/目录。
cpio -tv -F root_fs.cpio|more
------------------output------------------
drwxrwxr-x 2 hack hack 0 Jan 16 11:55 /sbin
-rwxr-xr-x 1 hack hack 29541 Aug 24 19:29 /sbin/internet.sh
-rwxr-xr-x 1 hack hack 3073 Aug 24 19:29 /sbin/config-powersave.sh
lrwxrwxrwx 1 hack hack 14 Jan 16 11:55 /sbin/poweroff -> ../bin/busybox
-rwxr-xr-x 1 hack hack 7356 Aug 24 19:29 /sbin/lan.sh
-rwxr-xr-x 1 hack hack 8981 Aug 24 19:29 /sbin/virtual_server_dmz_set2.sh
-rwxr-xr-x 1 hack hack 5120 Aug 24 19:29 /sbin/lan_web_filter.sh
-rwxr-xr-x 1 hack hack 1840 Aug 24 19:29 /sbin/portal_manage.sh
-rwxr-xr-x 1 hack hack 1143 Aug 24 19:29 /sbin/automount.sh
-rwxrwxr-x 1 hack hack 238 Aug 24 19:29 /sbin/pt_hotplug
------------------------------------------
在完成了上述准备工作后即可使用如下python脚本进行重打包。
# !/usr/bin/env python2
# coding=utf-8
import sys
import os
original_image_file = open("kernel_image", 'rb')
original_image_data = original_image_file.read()
original_xz_root_fs_start_offset = 0x48b000
original_root_fs_end_offset = 0x6d138c
original_root_fs_size = original_root_fs_end_offset - original_xz_root_fs_start_offset
working_folder = '/home/hack/IoT/D-Link_image'
root_fs_folder_name = 'rootfs'
xz_path = '/home/hack/IoT/tool/bin/xz'
lzma_path = '/home/hack/IoT/tool/bin/lzma'
# archive rootfs with cpio
cpio_archive_cmd = "cd %s ;pax -w -x sv4cpio -s '/%s//' %s > root_fs.cpio" % (working_folder, root_fs_folder_name, root_fs_folder_name)
print("execute: %s" % cpio_archive_cmd)
os.popen(cpio_archive_cmd)
# compress rootfs with xz
xz_cmd = "cd %s ;%s --check=crc32 -z -c root_fs.cpio > root_fs.cpio.xz" % (working_folder, xz_path)
print("execute: %s" % xz_cmd)
os.popen(xz_cmd)
# repack_image
new_image_name = 'kernel_image_hacked.img'
new_image = open(new_image_name, 'wb')
new_xz_root_fs_path = 'root_fs.cpio.xz'
new_xz_root = open(new_xz_root_fs_path, 'rb')
new_xz_root_data = new_xz_root.read()
if len(new_xz_root_data) > original_root_fs_size:
print("new image is too big, exit")
sys.exit()
new_image_data = original_image_data[:original_xz_root_fs_start_offset]
new_image_data += new_xz_root_data + ('\x00' * (original_root_fs_size - len(new_xz_root_data)))
new_image_data += original_image_data[original_root_fs_end_offset:]
new_image.write(new_image_data)
# compress image with lzma
lzma_cmd = "cd %s ;rm kernel_image_hacked.img.lzma; %s -z kernel_image_hacked.img" % (working_folder, lzma_path)
print("execute: %s" % lzma_cmd)
os.popen(lzma_cmd)
# make uimage
mkimg_cmd = 'cd %s; mkimage -A MIPS -O Linux -T kernel -C lzma -n "Linux Kernel Image" -a 80000000 -e 8000C2F0 -d kernel_image_hacked.img.lzma kernel_image_hacked.uimg' % (working_folder)
os.popen(mkimg_cmd)


PS: 设备中还存在疑似后门的开启telnet服务的特殊代码 ^ ^。
师傅,固件已经不能下载了,麻烦传网盘或者github一份吧,练练手