Path: blob/master/modules/auxiliary/scanner/ftp/ftp_login.rb
28052 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'metasploit/framework/credential_collection'6require 'metasploit/framework/login_scanner/ftp'78class MetasploitModule < Msf::Auxiliary9include Msf::Exploit::Remote::Ftp10include Msf::Auxiliary::Scanner11include Msf::Auxiliary::Report12include Msf::Auxiliary::AuthBrute1314def proto15'ftp'16end1718def initialize19super(20'Name' => 'FTP Authentication Scanner',21'Description' => %q{22This module will test FTP logins on a range of machines and23report successful logins. If you have loaded a database plugin24and connected to a database this module will record successful25logins and hosts so you can track your access.26},27'Author' => 'todb',28'References' => [29[ 'CVE', '1999-0502'] # Weak password30],31'License' => MSF_LICENSE,32'DefaultOptions' => {33'ConnectTimeout' => 3034}35)3637register_options(38[39Opt::Proxies,40Opt::RPORT(21),41OptBool.new('RECORD_GUEST', [ false, "Record anonymous/guest logins to the database", false])42]43)4445register_advanced_options(46[47OptBool.new('SINGLE_SESSION', [ false, 'Disconnect after every login attempt', false]),48]49)5051deregister_options('FTPUSER', 'FTPPASS') # Can use these, but should use 'username' and 'password'52@accepts_all_logins = {}53end5455def run_host(ip)56print_status("#{ip}:#{rport} - Starting FTP login sweep")5758cred_collection = build_credential_collection(59username: datastore['USERNAME'],60password: datastore['PASSWORD'],61prepended_creds: anonymous_creds62)6364scanner = Metasploit::Framework::LoginScanner::FTP.new(65configure_login_scanner(66host: ip,67port: rport,68proxies: datastore['PROXIES'],69cred_details: cred_collection,70stop_on_success: datastore['STOP_ON_SUCCESS'],71bruteforce_speed: datastore['BRUTEFORCE_SPEED'],72max_send_size: datastore['TCP::max_send_size'],73send_delay: datastore['TCP::send_delay'],74connection_timeout: datastore['ConnectTimeout'],75ftp_timeout: datastore['FTPTimeout'],76framework: framework,77framework_module: self,78ssl: datastore['SSL'],79ssl_version: datastore['SSLVersion'],80ssl_verify_mode: datastore['SSLVerifyMode'],81ssl_cipher: datastore['SSLCipher'],82local_port: datastore['CPORT'],83local_host: datastore['CHOST']84)85)8687scanner.scan! do |result|88credential_data = result.to_h89credential_data.merge!(90module_fullname: self.fullname,91workspace_id: myworkspace_id92)93if result.success?94credential_data[:private_type] = :password95credential_core = create_credential(credential_data)96credential_data[:core] = credential_core97create_credential_login(credential_data)9899print_good "#{ip}:#{rport} - Login Successful: #{result.credential}"100else101invalidate_login(credential_data)102vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})"103end104end105end106107# Always check for anonymous access by pretending to be a browser.108def anonymous_creds109anon_creds = [ ]110if datastore['RECORD_GUEST']111['IEUser@', 'User@', '[email protected]', '[email protected]' ].each do |password|112anon_creds << Metasploit::Framework::Credential.new(public: 'anonymous', private: password)113end114end115anon_creds116end117118def test_ftp_access(user, scanner)119dir = Rex::Text.rand_text_alpha(8)120write_check = scanner.send_cmd(['MKD', dir], true)121if write_check and write_check =~ /^2/122scanner.send_cmd(['RMD', dir], true)123print_status("#{rhost}:#{rport} - User '#{user}' has READ/WRITE access")124return 'Read/Write'125else126print_status("#{rhost}:#{rport} - User '#{user}' has READ access")127return 'Read-only'128end129end130131end132133134