从CVE到DrayTek Vigor系列企业路由器固件分析

一、引言

Trellix 公司的安全研究员发现一个严重的远程代码执行 (RCE)漏洞 (CVE-2022-32548),影响29款 DrayTek Vigor 系列企业路由器。

易受攻击的机型如下:

  • Vigor3910
  • Vigor1000B
  • Vigor2962 系列
  • Vigor2927 系列
  • Vigor2927 LTE 系列
  • Vigor2915 系列
  • Vigor2952 / 2952P
  • Vigor3220 系列
  • Vigor2926 系列
  • Vigor2926 LTE 系列
  • Vigor2862 系列
  • Vigor2862 LTE 系列
  • Vigor2620 LTE 系列
  • VigorLTE 200n
  • Vigor2133 系列
  • Vigor2762 系列
  • Vigor167
  • Vigor130
  • VigorNIC 132
  • Vigor165
  • Vigor166
  • Vigor2135 系列
  • Vigor2765 系列
  • Vigor2766 系列
  • Vigor2832
  • Vigor2865 系列
  • Vigor2865 LTE 系列
  • Vigor2866 系列
  • Vigor2866 LTE 系列

由于没有实际设备,我们先挑选影响的型号Vigor 3910进行固件分析(https://fw.draytek.com.tw/Vigor3910/Firmware/):

我们下载最新的V4.3.2版本的固件,首先使用binwalk进行初步分析,发现无法解包,再使用WinHex十六进制工具查看,可以初步认为固件是某种加密方式加密的:

既然有加密的固件,那么可以查看旧版本的固件是否有不加密的固件进行“过渡”操作。

二、旧版固件分析

通过历史固件的对比分析,发现v3.9.7.2版本的固件与新版的固件有所区别,使用binwalk分析如下:

$ binwalk -Me v3910_3972.all 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
273054        0x42A9E         Unix path: /home/eason_jhan/1000b/cavium/firmware/bdk/libbdk-os/bdk-rlock.c
283704        0x45438         SHA256 hash constants, little endian
469662        0x72A9E         Unix path: /home/eason_jhan/1000b/cavium/firmware/bdk/libbdk-os/bdk-rlock.c
480312        0x75438         SHA256 hash constants, little endian
573012        0x8BE54         SHA256 hash constants, little endian
835156        0xCBE54         SHA256 hash constants, little endian
2032941       0x1F052D        Neighborly text, "neighbor %d too different %d from average %d, picking %d.LMC%d.R%d: MAJORTY: Byte %d: picking majority of %d over average %d."
2079947       0x1FBCCB        Unix path: /home/eason_jhan/1000b/cavium/firmware/bdk/libbdk-os/bdk-rlock.c
2096368       0x1FFCF0        SHA256 hash constants, little endian
2119768       0x205858        LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 2285442 bytes
2886232       0x2C0A58        LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 311880 bytes
3000920       0x2DCA58        LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 630943 bytes
3155032       0x302458        device tree image (dtb)
3160664       0x303A58        device tree image (dtb)
3165272       0x304C58        device tree image (dtb)
3165784       0x304E58        device tree image (dtb)
3172440       0x306858        device tree image (dtb)
3180632       0x308858        device tree image (dtb)
3184728       0x309858        device tree image (dtb)
3185752       0x309C58        device tree image (dtb)
3191896       0x30B458        device tree image (dtb)
3192408       0x30B658        device tree image (dtb)
3199576       0x30D258        device tree image (dtb)
3203160       0x30E058        device tree image (dtb)
3207256       0x30F058        device tree image (dtb)
3214424       0x310C58        device tree image (dtb)
3219544       0x312058        device tree image (dtb)
3228760       0x314458        device tree image (dtb)
3233368       0x315658        device tree image (dtb)
3239000       0x316C58        device tree image (dtb)
3243096       0x317C58        device tree image (dtb)
3243608       0x317E58        device tree image (dtb)
3247704       0x318E58        device tree image (dtb)
3253336       0x31A458        device tree image (dtb)
3257432       0x31B458        device tree image (dtb)
3258456       0x31B858        device tree image (dtb)
3265112       0x31D258        device tree image (dtb)
3272280       0x31EE58        device tree image (dtb)
3276376       0x31FE58        device tree image (dtb)
3277400       0x320258        device tree image (dtb)
3284056       0x321C58        device tree image (dtb)
3287640       0x322A58        device tree image (dtb)
3288152       0x322C58        device tree image (dtb)
3295320       0x324858        device tree image (dtb)
3295832       0x324A58        device tree image (dtb)
3302488       0x326458        device tree image (dtb)
3306072       0x327258        device tree image (dtb)
3330136       0x32D058        device tree image (dtb)
3346008       0x330E58        device tree image (dtb)
3361880       0x334C58        device tree image (dtb)
3377752       0x338A58        device tree image (dtb)
3400792       0x33E458        device tree image (dtb)
3425368       0x344458        device tree image (dtb)
3442264       0x348658        device tree image (dtb)
3463768       0x34DA58        device tree image (dtb)
3478616       0x351458        device tree image (dtb)
3493976       0x355058        device tree image (dtb)
3509848       0x358E58        device tree image (dtb)
3526232       0x35CE58        device tree image (dtb)
3541592       0x360A58        device tree image (dtb)
3557526       0x364896        Copyright string: "Copyright (C) 2016, Cavium Inc."
3559079       0x364EA7        Copyright string: "copyright notice and this permission notice shall be"
3561562       0x36585A        Unix path: /sys/class/gpio/gpio472) for DSL model
5052256       0x4D1760        CRC32 polynomial table, little endian
5099137       0x4DCE81        Motorola S-Record; binary data in text format, record type: header
5259312       0x504030        Microsoft executable, portable (PE)
5499456       0x53EA40        SHA256 hash constants, little endian
12693552      0xC1B030        ELF, 64-bit LSB shared object, version 1 (SYSV)
12741544      0xC26BA8        gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
12820184      0xC39ED8        Intel x86 or x64 microcode, sig 0xffffff80, pf_mask 0x00, 1DE0-08-26, size 2048
12820328      0xC39F68        Intel x86 or x64 microcode, sig 0xffffff80, pf_mask 0x00, 1DE0-08-26, size 2048
12923200      0xC53140        LZO compressed data
12925744      0xC53B30        CRC32 polynomial table, little endian
13188944      0xC93F50        Copyright string: "Copyright (c) 1999-2006 Intel Corporation."
13196536      0xC95CF8        Copyright string: "Copyright (c) 2009 - 2012 Intel Corporation."
13197320      0xC96008        Copyright string: "Copyright (c) 1999-2008 Intel Corporation."
13199736      0xC96978        Copyright string: "Copyright (c) 2013 - 2016 Intel Corporation."
13410380      0xCCA04C        Certificate in DER format (x509 v3), header length: 4, sequence length: 14848
14404968      0xDBCD68        Unix path: /dev/vc/0
14479296      0xDCEFC0        Ubiquiti partition header, header size: 56 bytes, name: "PARTNAME=%s", base address: 0x74790A00, data size: 23295090 bytes
14486472      0xDD0BC8        xz compressed data
14569424      0xDE4FD0        Unix path: /lib/firmware/updates/4.9.0-OCTEONTX_SDK_6_2_0_p3_build_38
14712280      0xE07DD8        Copyright string: "Copyright(c) 1999-2006 Intel Corporation"
14789199      0xE1AA4F        Copyright string: "Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>"
14812265      0xE20469        Copyright string: "Copyright(c) Pierre Ossman"
14848048      0xE29030        Unix path: /sys/firmware/devicetree/base
14848848      0xE29350        Unix path: /sys/firmware/fdt': CRC check failed
14864129      0xE2CF01        Neighborly text, "neighbor table overflow!ate is %x"
15613000      0xEE3C48        LZ4 compressed data, legacy
15613426      0xEE3DF2        Executable script, shebang: "/bin/sh"
16971299      0x102F623       Unix path: /dev/net/tun.
17236166      0x10700C6       mcrypt 2.5 encrypted data, algorithm: "w", keysize: 332 bytes, mode: """,
19705376      0x12CAE20       XML document, version: "1.0"
20045201      0x131DD91       VMware4 disk image
20045848      0x131E018       Executable script, shebang: "/bin/sh"
20111190      0x132DF56       Base64 standard index table
21756040      0x14BF888       Unix path: /sys/class/net/%s/phy80211
22373111      0x15562F7       Base64 standard index table
22816893      0x15C287D       MPEG transport stream data
23678637      0x1694EAD       Copyright string: "Copyright 1995-2005 Jean-loup Gailly "
24029059      0x16EA783       Unix path: /dev/net/tun
24533651      0x1765A93       eCos RTOS string reference: "ecosW"
24543379      0x1768093       HTML document header
24563221      0x176CE15       LUKS_MAGIC
24564177      0x176D1D1       xz compressed data
24873394      0x17B89B2       OpenSSL encryption, salted, salt: 0xC00770252D323573
24884301      0x17BB44D       HTML document header
24906969      0x17C0CD9       Private key in DER format (PKCS header length: 4, sequence length: 2345
25343574      0x182B656       Unix path: /usr/local/shk
25480049      0x184CB71       Executable script, shebang: "/bin/bash"
26449086      0x19394BE       SHA256 hash constants, little endian
26965826      0x19B7742       Cisco IOS microcode, for ""
27792979      0x1A81653       gzip compressed data, maximum compression, has header CRC, last modified: 1974-10-07 02:33:45 (bogus date)
30516402      0x1D1A4B2       HTML document header
30707709      0x1D48FFD       Base64 standard index table
32138317      0x1EA644D       HTML document header
32463276      0x1EF59AC       PNG image, 32 x 24, 8-bit/color RGBA, interlaced
32463352      0x1EF59F8       Zlib compressed data, default compression
32492091      0x1EFCA3B       GIF image data, version "89a", 5 x
32548082      0x1F0A4F2       JPEG image data, EXIF standard
32574798      0x1F10D4E       Zlib compressed data, best compression
32577456      0x1F117B0       Zlib compressed data, best compression
32580729      0x1F12479       JPEG image data, JFIF standard 1.02, thumbnail 11x98
32751022      0x1F3BDAE       Zlib compressed data, best compression
32760485      0x1F3E2A5       Zlib compressed data, default compression
32767499      0x1F3FE0B       JPEG image data, JFIF standard 1.02
32822738      0x1F4D5D2       Zlib compressed data, best compression
32831773      0x1F4F91D       XML document, version: "1.0"
32866201      0x1F57F99       JPEG image data, JFIF standard 1.02
32905743      0x1F61A0F       GIF image data, version "89a", 30 x 30
32943989      0x1F6AF75       Zlib compressed data, best compression
32947100      0x1F6BB9C       Zlib compressed data, best compression
32954824      0x1F6D9C8       XML document, version: "1.0"
32972713      0x1F71FA9       JPEG image data, JFIF standard 1.01
33011108      0x1F7B5A4       PNG image, 52 x 5, 8-bit/color RGBA, non-interlaced
33201563      0x1FA9D9B       XML document, version: "1.0"
33236782      0x1FB272E       PNG image, 1000 x 280, 8-bit/color RGBA, interlaced
33318819      0x1FC67A3       Zlib compressed data, best compression
33382838      0x1FD61B6       JPEG image data, JFIF standard 1.01
33382868      0x1FD61D4       TIFF image data, little-endian offset of first image directory: 8
33516114      0x1FF6A52       ZBOOT firmware header, header size: 32 bytes, load address: 0x9C54505A, start address: 0x8B844857, checksum: 0x4F8B885F, version: 0xFF979388, image size: 991901497 bytes
33609975      0x200D8F7       PNG image, 300 x 84, 8-bit/color RGBA, non-interlaced
33776158      0x203621E       XML document, version: "1.0"
33809104      0x203E2D0       PNG image, 310 x 531, 8-bit/color RGBA, non-interlaced
33809203      0x203E333       Zlib compressed data, best compression
34312241      0x20B9031       JPEG image data, JFIF standard 1.01
34352652      0x20C2E0C       TIFF image data, big-endian, offset of first image directory: 8
34799229      0x212FE7D       Base64 standard index table
35282151      0x21A5CE7       HTML document header
35375557      0x21BC9C5       Base64 standard index table
38441243      0x24A911B       Certificate in DER format (x509 v3), header length: 4, sequence length: 873
38694241      0x24E6D61       Executable script, shebang: "/bin/bash"
38694568      0x24E6EA8       Unix path: /dev/net/tun
39750489      0x25E8B59       Unix path: /usr/lib64/tc/
39881890      0x2608CA2       Copyright string: "Copyright (C) 2004 by Harald Welte <laforge@gnumonks.org>"
40546844      0x26AB21C       Unix path: /home/ruby/X
40667261      0x26C887D       Copyright string: "Copyright (C) 2018, Thomas G. Lane, Guido Vollbeding"
40692035      0x26CE943       Unix path: /home/ruby/X
42108450      0x2828622       Copyright string: "Copyright (C) 2018, Thomas G. Lane, Guido Vollbeding"
42240067      0x2848843       Copyright string: "Copyright (C) 2018, Thomas G. Lane, Guido Vollbeding"
42600735      0x28A091F       gzip compressed data, ASCII, from VM/CMS, last modified: 1995-08-24 06:41:07
42608185      0x28A2639       ELF, 64-bit LSB processor-specific,
42845890      0x28DC6C2       Neighborly text, "neighbor C %s"
43871781      0x29D6E25       Unix path: /home/ruby/X
44237701      0x2A30385       Executable script, shebang: "/bin/sh"
44249877      0x2A33315       OpenSSH RSA public key
45239782      0x2B24DE6       SHA256 hash constants, little endian
45601353      0x2B7D249       gzip compressed data, ASCII, from VM/CMS, last modified: 2008-04-20 10:46:28
47200461      0x2D038CD       SHA256 hash constants, little endian

通过binwalk的分析结果可以知道,这个固件应该不是加密固件,但是binwalk并不支持它的解包操作,如此我们先大概回顾一下固件的基本结构:

通过以上固件的基本结构,结合binwalk的信息,我们可以这样假设:

偏移功能备注
0-0x205857BootLoader先大概确定内核,再往上推演
0x205858-0xEE3DF1Kernel因为有LZMA的标识,可以大概推断为内核,并且这区间有dtb设备树、PE结构等标识
0xEE3DF2-末尾Rootfs从这里开始有Executable script的标识,表示存在实际的shell脚本文件内容了,以及后面有图片、网页的标识,可以断定为文件系统

截取0xEE3DF2的部分内容,可以看出此的确为shell脚本的内容,但是脚本里面充斥着很多非ASCII的内容,经过经验分析,此脚本可能被压缩了。

我们再来分析binwalk的解包结果,在0xC26BA8处有个gzip的标识,经过解压缩,可以知道其为内核的配置信息:

我们知道内核决定了支持的文件系统的类型,那么其配置信息内部可能会定义文件系统的相关配置,如此我们搜索rootfs关键字,最终找到了initramfs.cpio.lz4的字样:

后缀名lz4,可以联想到假定的rootfs区段内shell脚本之前有个LZ4压缩数据,那么可以断定从0xEE3C48应该为文件系统的起始位置。

15613000      0xEE3C48        LZ4 compressed data, legacy
15613426      0xEE3DF2        Executable script, shebang: "/bin/sh"

现在知道了,binwalk可能对lz4压缩不太支持,那么我们手动对binwalk进行功能添加:

# Ubuntu系统 添加lz4压缩工具
apt install liblz4-tool
# 加入lz4的压缩支持(binwalk安装路径/binwalk/config/extract.conf,如果找不到用find命令查找)
^lz4 compressed data:lz4:lz4 -d '%e' '%e.bin'

添加后如下所示:

使用binwalk -Me 固件就能获取到最终的文件系统的内容:

三、新版固件分析

我们说旧版固件是未加密的,新版固件是加密的,那么未加密->加密的过程会有个“过渡”操作,通过关键字“firmware”对整个文件系统进行查找,最终找到一个文件fw_upload里面有对旧版和新版固件的操作:

通过梳理整个逻辑,发现新版固件v4.3.2使用fw_unpacker进行固件的解包操作,并使用chacha20进行解密。

通过分析可知固件的结构:

序号偏移功能
10x0-0x03标识,字符串6216
20x04-0x07填充,值0
30x08-0x0Bheader的checksum校验值,值0x3EFB072A
40x0C值1
50x0D-0x3F固件版本号,字符串4.3.2_RC5a
60x40-0x43长度,值0x5
70x44-0x48型号,字符串v3910
80x49-0x4C填充1,值0
90x4D-0x50未知,值0x00000059
100x51-0x54nonce内容的checksum校验值,值0x6B075354
110x55-0x88填充2,值0
120x89-0x8C字符串nonce的长度,值0x5
130x8D-0x92字符串nonce
140x93-0x95nonce内容的长度,值0xC
150x96-0xA1nonce内容,字符串xRDYwRMx0B7u
160xA2-0xA5填充1,值0
170xA6-0xA9未知,值0x02FD1A51
180xAA-0xADenc_Image内容的checksum校验值,值0x26B0401D
190xAE-0xE1填充2,值0
200xE2-0xE5字符串enc_Image的长度,值0x9
210xE6-0xEE字符串enc_Image
220xEF-0xF2enc_Image内容的长度,值0x02FD1A00
230xF3-0x2FD1AF2enc_Image内容
......以下内容以此类推,包含以下区块:
enc_thunder-bootfs-uboot-t81.img
fw_release
fw_ver
pid
oid
uver
bdk_ver
linux_ver
drayqemu_ver
fw_release
fw_ver
pid
oid
uver
bdk_ver
fw_release
fw_ver
pid
oid
uver
bdk_ver

每个区块间隔0x40字节,即填充1到填充2之间的内容。

checksum校验算法:

def checksum(data, num):
    length = len(data)
    num = (~num) & 0xFFFFFFFF
    if not num:
        num = 0xFFFFFFFF
    tmp1 = 0
    for i in range(length):
        tmp1 = data[i]
        for j in range(8):
            tmp2 = tmp1 ^ num
            num >>= 1
            if (tmp2 & 1):
                num ^= 0xEDB88320
            tmp1 >>= 1
    return (~num) & 0xFFFFFFFF

我们需要关心的就是enc_Image区段,它是chacha20加密的,那么找到key,nonce就能解密了,解密出来是一个PE文件,直接使用binwalk -Me 固件解包,解开文件系统如下所示:

最终,本站的固件分析工具也同步更新了此类型固件的解包方式。

四、参考链接

https://blog.csdn.net/smellycat000/article/details/126188195

留下评论

您的电子邮箱地址不会被公开。 必填项已用*标注