Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
MIPS-CVE-2014-9222 — 让我们通过深入挖掘 Zyxel 路由器固件和 MIPS 架构来享受乐趣。 | Kitploit
工具/GitHubGitHub/mercul1ninna/mips-cve-2014-9222
嵌入式系统安全漏洞分析漏洞利用逆向工程硬件黑客二进制分析学习与教育固件分析
GitHubmercul1ninna/mips-cve-2014-9222

MIPS-CVE-2014-9222

让我们通过深入挖掘 Zyxel 路由器固件和 MIPS 架构来享受乐趣。

查看仓库
57年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

免责声明

本教程仅供信息参考和教育目的。我认为,任何使用数字信息和计算机的人都应该熟悉道德黑客、信息安全及网络安全的相关知识。我相信,不了解黑客的手法,就无法有效防御黑客攻击。

前提条件

root@kitploit:~
$ IDA Pro +7.0(由于IDA价格昂贵,也可以使用Radar2)
$ 运行Rompager 4.07的路由器:数量众多,例如TP-Link TD-W8951*、ZyXEL P-660R、Billion BiPAC 51**/52** 等
$ UART转USB

"不幸的饼干"漏洞已存在一段时间,但公开的技术细节分析仍然缺乏。根据Check Point的报告,受影响的软件是来自AllegroSoft的嵌入式Web服务器RomPager。互联网范围的扫描表明,就可用端点数量而言,RomPager很可能是全球最流行的Web服务器软件。RomPager通常嵌入在设备固件中。该特定漏洞于2002年引入代码库。此外,暴露的设备使用RomPager服务的版本低于4.34(特别是4.07版本)。

本教程将使用一台运行Rompager 4.07的ZXHN H108L路由器。

root@kitploit:~
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="ZXHN H108L"
Content-Type: text/html
Transfer-Encoding: chunked
Server: RomPager/4.07 UPnP/1.0
EXT:

现在使用串口,首先必须确定波特率

root@kitploit:~
$ sudo stty -F /dev/ttyUSB0

输出:

root@kitploit:~
speed 115200 baud; line = 0;
-brkint -imaxbel

设备

我使用__minicom__,你也可以用__screen__或__HyperTerminal__,但我更青睐它的稳定性 ;)

首先必须禁用__硬件流控制__

root@kitploit:~
$ sudo minicom -s
root@kitploit:~
    +-----------------------------------------------------------------------+
    | A -    串行设备        : /dev/modem                                   |
    | B - 锁文件位置        : /var/lock                                      |
    | C -   呼叫程序        :                                               |
    | D -  呼出程序         :                                               |
    | E -   波特率/校验/数据位 : 115200 8N1                                  |
    | F - 硬件流控制        : No                                             |
    | G - 软件流控制        : No                                             |
    |                                                                       |
    |    修改哪项设置?                                                     |
    +-----------------------------------------------------------------------+
            | 屏幕和键盘      |
            | 保存设置为dfl   |
            | 保存设置为..    |
            | 退出            |
            | 退出Minicom     |
            +--------------------------+

现在可以开始了:

root@kitploit:~
$ sudo minicom -D /dev/ttyUSB0 -b 115200
root@kitploit:~
Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00    
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB GD25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode

RAS Version: ZXHN H108LV4.0.0a_ZRQ_MA                                          
System   ID: $2.12.162.0(G94.BY.2)3.20.19.0| 2014/03/21   20140321_v006  | 2014 

Press any key to enter debug mode within 3 seconds.
..........

显示可用命令:

$ ATHE

root@kitploit:~
======= 调试命令列表 =======
AT          仅回复OK
ATHE        打印帮助
ATBAx       更改波特率。1:38.4k, 2:19.2k, 3:9.6k 4:57.6k 5:115.2k
ATENx,(y)   设置BootExtension调试标志 (y=密码)
ATSE        显示密码生成器的种子
ATTI(h,m,s) 更改系统时间为时:分:秒或显示当前时间
ATDA(y,m,d) 更改系统日期为年/月/日或显示当前日期
ATDS        转储RAS堆栈
ATDT        转储启动模块公共区域
ATDUx,y     从地址x开始转储长度为y的内存内容
ATRBx       显示地址x的8位值
ATRWx       显示地址x的16位值
ATRLx       显示地址x的32位值
ATGO(x)     在地址x运行程序或启动路由器
ATGR        启动路由器
ATGT        运行硬件测试程序
ATRTw,x,y(,z) RAM测试级别w, 从地址x到y (z次迭代)
ATSH        转储ROM中制造商相关数据
ATDOx,y     通过XMODEM从地址x下载长度为y的数据到PC
ATTD        通过XMODEM将路由器配置下载到PC
ATUR        将路由器固件上传到闪存ROM

< 按任意键继续 >

该固件有一组隐藏命令,对我们的动态分析非常有用,问题是我们无法查看寄存器也不能设置断点,但幸运的是利用这些隐藏命令我们可以实现这些功能。为了看到并使用它们,我们需要使用__ATEN__。然而,这个命令需要密码,那么我们现在该怎么办?让我们逆向固件,找出密码生成算法。

(静态分析)先看看固件文件:

root@kitploit:~
$ binwalk ras

binwalk1

root@kitploit:~
$ dd if=ras of=rom1.lzma bs=1 skip=85043 count=66696
$ dd if=ras of=rom2.lzma bs=1 skip=350259 count=3350556
$ lzma -d <rom1.lzma> rom1
$ lzma -d <rom2.lzma> rom2

现在看看提取文件中的签名:

root@kitploit:~
$ binwalk -Y rom1
root@kitploit:~
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             MIPS可执行代码, 32/64位, 大端序, 至少1250条有效指令

strings 是一个很好的工具,可以了解二进制文件的内容。让我们看看能否找到密码算法:

root@kitploit:~
$ strings rom1 | grep -i aten
$ strings rom2 | grep -i aten

显然看不到,因为固件仍然被压缩,这意味着我们必须使用调试模式从路由器中转储出来:

root@kitploit:~
$ ATDO bfc00000, 1f0000

xmodem

想到的第一件事就是寻找调度表(dispatch table)。为什么?只是直觉,另一种可能性是使用if-elif链,但那样会非常长,用于检查用户提供的密码是否有效。下面是我找到的内容:

root@kitploit:~
ROM:800158A0 CmdTable:       .word unk_80015C20       # DATA XREF: sub_8000E3D8+4Co
ROM:800158A0                                          # sub_8000E3D8+90o ...
ROM:800158A4                 .word sub_8000E6D0
ROM:800158A8                 .byte    0
ROM:800158A9                 .byte    0
ROM:800158AA                 .byte    0
ROM:800158AB                 .byte    0
ROM:800158AC                 .word aJustAnswerOk      # "          just answer OK"
ROM:800158B0                 .word aAthe              # "ATHE"
ROM:800158B4                 .word CMD_SHOW_HELP_ATHE
ROM:800158B8                 .byte    0
ROM:800158B9                 .byte    0
ROM:800158BA                 .byte    0
ROM:800158BB                 .byte    0
ROM:800158BC                 .word aPrintHelp         # "          print help"
ROM:800158C0                 .word aAtba              # "ATBA"
ROM:800158C4                 .word CMD_ATBA
...
ROM:800158D0                 .word aAten              # "ATEN"
ROM:800158D4                 .word CMD_ATEN

请记住,MIPS中的字(word)是4字节。现在看看__CMD_ATEN__:

root@kitploit:~
ROM:8000FF84                 lw      $a0, 8($s0)
ROM:8000FF88                 jal     sub_80013654
ROM:8000FF8C                 li      $a1, 0
ROM:8000FF90                 jal     passwd_generator

然后是__passwd_generator__:

root@kitploit:~
ROM:80010A2C passwd_generator:                         # CODE XREF: CMD_ATEN+50p
ROM:80010A2C                 lui     $t9, 0xA11F
ROM:80010A30                 lw      $v1, ptrDO_GTABLE
ROM:80010A34                 lw      $t8, dword_80017050
ROM:80010A38                 lw      $v1, 0x18($v1)   # 获取种子部分,由ATSE命令生成
ROM:80010A3C                 lbu     $t8, 0x6D($t8)   # 获取MAC地址最后一个字节
ROM:80010A40                 sll     $v1, 8     # $v1 = v1 << 8
ROM:80010A44                 andi    $t7, $t8, 7    # $t7 = t8 & 0x7
ROM:80010A48                 li      $t8, 0     # $t8 = 0
ROM:80010A4C                 srl     $v1, 8     # $v1 = v1 >> 8 
ROM:80010A50                 li      $t9, 0xA11F5AC6    # $t9 = MAGIC
ROM:80010A54                 j       loc_80010A68
ROM:80010A58                 addu    $t9, $v1, $t9    # $t9 = $v1 + $t9
ROM:80010A5C  # ---------------------------------------------------------------------------
ROM:80010A5C
ROM:80010A5C loc_80010A5C:                              # CODE XREF: passwd_generator+40j
ROM:80010A5C                 sll     $t9, 31      # $t9 = $t9 << 31
ROM:80010A60                 or      $t9, $t6, $t9    # $t9 = $t6 | $t9
ROM:80010A64                 addiu   $t8, 1       # $t8 = $t8 + 1
ROM:80010A68
ROM:80010A68 loc_80010A68:                # CODE XREF: passwd_generator+28j
ROM:80010A68                 sltu    $t6, $t8, $t7    # $t6 = (t8 < t7? 1:0)
ROM:80010A6C                 bnez    $t6, loc_80010A5C    # 如果$t6 != 0则跳转
ROM:80010A70                 srl     $t6, $t9, 1    # $t6 = $t9 >> 1
ROM:80010A74                 jr      $ra      # 全部完成,退出
ROM:80010A78                 xor     $v0, $t9, $v1    # $v0 = $t9 ^ $v1

结论如下:

  • $v1 是种子值(由ATSE命令生成,如果未使用ATSE则为零)
  • $t8 初始包含MAC地址的最后一个字节(最后一个八位组)
  • 0xA11F5AC6 是我们一直在找的神奇数值!
  • 那两条指令:"$v1 = v1 << 8" 和 "$v1 = v1 >> 8" 相当于 "seed = seed & 0x00FFFFFF"
  • 循环(sll-or-srl)其实就是ROR指令(MIPS上的ROR是伪指令,通常用sll-or-srl序列模拟)
  • $v0 是结果

现在编写一个C程序实现相同功能并编译:

root@kitploit:~
U32 passwd_generator(U32 seed, U8 last_mac_octet)
{
      U32 b = seed & 0x00FFFFFF;
      U32 r = ROR(b + 0xA11F5AC6, last_mac_octet & 7);
      return r^b;
}

现在运行 ATSE 获取种子并使用它(例如,我得到 088521A78838):

root@kitploit:~
$ ./gen_pass 088521A78838

现在运行我们刚刚破解的神奇命令 :p

root@kitploit:~
$ ATEN1, A12F5AC6
root@kitploit:~
ATEN1, A12F5AC6
OK
ATHE
======= 调试命令列表 =======
AT          仅回复OK
ATHE        打印帮助
ATBAx       更改波特率。1:38.4k, 2:19.2k, 3:9.6k 4:57.6k 5:115.2k
ATENx,(y)   设置BootExtension调试标志 (y=密码)
ATSE        显示密码生成器的种子
ATTI(h,m,s) 更改系统时间为时:分:秒或显示当前时间
ATDA(y,m,d) 更改系统日期为年/月/日或显示当前日期
ATDS        转储RAS堆栈
ATDT        转储启动模块公共区域
ATDUx,y     从地址x开始转储长度为y的内存内容
ATWBx,y     将8位值y写入地址x
ATWWx,y     将16位值y写入地址x
ATWLx,y     将32位值y写入地址x
ATRBx       显示地址x的8位值
ATRWx       显示地址x的16位值
ATRLx       显示地址x的32位值
ATGO(x)     在地址x运行程序或启动路由器
ATGR        启动路由器
ATGT        运行硬件测试程序
AT%Tx        在启动时启用硬件测试程序
ATBTx        块0写使能 (1=启用, 其他=禁用)

< 按任意键继续 >
ATRTw,x,y(,z) RAM测试级别w, 从地址x到y (z次迭代)
ATWEa(,b,c,d) 将MAC地址、国家代码、EngDbgFlag、FeatureBit写入闪存ROM
ATCUx        将国家代码写入闪存ROM
ATCB         从闪存ROM复制到工作缓冲区
ATCL         清除工作缓冲区
ATSB         将工作缓冲区保存到闪存ROM
ATBU         转储工作缓冲区中的制造商相关数据
ATSH         转储ROM中的制造商相关数据
ATWMx        在工作缓冲区中设置MAC地址的低6位
ATMHx        在工作缓冲区中设置MAC地址的高6位
ATBS         显示BootBase密码生成器的种子
ATLBx        通过xmodem上传BootBase, x为密码
ATSMx        在工作缓冲区中设置MAC地址的6位
ATCOx        在工作缓冲区中设置国家代码
ATFLx        在工作缓冲区中设置EngDebugFlag
ATSTx        在工作缓冲区中设置ROMRAS地址
ATSYx        在工作缓冲区中设置系统类型
ATVDx        在工作缓冲区中设置供应商名称
ATPNx        在工作缓冲区中设置产品名称
ATFEx,y,...  在工作缓冲区中设置功能位
ATMP         检查并转储memMapTab
ATDOx,y      通过XMODEM从地址x下载长度为y的数据到PC

< 按任意键继续 >
ATTD         通过XMODEM将路由器配置下载到PC
ATUPx,y      通过XMODEM从PC上传数据到RAM地址x, 长度y
ATUR         将路由器固件上传到闪存ROM
ATDC         在上传固件期间禁用硬件版本检查
ATLC         将路由器配置文件上传到闪存ROM
ATUXx(,y)    从闪存块x到y通过xmodem上传
ATERx,y      擦除闪存ROM从块x到y
ATWFx,y,z    将数据从地址x复制到闪存地址y, 长度z
ATXSx        xmodem选择: x=0: CRC模式(默认); x=1: 校验和模式
ATLD         将配置文件和默认ROM文件上传到闪存
ATBR         重置为默认Romfile
ATCD         将当前ROM文件转换为默认ROM文件并写入闪存

OK

最后,我们获得了全新的命令集,可以让我们转储内存

root@kitploit:~
$ ATMP
root@kitploit:~
ROMIO image start at bfc30000
code version: 
code start: 80008000
code length: 1A5D4E
memMapTab: 18 entries, start = bfc44000, checksum = 9770
$RAM Section:
  0: BootExt(RAMBOOT), start=80030000, len=18000
  1: HTPCode(RAMCODE), start=80048000, len=E0000
  2: RasCode(RAMCODE), start=80048000, len=420000
$ROM Section:
  3: BootBas(ROMIMG), start=bfc28000, len=4000
  4: DbgArea(ROMIMG), start=bfc2c000, len=2000
  5: RomDir2(ROMDIR), start=bfc2e000, len=2000
  6: BootExt(ROMIMG), start=bfc30030, len=13FD0
  7: MemMapT(ROMMAP), start=bfc44000, len=C00
  8: HTPCode(ROMBIN), start=bfc44c00, len=8000
     (压缩)
     Version: HTP_TC V 0.05, start: bfc44c30
     Length: 10488, Checksum: CB32
     Compressed Length: 41CF, Checksum: D5A5
  9: termcap(ROMIMG), start=bfc4cc00, len=400
 10: RomDefa(ROMIMG), start=bfc4d000, len=2000
 11: LedDefi(ROMIMG), start=bfc4f000, len=400
 12: LogoImg(ROMIMG), start=bfc4f400, len=2000
 13: LogoImg2(ROMIMG), start=bfc51400, len=2000
 14: StrImag(ROMIMG), start=bfc53400, len=32000
 15: StrImag2(ROMIMG), start=bfc85400, len=32000
 16: Rt11nE2p(ROMIMG), start=bfcb7400, len=400
 17: RasCode(ROMBIN), start=bfcb7800, len=246C00
     (压缩)
     Version: ADSL ATU-R, start: bfcb7830
     Length: 321D2C, Checksum: 582D
     Compressed Length: 11E54B, Checksum: B30B
$USER Section:
Msecs   128
Heap0   16   300 16
Heap1   32   64  4
Heap2   64   64  4
Heap3   128  160 4
Heap4   192  256 4
Heap5   256  80  4
Heap6   320  20   4
Heap7   384  4   2
Heap8   448  20  2
Heap9   512  34  2
Heap10  1024 52  4
Heap11  2048 20  2
Heap12  3172 4   2
Heap13  4096 2   2
Heap14  0 0
...

我们刚才学到的知识将帮助我们分析之前提取的ROM文件

root@kitploit:~
code start: 80008000
code length: 1A5D4E

现在,在转储一个新ROM文件后,我们可以将__ROM起始地址__和__加载地址__设置为__0x80008000__,使用以下命令:

root@kitploit:~
$ ATDO 80008000, 1A5D4E

我们知道__ATGR__会启动路由器,所以我们可以跟踪它,找到将执行权传递给固件第二部分的指令。

atgr1

root@kitploit:~
ROM:80011E8C loc_80011E8C:            # CODE XREF: LoadAndRunImage+D8j
ROM:80011E8C                 jal     sub_80009B24
ROM:80011E90                 li      $a0, 0x1F4
ROM:80011E94
ROM:80011E94 execute_image:           # 执行镜像
ROM:80011E94                 jalr    $s0        # 跳转并链接到$s0中的地址
ROM:80011E98                 nop

现在我们需要问:$s0中存储的是什么地址?显然我们仍然无法设置断点,也无法查看寄存器,所以我们需要通过一些小技巧来泄露它。幸运的是,我们可以读写内存,看看下面的命令:

root@kitploit:~
ATWL 80011E94, ae30001c
ATGR

看起来,这条命令将__0x80011E94__处的指令补丁为__ae30001c__(MIPS指令__sw $s0, 0x1C($s1)的字节表示)。通过覆盖原始的__jalr $s0__为__sw $s0, 0x1C($s1),我们强制程序将__$s0__寄存器的内容存储到内存地址__0x8001FF1C__。这样,第二阶段的固件将不会被执行,而是显示"ERROR"消息,我们仍然可以访问第一阶段的控制台,太棒了!那么让我们看看__0x8001FF1C__中存储了什么内容。

root@kitploit:~
ATRL 8001FF1C
8001FF1C: 80020000

抓住它了!... 使用__0x80020000__,我们可以转储并正确分析固件的第二部分

未完待续 ...

下载工具