CDPwn系列之CVE-2020-3119分析
漏洞简介
CDPwn
系列漏洞是由来自Armis
的安全研究员在思科CDP(Cisco Discovery Protocol)
协议中发现的5个0 day
漏洞,影响的产品包括思科交换机、路由器、IP
电话以及摄像机等。其中,CVE-2020-3119
是NX-OS
系统中存在的一个栈溢出漏洞,利用该漏洞可在受影响的设备(如Nexus
系列交换机)上实现任意代码执行,如修改Nexus
交换机的配置以穿越VLAN
等。
下面借助GNS3
软件搭建Nexus
交换机仿真环境,来对该漏洞进行分析。
环境准备
根据漏洞公告,选取Nexus 9000 Series Switches in standalone NX-OS mode
作为分析目标,获取到对应的镜像如nxosv.9.2.2.qcow2
后,根据GNS3
提供的Cisco NX-OSv 9000 appliance
中的模板进行操作即可。需要说明的是,
- 与思科
ASAV
防火墙不同,模拟Nexus 9000
系列交换机除了需要设备镜像外,还需要一个UEFI
格式的启动文件; - 模拟
Nexus 9000
系列交换机对虚拟机的配置要求较高(8G
内存),建议采用GNS3
设备模板中的默认配置,降低配置的话可能导致设备无法启动。
设备启动后,建议连接到设备的Ethernet1/1
口,之后对设备进行配置。
在Nexus 9000
系列交换机上,存在以下3种shell
:
vsh
:正常配置设备时CLI
界面的shell
;guestshell
:在vsh
中运行guestshell
命令后进入的shell
,可以运行常见的shell
命令;bash shell
:在vsh
中运行run bash
命令后进入的shell
,可以查看底层系统中的文件,以及设备上的进程信息等;需要先在
configure
模式下,运行feature bash-shell
开启bash shell
默认配置下,bash shell
中是没有ip
信息的。为了方便后续进行分析调试,需要给之前连接的Ethernet1/1
口配置ip
信息,根据mac
地址查找对应的网口,然后配置对应的ip
即可。
设备的
mgmt
口在bash shell
下不存在对应的网口
另外,由于采用binwalk
工具对设备镜像进行解压提取失败,因而直接通过bash shell
拷贝设备文件系统中的文件:将公钥置于/root/.ssh/authorized_keys
,然后通过scp
方式进行拷贝即可。
Update:从
qcow2
文件中提取出对应的bin
文件如nxos.9.2.2.bin
,然后使用7z
等工具直接对bin
文件进行解压,即可提取出文件系统,其中包含cdpd
等程序。
CDP
数据包分析
为了便于后续的分析,需要先了解CDP
数据包的相关格式。在GNS3
中设备之间的链路上捕获流量,看到设备发送的CDP
数据包示例如下。
可以看到,除了开始的version
、ttl
和checksum
字段外,后面的每一部分都是典型的TLV(Type-Length-Value)
格式,Device ID
和Addresses
部分的字段明细如下。其中,在Addresses
部分,其Value
还有更细致的格式。
另外,python
scapy
模块支持CDP
协议,可以很方便地构造和发送CDP
数据包,示例如下。
1 | from scapy.contrib import cdp |
漏洞分析
根据Armis
的技术报告可知,该漏洞存在于程序/isan/bin/cdpd
中的函数cdpd_poe_handle_pwr_tlvs()
里,其主要功能是对Power Request(type=0x19)
部分的数据进行解析和处理,该部分的协议格式示例如下。
函数cdpd_poe_handle_pwr_tlvs()
的部分伪代码如下,其中,cdp_payload_pwr_req_ptr
指向Power Request(type=0x19)
部分的起始处。可以看到,首先在(1)
处获取到Length
字段的值,在(2)
处计算得到Power Requested
字段的个数(Type
+ Length
+ Request-ID
+ Management-ID
为8字节,Power Requested
字段每项为4
字节),之后在(4)
处将每个Power Requested
字段的值保存到v35
指向的内存空间中。由于v35
指向的内存区域为栈(在(3)
处获取局部变量的地址,其距离ebp
的大小为0x40
),而循环的次数外部可控,因此当Power Requested
字段的个数超过0x11
后,将覆盖栈上的返回地址。
1 | // 为方便理解, 对函数/变量进行了重命名 |
在后续进行漏洞利用时,由于在(5)
处将v35
指向的内存地址空间的内容保存到了a1[pwr_levels_count + 311]
中,而该地址与函数cdpd_poe_handle_pwr_tlvs()
的第一个参数有关,在覆盖栈上的返回地址之后也会覆盖该参数,因此需要构造一个合适的参数,使得(5)
处不会崩溃。另外,还要保证(6)
处的条件不成立,即执行else
分支,否则在该函数返回前还会出现其他崩溃。
另外,cdpd
程序启用的保护机制如下,同时设备上的ASLR
等级为2。由于cdpd
程序崩溃后会重启,因此需要通过爆破的方式来猜测程序相关的基地址。
1 | checksec --file cdpd |
之后漏洞利用可以执行注入的shellcode
,或者通过调用system()
来执行自定义的shell
命令。
通过
/isan/bin/vsh
可以执行设备配置界面中的命令,如system('/isan/bin/vsh -c "conf t ; username aaa password test123! role network-admin"
执行成功后,会添加一个aaa
的管理用户。
补丁分析
根据思科的漏洞公告,该漏洞在如下的版本中已修复。
以7.0(3)I7(8)
为例,函数cdpd_poe_handle_pwr_tlvs()
的部分伪代码如下。可以看到,在(1)
处增加了对Power Requested
字段个数的判断,其最大值为10。
1 | char __cdecl cdpd_poe_handle_pwr_tlvs(int *a1, int a2, _WORD *a3) |
小结
- 通过
GNS3
软件搭建设备的仿真环境,同时对该漏洞的形成原因进行了分析:在对Power Request(type=0x19)
部分的数据进行解析时,由于缺乏对其内容长度的校验,造成栈溢出。
相关链接
- CDPwn: 5 Zero-Days in Cisco Discovery Protocol
- Cisco NX-OS Software Cisco Discovery Protocol Remote Code Execution Vulnerability
- VIRTUALIZING A CISCO NEXUS 9K WITH GNS3
- CVE-2020-3119 Cisco CDP 协议栈溢出漏洞分析
本文首发于安全客,文章链接:https://www.anquanke.com/post/id/209018