From 0818a856b6429e9a1c00471b9de7410f07561dd0 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Thu, 30 Jun 2011 06:52:52 +0000 Subject: [PATCH] Some fixups for some new AuthBrute hotness. git-svn-id: file:///home/svn/framework3/trunk@13075 4d416f70-5f16-0410-b530-b9f4589650da --- lib/msf/core/auxiliary/auth_brute.rb | 54 ++++++++++++++++++++-------- lib/msf/core/option_container.rb | 29 +++++++++++---- lib/rex/text.rb | 24 +++++++++++++ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/lib/msf/core/auxiliary/auth_brute.rb b/lib/msf/core/auxiliary/auth_brute.rb index 309d13db3b..75d198ba5d 100644 --- a/lib/msf/core/auxiliary/auth_brute.rb +++ b/lib/msf/core/auxiliary/auth_brute.rb @@ -160,24 +160,23 @@ module Auxiliary::AuthBrute expired_cred || expired_time end + # If the user passed a memory location for credential gen, assume + # that that's precisely what's desired -- no other transforms or + # additions or uniqueness should be done. Otherwise, perform + # the usual alterations. def build_credentials_array credentials = extract_word_pair(datastore['USERPASS_FILE']) - translate_proto_datastores() - + return credentials if datastore['USERPASS_FILE'] =~ /^memory:/ users = load_user_vars(credentials) passwords = load_password_vars(credentials) - cleanup_files() - if datastore['USER_AS_PASS'] credentials = gen_user_as_password(users, credentials) end - if datastore['BLANK_PASSWORDS'] credentials = gen_blank_passwords(users, credentials) end - credentials.concat(combine_users_and_passwords(users, passwords)) credentials.uniq! credentials = just_uniq_passwords(credentials) if @strip_usernames @@ -330,19 +329,44 @@ module Auxiliary::AuthBrute return save_array end + def get_object_from_memory_location(memloc) + if memloc.to_s =~ /^memory:\s*([0-9]+)/ + id = $1 + ObjectSpace._id2ref(id.to_s.to_i) + end + end + def extract_word_pair(wordfile) - return [] unless wordfile && File.readable?(wordfile) creds = [] + if wordfile.to_s =~ /^memory:/ + return extract_word_pair_from_memory(wordfile.to_s) + else + return [] unless wordfile && File.readable?(wordfile) + begin + upfile_contents = File.open(wordfile) {|f| f.read(f.stat.size)} + rescue + return [] + end + upfile_contents.split(/\n/).each do |line| + user,pass = line.split(/\s+/,2).map { |x| x.strip } + creds << [user.to_s, pass.to_s] + end + return creds + end + end + + def extract_word_pair_from_memory(memloc) begin - upfile_contents = File.open(wordfile) {|f| f.read(f.stat.size)} - rescue - return [] + creds = [] + obj = get_object_from_memory_location(memloc) + obj.all_creds.each do |cred| + user,pass = cred.split(/\s+/,2).map {|x| x.strip} + creds << [Rex::Text.dehex(user.to_s), Rex::Text.dehex(pass.to_s)] + end + return creds + rescue => e + raise ArgumentError, "Could not read credentials from memory, raised: #{e.class}: #{e.message}" end - upfile_contents.split(/\n/).each do |line| - user,pass = line.split(/\s+/,2).map { |x| x.strip } - creds << [user.to_s, pass.to_s] - end - return creds end def userpass_sleep_interval diff --git a/lib/msf/core/option_container.rb b/lib/msf/core/option_container.rb index 742008dded..1b37a64465 100644 --- a/lib/msf/core/option_container.rb +++ b/lib/msf/core/option_container.rb @@ -132,7 +132,7 @@ end # OptBool - Boolean true or false indication # OptPort - TCP/UDP service port # OptAddress - IP address or hostname -# OptPath - Path name on disk +# OptPath - Path name on disk or an Object ID # OptInt - An integer value # OptEnum - Select from a set of valid values # OptAddressRange - A subnet or range of addresses @@ -383,16 +383,33 @@ class OptPath < OptBase return 'path' end + # Generally, 'value' should be a file that exists. def valid?(value) return false if empty_required_value?(value) - - if ((value != nil and value.empty? == false) and - (File.exists?(value) == false)) - return false + if value and !value.empty? + if value =~ /^memory:\s*([0-9]+)/i + return false unless check_memory_location($1) + else + unless File.exists?(value) + return false + end + end end - return super end + + # The AuthBrute mixin can take a memory address as well -- + # currently, no other OptFile can make use of these objects. + # TODO: Implement memory:xxx to be more generally useful so + # the validator on OptFile isn't lying for non-AuthBrute. + def check_memory_location(id) + return false unless self.class.const_defined?(:ObjectSpace) + obj = ObjectSpace._id2ref(id.to_i) rescue nil + return false unless obj.respond_to? :acts_as_file? + return false unless obj.acts_as_file? # redundant? + return !!obj + end + end ### diff --git a/lib/rex/text.rb b/lib/rex/text.rb index 84d05f0b3d..da7fb3f129 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -704,6 +704,30 @@ module Text Digest::MD5.hexdigest(str) end + # + # Convert hex-encoded characters to literals. + # Example: "AA\\x42CC" becomes "AABCC" + # + def self.dehex(str) + return str unless str.respond_to? :match + return str unless str.respond_to? :gsub + regex = /\x5cx[0-9a-f]{2}/mi + if str.match(regex) + str.gsub(regex) { |x| x[2,2].to_i(16).chr } + else + str + end + end + + # + # Convert and replace hex-encoded characters to literals. + # + def self.dehex!(str) + return str unless str.respond_to? :match + return str unless str.respond_to? :gsub + regex = /\x5cx[0-9a-f]{2}/mi + str.gsub!(regex) { |x| x[2,2].to_i(16).chr } + end ## #