Fixes #435. Resolves a long-standing issue where datastore entries with a default of 'false' were being ignored.
git-svn-id: file:///home/svn/framework3/trunk@7334 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
84ebdfa7eb
commit
737dc327a3
|
@ -24,7 +24,7 @@ class DataStore < Hash
|
|||
k = find_key_case(k)
|
||||
@imported[k] = false
|
||||
@imported_by[k] = nil
|
||||
|
||||
|
||||
super(k,v)
|
||||
end
|
||||
|
||||
|
@ -34,14 +34,14 @@ class DataStore < Hash
|
|||
def [](k)
|
||||
super(find_key_case(k))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around store
|
||||
#
|
||||
#
|
||||
def store(k,v)
|
||||
super(find_key_case(k), v)
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Updates a value in the datastore with the specified name, k, to the
|
||||
|
@ -60,11 +60,11 @@ class DataStore < Hash
|
|||
options.each_option { |name, opt|
|
||||
# If there's already a value defined for this option, then skip it
|
||||
# and don't import it.
|
||||
next if self[name] and overwrite == false
|
||||
next if self.has_key?(name) and overwrite == false
|
||||
|
||||
# If the option has a default value, import it, but only if the
|
||||
# datastore doesn't already have a value set for it.
|
||||
if (opt.default and (overwrite or self[name] == nil))
|
||||
if ((opt.default != nil) and (overwrite or self[name] == nil))
|
||||
self.store(name, opt.default.to_s)
|
||||
|
||||
@imported[name] = true
|
||||
|
@ -100,7 +100,7 @@ class DataStore < Hash
|
|||
if (var == nil or val == nil)
|
||||
var = "unknown" if (!var)
|
||||
|
||||
raise Rex::ArgumentParseError, "Invalid option specified: #{var}",
|
||||
raise Rex::ArgumentParseError, "Invalid option specified: #{var}",
|
||||
caller
|
||||
end
|
||||
|
||||
|
@ -187,28 +187,28 @@ class DataStore < Hash
|
|||
def clear_non_user_defined
|
||||
@imported.delete_if { |k, v|
|
||||
if (v and @imported_by[k] != 'self')
|
||||
self.delete(k)
|
||||
self.delete(k)
|
||||
@imported_by.delete(k)
|
||||
end
|
||||
|
||||
v
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
|
||||
#
|
||||
# Case-insensitive key lookup
|
||||
#
|
||||
def find_key_case(k)
|
||||
|
||||
|
||||
# Scan each key looking for a match
|
||||
self.each_key do |rk|
|
||||
if (rk.downcase == k.downcase)
|
||||
return rk
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Fall through to the non-existent value
|
||||
return k
|
||||
end
|
||||
|
@ -247,7 +247,7 @@ class ModuleDataStore < DataStore
|
|||
#
|
||||
# Same as fetch
|
||||
#
|
||||
def [](key)
|
||||
def [](key)
|
||||
val = nil
|
||||
val = super if(@imported_by[key] != 'self')
|
||||
if (val.nil? and @_module and @_module.framework)
|
||||
|
@ -257,6 +257,13 @@ class ModuleDataStore < DataStore
|
|||
val
|
||||
end
|
||||
|
||||
#
|
||||
# Was this entry actually set or just using its default
|
||||
#
|
||||
def default?(key)
|
||||
(@imported_by[key] == 'self')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -25,8 +25,7 @@ module Exploit::Remote::HttpClient
|
|||
Opt::RHOST,
|
||||
Opt::RPORT(80),
|
||||
OptString.new('VHOST', [ false, "HTTP server virtual host" ]),
|
||||
Opt::SSL,
|
||||
Opt::Proxies
|
||||
Opt::Proxies
|
||||
], self.class
|
||||
)
|
||||
|
||||
|
@ -35,7 +34,8 @@ module Exploit::Remote::HttpClient
|
|||
OptString.new('UserAgent', [false, 'The User-Agent header to use for all requests']),
|
||||
OptString.new('BasicAuthUser', [false, 'The HTTP username to specify for basic authentication']),
|
||||
OptString.new('BasicAuthPass', [false, 'The HTTP password to specify for basic authentication']),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']])
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']])
|
||||
], self.class
|
||||
)
|
||||
|
||||
|
@ -64,20 +64,31 @@ module Exploit::Remote::HttpClient
|
|||
OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false])
|
||||
#
|
||||
# Remaining evasions to implement
|
||||
#
|
||||
#
|
||||
# OptBool.new('HTTP::chunked', [false, 'Enable chunking of HTTP request via "Transfer-Encoding: chunked"', 'false']),
|
||||
# OptInt.new('HTTP::junk_pipeline', [true, 'Insert the specified number of junk pipeline requests', 0]),
|
||||
], self.class
|
||||
)
|
||||
register_autofilter_ports([ 80, 8080, 443, 8000, 8888, 8880, 8008, 3000, 8443 ])
|
||||
register_autofilter_services(%W{ http https })
|
||||
register_autofilter_services(%W{ http https })
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Connects to an HTTP server.
|
||||
#
|
||||
def connect(opts={})
|
||||
|
||||
dossl = false
|
||||
if(opts.has_key?('SSL'))
|
||||
dossl = opts['SSL']
|
||||
else
|
||||
dossl = ssl
|
||||
if (datastore.default?('SSL') and rport.to_i == 443)
|
||||
dossl = true
|
||||
end
|
||||
end
|
||||
|
||||
nclient = Rex::Proto::Http::Client.new(
|
||||
rhost,
|
||||
rport.to_i,
|
||||
|
@ -85,11 +96,11 @@ module Exploit::Remote::HttpClient
|
|||
'Msf' => framework,
|
||||
'MsfExploit' => self,
|
||||
},
|
||||
ssl,
|
||||
dossl,
|
||||
ssl_version,
|
||||
proxies
|
||||
)
|
||||
|
||||
|
||||
# Configure the HTTP client with the supplied parameter
|
||||
nclient.set_config(
|
||||
'vhost' => self.vhost(),
|
||||
|
@ -108,7 +119,7 @@ module Exploit::Remote::HttpClient
|
|||
'uri_dir_fake_relative' => datastore['HTTP::uri_dir_fake_relative'],
|
||||
'uri_use_backslashes' => datastore['HTTP::uri_use_backslashes'],
|
||||
'pad_fake_headers' => datastore['HTTP::pad_fake_headers'],
|
||||
'pad_fake_headers_count' => datastore['HTTP::pad_fake_headers_count'],
|
||||
'pad_fake_headers_count' => datastore['HTTP::pad_fake_headers_count'],
|
||||
'pad_get_params' => datastore['HTTP::pad_get_params'],
|
||||
'pad_get_params_count' => datastore['HTTP::pad_get_params_count'],
|
||||
'pad_post_params' => datastore['HTTP::pad_post_params'],
|
||||
|
@ -125,9 +136,9 @@ module Exploit::Remote::HttpClient
|
|||
disconnect
|
||||
end
|
||||
|
||||
self.client = nclient
|
||||
self.client = nclient
|
||||
end
|
||||
|
||||
|
||||
return nclient
|
||||
end
|
||||
|
||||
|
@ -141,7 +152,7 @@ module Exploit::Remote::HttpClient
|
|||
(self.client))
|
||||
nsock = self.client.conn
|
||||
end
|
||||
|
||||
|
||||
# If the parent claims the socket associated with the HTTP client, then
|
||||
# we rip the socket out from under the HTTP client.
|
||||
if (((rv = super(nsock)) == Handler::Claimed) and
|
||||
|
@ -193,23 +204,23 @@ module Exploit::Remote::HttpClient
|
|||
# Connects to the server, creates a request, sends the request, reads the response
|
||||
#
|
||||
def send_request_cgi(opts={}, timeout = -1)
|
||||
begin
|
||||
begin
|
||||
c = connect(opts)
|
||||
r = c.request_cgi(opts)
|
||||
c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout)
|
||||
c.send_recv(r, opts[:timeout] ? opts[:timeout] : timeout)
|
||||
rescue ::Errno::EPIPE, ::Timeout::Error
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Combine the user/pass into an auth string for the HTTP Client
|
||||
#
|
||||
def basic_auth
|
||||
return if not datastore['BasicAuthUser']
|
||||
datastore['BasicAuthUser'] + ":" + (datastore['BasicAuthPass'] || '')
|
||||
datastore['BasicAuthUser'] + ":" + (datastore['BasicAuthPass'] || '')
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Wrappers for getters
|
||||
|
@ -250,14 +261,14 @@ module Exploit::Remote::HttpClient
|
|||
def ssl_version
|
||||
datastore['SSLVersion']
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the configured proxy list
|
||||
#
|
||||
def proxies
|
||||
datastore['Proxies']
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :client
|
||||
|
@ -278,7 +289,7 @@ module Exploit::Remote::HttpServer
|
|||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('URIPATH', [ false, "The URI to use for this exploit (default is random)"]),
|
||||
|
@ -341,13 +352,13 @@ module Exploit::Remote::HttpServer
|
|||
|
||||
# Start the HTTP server service.
|
||||
self.service = Rex::ServiceManager.start(
|
||||
Rex::Proto::Http::Server,
|
||||
Rex::Proto::Http::Server,
|
||||
opts['ServerPort'].to_i,
|
||||
opts['ServerHost'],
|
||||
{
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.service.server_name = 'Apache'
|
||||
|
@ -362,11 +373,11 @@ module Exploit::Remote::HttpServer
|
|||
}.update(opts['Uri'] || {})
|
||||
|
||||
print_status("Using URL: http://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")
|
||||
|
||||
|
||||
if (opts['ServerHost'] == '0.0.0.0')
|
||||
print_status(" Local IP: http://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
|
||||
end
|
||||
|
||||
|
||||
add_resource(uopts)
|
||||
end
|
||||
|
||||
|
@ -374,7 +385,7 @@ module Exploit::Remote::HttpServer
|
|||
# Store the results of server-side User-Agent fingerprinting in the DB.
|
||||
#
|
||||
# Returns an array containing host and client information.
|
||||
#
|
||||
#
|
||||
def report_user_agent(address, request)
|
||||
ua = request['User-Agent'].downcase
|
||||
# always check for IE last because everybody tries to
|
||||
|
@ -453,7 +464,7 @@ module Exploit::Remote::HttpServer
|
|||
:address => address,
|
||||
:host => address,
|
||||
:os_name => os_name,
|
||||
:os_flavor => os_flavor,
|
||||
:os_flavor => os_flavor,
|
||||
:os_lang => os_lang || 'en',
|
||||
:arch => arch
|
||||
}
|
||||
|
@ -484,14 +495,14 @@ module Exploit::Remote::HttpServer
|
|||
@service_path = opts['Path']
|
||||
service.add_resource(opts['Path'], opts)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the last-used resource path
|
||||
#
|
||||
def get_resource
|
||||
@service_path
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Removes a URI resource.
|
||||
#
|
||||
|
@ -505,7 +516,7 @@ module Exploit::Remote::HttpServer
|
|||
def close_client(cli)
|
||||
service.close_client(cli)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Creates an HTTP response packet.
|
||||
#
|
||||
|
@ -525,7 +536,7 @@ module Exploit::Remote::HttpServer
|
|||
response['Content-Type'] = 'text/html'
|
||||
response.body = body
|
||||
|
||||
if (datastore['HTTP::compression'])
|
||||
if (datastore['HTTP::compression'])
|
||||
self.use_zlib # make sure...
|
||||
response.compress = datastore['HTTP::compression']
|
||||
end
|
||||
|
@ -538,7 +549,7 @@ module Exploit::Remote::HttpServer
|
|||
if (datastore['HTTP::header_folding'] == true)
|
||||
response.headers.fold = 1
|
||||
end
|
||||
|
||||
|
||||
if (datastore['HTTP::junk_headers'] == true)
|
||||
response.headers.junk_headers = 1
|
||||
end
|
||||
|
@ -556,10 +567,10 @@ module Exploit::Remote::HttpServer
|
|||
response['Content-Type'] = 'text/html'
|
||||
response['Location'] = location
|
||||
response.body = body
|
||||
|
||||
|
||||
cli.send_response(response)
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Sends a 302 redirect relative to our base path
|
||||
|
@ -614,7 +625,7 @@ module Exploit::Remote::HttpServer
|
|||
#
|
||||
def regenerate_payload(cli, arch = nil, platform = nil, target = nil)
|
||||
pcode = nil
|
||||
|
||||
|
||||
# If the payload fails to generate for some reason, send a 403.
|
||||
if ((pcode = super(cli, arch, platform, target)) == nil)
|
||||
print_error("Failed to generate payload, sending 403.")
|
||||
|
@ -657,7 +668,7 @@ protected
|
|||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
# utf-8, utf-7 and utf-7-all are currently not supported by
|
||||
|
@ -829,10 +840,10 @@ protected
|
|||
};
|
||||
|
||||
ENDJS
|
||||
opts = {
|
||||
'Symbols' => {
|
||||
opts = {
|
||||
'Symbols' => {
|
||||
'Variables' => [
|
||||
'Base64', 'encoding',
|
||||
'Base64', 'encoding',
|
||||
'result', '_keyStr',
|
||||
'encoded_data',
|
||||
'utftext', 'input_idx',
|
||||
|
@ -840,9 +851,9 @@ protected
|
|||
'chr', 'chr1', 'chr2', 'chr3',
|
||||
'enc1', 'enc2', 'enc3', 'enc4'
|
||||
],
|
||||
'Methods' => [
|
||||
'Methods' => [
|
||||
'_utf8_encode', '_utf8_decode',
|
||||
'encode', 'decode'
|
||||
'encode', 'decode'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -852,7 +863,7 @@ protected
|
|||
end
|
||||
|
||||
def js_heap_spray
|
||||
js = %Q|
|
||||
js = %Q|
|
||||
var memory = new Array();
|
||||
function sprayHeap(shellcode, heapSprayAddr, heapBlockSize) {
|
||||
var index;
|
||||
|
@ -860,27 +871,27 @@ protected
|
|||
var heapSprayAddr_lo = (heapSprayAddr & 0xffff).toString(16);
|
||||
while (heapSprayAddr_hi.length < 4) { heapSprayAddr_hi = "0" + heapSprayAddr_hi; }
|
||||
while (heapSprayAddr_lo.length < 4) { heapSprayAddr_lo = "0" + heapSprayAddr_lo; }
|
||||
|
||||
|
||||
var retSlide = unescape("%u"+heapSprayAddr_hi + "%u"+heapSprayAddr_lo);
|
||||
while (retSlide.length < heapBlockSize) { retSlide += retSlide; }
|
||||
retSlide = retSlide.substring(0, heapBlockSize - shellcode.length);
|
||||
|
||||
var heapBlockCnt = (heapSprayAddr - heapBlockSize)/heapBlockSize;
|
||||
for (index = 0; index < heapBlockCnt; index++) {
|
||||
memory[index] = retSlide + shellcode;
|
||||
}
|
||||
memory[index] = retSlide + shellcode;
|
||||
}
|
||||
}
|
||||
|
|
||||
opts = {
|
||||
'Symbols' => {
|
||||
'Variables' => [
|
||||
'Variables' => [
|
||||
'shellcode',
|
||||
'retSlide',
|
||||
'payLoadSize',
|
||||
'retSlide',
|
||||
'payLoadSize',
|
||||
'memory',
|
||||
'index',
|
||||
'heapSprayAddr_lo',
|
||||
'heapSprayAddr_hi',
|
||||
'index',
|
||||
'heapSprayAddr_lo',
|
||||
'heapSprayAddr_hi',
|
||||
'heapSprayAddr',
|
||||
'heapBlockSize',
|
||||
'heapBlockCnt',
|
||||
|
@ -927,7 +938,7 @@ protected
|
|||
body = '<script>document.write(unescape("' + Rex::Text.to_hex(body, '%') + '"))</script>'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
if ['utf-16le','utf-16be','utf32-le','utf32-be','utf-7','utf-8'].include?(datastore['HTML::unicode'])
|
||||
headers['Content-Type'] = 'text/html; charset: ' + datastore['HTML::unicode']
|
||||
body = Rex::Text.to_unicode(body, datastore['HTML::unicode'])
|
||||
|
@ -946,7 +957,7 @@ protected
|
|||
raise RuntimeError, 'Invalid unicode. how did you get here?'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
send_response(cli, body, headers)
|
||||
end
|
||||
|
||||
|
@ -964,26 +975,26 @@ module Exploit::Remote::HttpServer::PHPInclude
|
|||
include Msf::Exploit::Remote::HttpServer
|
||||
|
||||
def initialize(info = {})
|
||||
|
||||
|
||||
# Override TCPServer's stance of passive
|
||||
super(update_info(info, 'Stance' => Msf::Exploit::Stance::Aggressive))
|
||||
|
||||
super(update_info(info, 'Stance' => Msf::Exploit::Stance::Aggressive))
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
OptEnum.new('PHP::Encode', [false, 'Enable PHP code obfuscation', 'none', ['none', 'base64']]),
|
||||
], Exploit::Remote::HttpServer::PHPInclude
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Override exploit() to handle service start/stop
|
||||
#
|
||||
def exploit
|
||||
start_service
|
||||
print_status("PHP include server started.");
|
||||
|
||||
|
||||
php_exploit
|
||||
|
||||
|
||||
select(nil, nil, nil, 5)
|
||||
stop_service
|
||||
end
|
||||
|
@ -999,7 +1010,7 @@ module Exploit::Remote::HttpServer::PHPInclude
|
|||
when 'none'
|
||||
body = "<?php #{body} ?>"
|
||||
end
|
||||
|
||||
|
||||
send_response(cli, body, headers)
|
||||
end
|
||||
|
||||
|
@ -1009,11 +1020,11 @@ module Exploit::Remote::HttpServer::PHPInclude
|
|||
def on_request_uri(cli, request, headers={})
|
||||
# Re-generate the payload
|
||||
return if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
|
||||
# Send it to the application
|
||||
send_php_payload(cli, p.encoded, headers)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Return the PHP include URL (pre-encoded)
|
||||
#
|
||||
|
@ -1024,7 +1035,8 @@ module Exploit::Remote::HttpServer::PHPInclude
|
|||
end
|
||||
"http://#{addr}:#{datastore['SRVPORT']}#{get_resource()}?"
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ module Exploit::Remote::SMB
|
|||
SIMPLE = Rex::Proto::SMB::SimpleClient
|
||||
XCEPT = Rex::Proto::SMB::Exceptions
|
||||
CONST = Rex::Proto::SMB::Constants
|
||||
|
||||
|
||||
# Alias over the Rex DCERPC protocol modules
|
||||
DCERPCPacket = Rex::Proto::DCERPC::Packet
|
||||
DCERPCClient = Rex::Proto::DCERPC::Client
|
||||
|
@ -29,7 +29,7 @@ module Exploit::Remote::SMB
|
|||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
OptBool.new('SMB::pipe_evasion', [ true, 'Enable segmented read/writes for SMB Pipes', 'False']),
|
||||
|
@ -40,7 +40,7 @@ module Exploit::Remote::SMB
|
|||
OptInt.new('SMB::pad_data_level', [ true, 'Place extra padding between headers and data (level 0-3)', 0]),
|
||||
OptInt.new('SMB::pad_file_level', [ true, 'Obscure path names used in open/create (level 0-3)', 0]),
|
||||
OptInt.new('SMB::obscure_trans_pipe_level', [ true, 'Obscure PIPE string in TransNamedPipe (level 0-3)', 0]),
|
||||
|
||||
|
||||
], Msf::Exploit::Remote::SMB)
|
||||
|
||||
register_advanced_options(
|
||||
|
@ -55,30 +55,34 @@ module Exploit::Remote::SMB
|
|||
register_options(
|
||||
[
|
||||
Opt::RHOST,
|
||||
OptInt.new('RPORT', [ true, 'Set the SMB service port', 445])
|
||||
OptInt.new('RPORT', [ true, 'Set the SMB service port', 445])
|
||||
], Msf::Exploit::Remote::SMB)
|
||||
|
||||
|
||||
register_autofilter_ports([ 139, 445])
|
||||
register_autofilter_services(%W{ netbios-ssn microsoft-ds })
|
||||
register_autofilter_services(%W{ netbios-ssn microsoft-ds })
|
||||
end
|
||||
|
||||
|
||||
def connect(global=true)
|
||||
|
||||
|
||||
disconnect() if global
|
||||
|
||||
|
||||
s = super(global)
|
||||
self.sock = s if global
|
||||
|
||||
# Make sure that SMBDirect is false when RPORT is 139
|
||||
|
||||
# Disable direct SMB when SMBDirect has not been set
|
||||
# and the destination port is configured as 139
|
||||
direct = smb_direct
|
||||
direct = false if rport.to_i == 139
|
||||
if(datastore.default?('SMBDirect') and rport.to_i == 139)
|
||||
direct = true
|
||||
end
|
||||
|
||||
c = SIMPLE.new(s, direct)
|
||||
|
||||
|
||||
# setup pipe evasion foo
|
||||
if datastore['SMB::pipe_evasion']
|
||||
# XXX - insert code to change the instance of the read/write functions to do segmentation
|
||||
end
|
||||
|
||||
|
||||
if (datastore['SMB::pad_data_level'])
|
||||
c.client.evasion_opts['pad_data'] = datastore['SMB::pad_data_level']
|
||||
end
|
||||
|
@ -90,7 +94,7 @@ module Exploit::Remote::SMB
|
|||
if (datastore['SMB::obscure_trans_pipe_level'])
|
||||
c.client.evasion_opts['obscure_trans_pipe'] = datastore['SMB::obscure_trans_pipe_level']
|
||||
end
|
||||
|
||||
|
||||
self.simple = c if global
|
||||
c
|
||||
end
|
||||
|
@ -99,47 +103,47 @@ module Exploit::Remote::SMB
|
|||
def unicode(str)
|
||||
Rex::Text.to_unicode(str)
|
||||
end
|
||||
|
||||
|
||||
# This method establishes a SMB session over the default socket
|
||||
def smb_login
|
||||
simple.login(
|
||||
datastore['SMBName'],
|
||||
datastore['SMBName'],
|
||||
datastore['SMBUser'],
|
||||
datastore['SMBPass'],
|
||||
datastore['SMBDomain']
|
||||
)
|
||||
|
||||
|
||||
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
|
||||
end
|
||||
|
||||
# This method returns the native operating system of the peer
|
||||
# This method returns the native operating system of the peer
|
||||
def smb_peer_os
|
||||
self.simple.client.peer_native_os
|
||||
end
|
||||
|
||||
|
||||
# This method returns the native lanman version of the peer
|
||||
def smb_peer_lm
|
||||
self.simple.client.peer_native_lm
|
||||
end
|
||||
|
||||
|
||||
# This method opens a handle to an IPC pipe
|
||||
def smb_create(pipe)
|
||||
self.simple.create_pipe(pipe)
|
||||
end
|
||||
|
||||
|
||||
def smb_hostname
|
||||
datastore['SMBName'] || '*SMBSERVER'
|
||||
end
|
||||
|
||||
|
||||
def smb_direct
|
||||
datastore['SMBDirect']
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Fingerprinting methods
|
||||
#
|
||||
|
||||
|
||||
|
||||
# This method the EnumPrinters() function of the spooler service
|
||||
def smb_enumprinters(flags, name, level, blen)
|
||||
|
@ -151,9 +155,9 @@ module Exploit::Remote::SMB
|
|||
NDR.long(blen) +
|
||||
"\x00" * blen +
|
||||
NDR.long(blen)
|
||||
|
||||
|
||||
handle = dcerpc_handle(
|
||||
'12345678-1234-abcd-ef00-0123456789ab', '1.0',
|
||||
'12345678-1234-abcd-ef00-0123456789ab', '1.0',
|
||||
'ncacn_np', ["\\SPOOLSS"]
|
||||
)
|
||||
|
||||
|
@ -165,18 +169,18 @@ module Exploit::Remote::SMB
|
|||
raise $!
|
||||
rescue ::Exception => e
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# This method dumps the print provider strings from the spooler
|
||||
def smb_enumprintproviders
|
||||
resp = smb_enumprinters(8, nil, 1, 0)
|
||||
return nil if not resp
|
||||
return nil if not resp
|
||||
rptr, tmp, blen = resp.unpack("V*")
|
||||
|
||||
resp = smb_enumprinters(8, nil, 1, blen)
|
||||
return nil if not resp
|
||||
|
||||
|
||||
bcnt,pcnt,stat = resp[-12, 12].unpack("VVV")
|
||||
return nil if stat != 0
|
||||
return nil if pcnt == 0
|
||||
|
@ -189,7 +193,7 @@ module Exploit::Remote::SMB
|
|||
# The correct way, which leads to invalid offsets :-(
|
||||
#
|
||||
providers = []
|
||||
|
||||
|
||||
0.upto(pcnt-1) do |i|
|
||||
flags,desc_o,name_o,comm_o = resp[8 + (i*16), 16].unpack("VVVV")
|
||||
|
||||
|
@ -201,11 +205,11 @@ module Exploit::Remote::SMB
|
|||
|
||||
providers
|
||||
end
|
||||
|
||||
|
||||
# This method performs an extensive set of fingerprinting operations
|
||||
def smb_fingerprint
|
||||
fprint = {}
|
||||
|
||||
|
||||
# Connect to the server if needed
|
||||
if(not self.simple)
|
||||
connect()
|
||||
|
@ -249,23 +253,23 @@ module Exploit::Remote::SMB
|
|||
os = 'Windows Vista ' + $1
|
||||
sp = '(Build ' + $2 + ')'
|
||||
|
||||
when /Windows Server \(R\) 2008 (\w+|\w+ \w+) (\d+) Service Pack (\d+)/
|
||||
when /Windows Server \(R\) 2008 (\w+|\w+ \w+) (\d+) Service Pack (\d+)/
|
||||
os = 'Windows 2008 ' + $1
|
||||
sp = 'Service Pack ' + $3
|
||||
sp = 'Service Pack ' + $3
|
||||
|
||||
when /Windows Server \(R\) 2008 (\w+|\w+ \w+) (\d+)/
|
||||
when /Windows Server \(R\) 2008 (\w+|\w+ \w+) (\d+)/
|
||||
os = 'Windows 2008 ' + $1
|
||||
sp = '(Build ' + $2 + ')'
|
||||
|
||||
when /Windows \(R\) Storage Server 2008 (\w+|\w+ \w+) (\d+) Service Pack (\d+)/
|
||||
when /Windows \(R\) Storage Server 2008 (\w+|\w+ \w+) (\d+) Service Pack (\d+)/
|
||||
os = 'Windows 2008 Storage Server ' + $1
|
||||
sp = 'Service Pack ' + $3
|
||||
sp = 'Service Pack ' + $3
|
||||
|
||||
when /Windows \(R\) Storage Server 2008 (\w+|\w+ \w+) (\d+)/
|
||||
when /Windows \(R\) Storage Server 2008 (\w+|\w+ \w+) (\d+)/
|
||||
os = 'Windows 2008 Storage Server ' + $1
|
||||
sp = '(Build ' + $2 + ')'
|
||||
|
||||
when /Windows 7 (\w+|\w+ \w+) (\d+)/
|
||||
|
||||
when /Windows 7 (\w+|\w+ \w+) (\d+)/
|
||||
os = 'Windows 7 ' + $1
|
||||
sp = '(Build ' + $2 + ')'
|
||||
|
||||
|
@ -313,14 +317,14 @@ module Exploit::Remote::SMB
|
|||
# Credit to spoonm for first use of unbounded [out] buffers
|
||||
#
|
||||
handle = dcerpc_handle(
|
||||
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
|
||||
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
|
||||
'ncacn_np', ["\\BROWSER"]
|
||||
)
|
||||
|
||||
begin
|
||||
dcerpc_bind(handle)
|
||||
|
||||
stub =
|
||||
stub =
|
||||
NDR.uwstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
|
||||
NDR.wstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
|
||||
NDR.long(64001) +
|
||||
|
@ -348,7 +352,7 @@ module Exploit::Remote::SMB
|
|||
# Silent fix of pointer leak in SP3 and detection method by Rhys Kidd
|
||||
#
|
||||
handle = dcerpc_handle(
|
||||
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
|
||||
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
|
||||
'ncacn_np', ["\\BROWSER"]
|
||||
)
|
||||
|
||||
|
@ -382,7 +386,7 @@ module Exploit::Remote::SMB
|
|||
|
||||
lang = 'Unknown'
|
||||
|
||||
sigs =
|
||||
sigs =
|
||||
{
|
||||
'English' =>
|
||||
[
|
||||
|
@ -458,7 +462,7 @@ module Exploit::Remote::SMB
|
|||
[
|
||||
"\xdc\x8f\x0b\x7a\x53\x62\x70\x53\x3a\x67"
|
||||
],
|
||||
'Chinese - Traditional / Taiwan' =>
|
||||
'Chinese - Traditional / Taiwan' =>
|
||||
[
|
||||
"\x60\x90\xef\x7a\x70\x53\x68\x88\x5f\x6a",
|
||||
],
|
||||
|
@ -534,11 +538,11 @@ module Exploit::Remote::SMB
|
|||
|
||||
fprint
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Accessors
|
||||
#
|
||||
|
||||
|
||||
attr_accessor :simple
|
||||
|
||||
end
|
||||
|
@ -575,32 +579,32 @@ module Exploit::Remote::SMBServer
|
|||
# print_status("New SMB connection from #{client.peerhost}:#{client.peerport}")
|
||||
smb_conn(client)
|
||||
end
|
||||
|
||||
|
||||
def on_client_data(client)
|
||||
# print_status("New data from #{client.peerhost}:#{client.peerport}")
|
||||
smb_recv(client)
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def on_client_close(client)
|
||||
smb_stop(client)
|
||||
end
|
||||
|
||||
|
||||
def smb_conn(c)
|
||||
@state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport}
|
||||
end
|
||||
|
||||
|
||||
def smb_stop(c)
|
||||
@state.delete(c)
|
||||
end
|
||||
|
||||
|
||||
def smb_recv(c)
|
||||
smb = @state[c]
|
||||
smb[:data] ||= ''
|
||||
smb[:data] << c.get_once
|
||||
|
||||
|
||||
while(smb[:data].length > 0)
|
||||
|
||||
|
||||
return if smb[:data].length < 4
|
||||
|
||||
plen = smb[:data][2,2].unpack('n')[0]
|
||||
|
@ -617,23 +621,23 @@ module Exploit::Remote::SMBServer
|
|||
# Check for a NetBIOS name request
|
||||
if (pkt_nbs.v['Type'] == 0x81)
|
||||
# Accept any name they happen to send
|
||||
|
||||
|
||||
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/, '')
|
||||
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/, '')
|
||||
|
||||
|
||||
smb[:nbdst] = host_dst
|
||||
smb[:nbsrc] = host_src
|
||||
|
||||
|
||||
# print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})")
|
||||
c.write("\x82\x00\x00\x00")
|
||||
next
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# TODO: Support AndX parameters
|
||||
#
|
||||
|
||||
#
|
||||
|
||||
|
||||
# Cast this to a generic SMB structure
|
||||
pkt = CONST::SMB_BASE_PKT.make_struct
|
||||
|
@ -641,10 +645,10 @@ module Exploit::Remote::SMBServer
|
|||
|
||||
# Only response to requests, ignore server replies
|
||||
if (pkt['Payload']['SMB'].v['Flags1'] & 128 != 0)
|
||||
print_status("Ignoring server response from #{smb[:name]}")
|
||||
print_status("Ignoring server response from #{smb[:name]}")
|
||||
next
|
||||
end
|
||||
|
||||
|
||||
cmd = pkt['Payload']['SMB'].v['Command']
|
||||
begin
|
||||
smb_cmd_dispatch(cmd, c, buff)
|
||||
|
@ -652,16 +656,16 @@ module Exploit::Remote::SMBServer
|
|||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_status("Error processing request from #{smb[:name]} (#{cmd}): #{e.class} #{e} #{e.backtrace}")
|
||||
next
|
||||
end
|
||||
end
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def smb_cmd_dispatch(cmd, c, buff)
|
||||
smb = @state[c]
|
||||
print_status("Received command #{cmd} from #{smb[:name]}")
|
||||
smb = @state[c]
|
||||
print_status("Received command #{cmd} from #{smb[:name]}")
|
||||
end
|
||||
|
||||
|
||||
def smb_set_defaults(c, pkt)
|
||||
smb = @state[c]
|
||||
pkt['Payload']['SMB'].v['ProcessID'] = smb[:process_id].to_i
|
||||
|
@ -669,8 +673,9 @@ module Exploit::Remote::SMBServer
|
|||
pkt['Payload']['SMB'].v['TreeID'] = smb[:tree_id].to_i
|
||||
pkt['Payload']['SMB'].v['MultiplexID'] = smb[:multiplex_id].to_i
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -2,28 +2,28 @@ module Msf
|
|||
|
||||
module EvasiveTCP
|
||||
attr_accessor :_send_size, :_send_delay, :evasive
|
||||
|
||||
|
||||
def denagle
|
||||
begin
|
||||
setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||
setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||
rescue ::Exception
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def write(buf, opts={})
|
||||
|
||||
|
||||
return super(buf, opts) if not @evasive
|
||||
|
||||
|
||||
ret = 0
|
||||
idx = 0
|
||||
len = @_send_size || buf.length
|
||||
|
||||
while(idx < buf.length)
|
||||
|
||||
|
||||
if(@_send_delay and idx > 0)
|
||||
select(nil, nil, nil, @_send_delay)
|
||||
end
|
||||
|
||||
|
||||
pkt = buf[idx, len]
|
||||
|
||||
res = super(pkt, opts)
|
||||
|
@ -31,7 +31,7 @@ module EvasiveTCP
|
|||
|
||||
idx += len
|
||||
ret += res if res
|
||||
end
|
||||
end
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
@ -60,7 +60,7 @@ module Exploit::Remote::Tcp
|
|||
|
||||
register_advanced_options(
|
||||
[
|
||||
Opt::SSL,
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
Opt::Proxies,
|
||||
Opt::CPORT,
|
||||
|
@ -68,7 +68,7 @@ module Exploit::Remote::Tcp
|
|||
OptInt.new('ConnectTimeout', [ true, 'Maximum number of seconds to establish a TCP connection', 10])
|
||||
], Msf::Exploit::Remote::Tcp
|
||||
)
|
||||
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
OptInt.new('TCP::max_send_size', [false, 'Maxiumum tcp segment size. (0 = disable)', 0]),
|
||||
|
@ -81,12 +81,23 @@ module Exploit::Remote::Tcp
|
|||
# Establishes a TCP connection to the specified RHOST/RPORT
|
||||
#
|
||||
def connect(global = true, opts={})
|
||||
|
||||
dossl = false
|
||||
if(opts.has_key?('SSL'))
|
||||
dossl = opts['SSL']
|
||||
else
|
||||
dossl = ssl
|
||||
if (datastore.default?('SSL') and rport.to_i == 443)
|
||||
dossl = true
|
||||
end
|
||||
end
|
||||
|
||||
nsock = Rex::Socket::Tcp.create(
|
||||
'PeerHost' => opts['RHOST'] || rhost,
|
||||
'PeerPort' => (opts['RPORT'] || rport).to_i,
|
||||
'LocalHost' => opts['CHOST'] || chost || "0.0.0.0",
|
||||
'LocalPort' => (opts['CPORT'] || cport || 0).to_i,
|
||||
'SSL' => opts['SSL'] || ssl,
|
||||
'SSL' => dossl,
|
||||
'SSLVersion'=> opts['SSLVersion'] || ssl_version,
|
||||
'Proxies' => proxies,
|
||||
'Timeout' => (opts['ConnectTimeout'] || connect_timeout || 10).to_i,
|
||||
|
@ -114,11 +125,11 @@ module Exploit::Remote::Tcp
|
|||
if( datastore['TCP::max_send_size'] == 0 and datastore['TCP::send_delay'] == 0)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
return if socket.respond_to?('evasive')
|
||||
|
||||
|
||||
socket.extend(EvasiveTCP)
|
||||
|
||||
|
||||
if ( datastore['TCP::max_send_size'] > 0)
|
||||
socket._send_size = datastore['TCP::max_send_size']
|
||||
socket.denagle
|
||||
|
@ -130,7 +141,7 @@ module Exploit::Remote::Tcp
|
|||
socket.evasive = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def handler(nsock = self.sock)
|
||||
# If the handler claims the socket, then we don't want it to get closed
|
||||
# during cleanup
|
||||
|
@ -162,7 +173,7 @@ module Exploit::Remote::Tcp
|
|||
if (nsock == sock)
|
||||
self.sock = nil
|
||||
end
|
||||
|
||||
|
||||
# Remove this socket from the list of sockets created by this exploit
|
||||
remove_socket(nsock)
|
||||
end
|
||||
|
@ -230,7 +241,7 @@ module Exploit::Remote::Tcp
|
|||
def ssl
|
||||
datastore['SSL']
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the string indicating SSLVersion
|
||||
#
|
||||
|
@ -240,18 +251,18 @@ module Exploit::Remote::Tcp
|
|||
|
||||
#
|
||||
# Returns the proxy configuration
|
||||
#
|
||||
#
|
||||
def proxies
|
||||
datastore['Proxies']
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the TCP connection timeout
|
||||
#
|
||||
#
|
||||
def connect_timeout
|
||||
datastore['ConnectTimeout']
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :sock
|
||||
|
@ -274,11 +285,12 @@ module Exploit::Remote::TcpServer
|
|||
|
||||
register_options(
|
||||
[
|
||||
Opt::SSL,
|
||||
OptBool.new('SSL', [ false, 'Negotiate SSL for incoming connections', false]),
|
||||
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]),
|
||||
OptAddress.new('SRVHOST', [ true, "The local host to listen on.", '0.0.0.0' ]),
|
||||
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 8080 ]),
|
||||
], Msf::Exploit::Remote::TcpServer)
|
||||
|
||||
|
||||
register_evasion_options(
|
||||
[
|
||||
OptInt.new('TCP::max_send_size', [false, 'Maximum tcp segment size. (0 = disable)', 0]),
|
||||
|
@ -292,13 +304,13 @@ module Exploit::Remote::TcpServer
|
|||
# service that corresponds with what the client has requested.
|
||||
#
|
||||
def exploit
|
||||
|
||||
|
||||
start_service()
|
||||
print_status("Server started.")
|
||||
|
||||
# Call the exploit primer
|
||||
# Call the exploit primer
|
||||
primer
|
||||
|
||||
|
||||
# Wait on the service to stop
|
||||
self.service.wait
|
||||
end
|
||||
|
@ -342,7 +354,7 @@ module Exploit::Remote::TcpServer
|
|||
#
|
||||
def start_service(*args)
|
||||
begin
|
||||
|
||||
|
||||
self.service = Rex::Socket::TcpServer.create(
|
||||
'LocalHost' => srvhost,
|
||||
'LocalPort' => srvport,
|
||||
|
@ -365,7 +377,7 @@ module Exploit::Remote::TcpServer
|
|||
|
||||
# Start the listening service
|
||||
self.service.start
|
||||
|
||||
|
||||
rescue ::Errno::EACCES => e
|
||||
if (srvport.to_i < 1024)
|
||||
print_line(" ")
|
||||
|
@ -420,19 +432,19 @@ module Exploit::Remote::TcpServer
|
|||
def ssl
|
||||
datastore['SSL']
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Re-generates the payload, substituting the current RHOST and RPORT with
|
||||
# the supplied client host and port from the socket.
|
||||
#
|
||||
def regenerate_payload(cli, arch = nil, platform = nil, target = nil)
|
||||
|
||||
|
||||
ohost = datastore['RHOST']
|
||||
oport = datastore['RPORT']
|
||||
p = nil
|
||||
|
||||
begin
|
||||
|
||||
begin
|
||||
# Update the datastore with the supplied client peerhost/peerport
|
||||
datastore['RHOST'] = cli.peerhost
|
||||
datastore['RPORT'] = cli.peerport
|
||||
|
@ -447,19 +459,20 @@ module Exploit::Remote::TcpServer
|
|||
'RHOST' => datastore['RHOST'],
|
||||
'RPORT' => datastore['RPORT']
|
||||
})
|
||||
|
||||
|
||||
ensure
|
||||
datastore['RHOST'] = ohost
|
||||
datastore['RPORT'] = oport
|
||||
datastore['RPORT'] = oport
|
||||
end
|
||||
|
||||
p
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
|
||||
attr_accessor :service # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class Module
|
|||
# user interface subscribes are designed to provide a flexible way of
|
||||
# interacting with the user, n stuff.
|
||||
include Rex::Ui::Subscriber
|
||||
|
||||
|
||||
# Make include public so we can runtime extend
|
||||
public_class_method :include
|
||||
|
||||
|
@ -35,18 +35,18 @@ class Module
|
|||
def fullname
|
||||
return type + '/' + refname
|
||||
end
|
||||
|
||||
|
||||
def shortname
|
||||
return refname.split('/')[-1]
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns this module's ranking.
|
||||
#
|
||||
def rank
|
||||
(const_defined?('Rank')) ? const_get('Rank') : NormalRanking
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns this module's ranking as a string representation.
|
||||
#
|
||||
|
@ -54,7 +54,7 @@ class Module
|
|||
RankingName[rank]
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# The module's name that is assigned it it by the framework
|
||||
# or derived from the path that the module is loaded from.
|
||||
#
|
||||
|
@ -133,7 +133,7 @@ class Module
|
|||
self.privileged = module_info['Privileged'] || false
|
||||
self.license = module_info['License'] || MSF_LICENSE
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Creates a fresh copy of an instantiated module
|
||||
#
|
||||
|
@ -148,25 +148,25 @@ class Module
|
|||
#
|
||||
# Overwrite the Subscriber print_line to do time stamps
|
||||
#
|
||||
|
||||
|
||||
def print_prefix
|
||||
if(
|
||||
datastore['TimestampOutput'] =~ /^(t|y|1)/i or
|
||||
datastore['TimestampOutput'] =~ /^(t|y|1)/i or
|
||||
framework.datastore['TimestampOutput'] =~ /^(t|y|1)/i
|
||||
)
|
||||
return "[#{Time.now.strftime("%Y.%m.%d-%H:%M:%S")}] "
|
||||
end
|
||||
""
|
||||
end
|
||||
|
||||
|
||||
def print_status(msg='')
|
||||
print_line(print_prefix + "[*] " + msg)
|
||||
end
|
||||
|
||||
|
||||
def print_error(msg='')
|
||||
print_line(print_prefix + "[-] " + msg)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the module's framework full reference name. This is the
|
||||
# short name that end-users work with (refname) plus the type
|
||||
|
@ -180,7 +180,7 @@ class Module
|
|||
|
||||
#
|
||||
# Returns the module's framework reference name. This is the
|
||||
# short name that end-users work with. Ex:
|
||||
# short name that end-users work with. Ex:
|
||||
#
|
||||
# windows/shell/reverse_tcp
|
||||
#
|
||||
|
@ -205,7 +205,7 @@ class Module
|
|||
def shortname
|
||||
return self.class.shortname
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns the unduplicated class associated with this module.
|
||||
#
|
||||
|
@ -278,7 +278,7 @@ class Module
|
|||
else
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
# Enumerate each compatibility item in our hash to find out
|
||||
# if we're compatible with this sucker.
|
||||
ch.each_pair do |k,v|
|
||||
|
@ -289,14 +289,14 @@ class Module
|
|||
|
||||
# Reject a filled compat item on one side, but not the other
|
||||
return false if (v and not mval)
|
||||
|
||||
|
||||
# Track how many of our values matched the module
|
||||
mcnt = 0
|
||||
|
||||
|
||||
# Values are whitespace separated
|
||||
sv = v.split(/\s+/)
|
||||
mv = mval.split(/\s+/)
|
||||
|
||||
|
||||
sv.each do |x|
|
||||
|
||||
dlog("Checking compat [#{mod.refname} with #{self.refname}]: #{x} to #{mv.join(", ")}", 'core', LEV_3)
|
||||
|
@ -309,10 +309,10 @@ class Module
|
|||
|
||||
mcnt += 1 if mv.include?(x)
|
||||
end
|
||||
|
||||
|
||||
# No values matched, reject this module
|
||||
if (mcnt == 0)
|
||||
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}, value was #{mval}", 'core', LEV_1)
|
||||
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}, value was #{mval}", 'core', LEV_1)
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -363,7 +363,7 @@ class Module
|
|||
def arch?(what)
|
||||
return true if (what == ARCH_ANY)
|
||||
|
||||
return arch.index(what) != nil
|
||||
return arch.index(what) != nil
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -420,7 +420,7 @@ class Module
|
|||
self.datastore.import_options_from_hash(module_info['DefaultOptions'], true, 'self')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This method ensures that the options associated with this module all
|
||||
# have valid values according to each required option in the option
|
||||
|
@ -485,7 +485,7 @@ class Module
|
|||
def self.cached?
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The array of zero or more authors.
|
||||
#
|
||||
|
@ -536,7 +536,7 @@ protected
|
|||
#
|
||||
def set_defaults
|
||||
self.module_info = {
|
||||
'Name' => 'No module name',
|
||||
'Name' => 'No module name',
|
||||
'Description' => 'No module description',
|
||||
'Version' => '0',
|
||||
'Author' => nil,
|
||||
|
@ -579,7 +579,7 @@ protected
|
|||
c['Encoder'].update(module_info['EncoderCompat'] || {})
|
||||
c['Nop'].update(module_info['NopCompat'] || {})
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Register options with a specific owning class.
|
||||
#
|
||||
|
@ -592,7 +592,7 @@ protected
|
|||
refs[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Purge invalid references
|
||||
refs.delete(nil)
|
||||
end
|
||||
|
@ -621,7 +621,7 @@ protected
|
|||
self.options.add_evasion_options(options, owner)
|
||||
self.datastore.import_options(self.options, 'self', true)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Removes the supplied options from the module's option container
|
||||
# and data store.
|
||||
|
@ -725,7 +725,7 @@ protected
|
|||
#
|
||||
def merge_info_name(info, val)
|
||||
merge_info_string(info, 'Name', val, ', ', true)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Merges the module description.
|
||||
|
@ -760,7 +760,7 @@ protected
|
|||
# Merges options.
|
||||
#
|
||||
def merge_info_options(info, val, advanced = false, evasion = false)
|
||||
|
||||
|
||||
key_name = ((advanced) ? 'Advanced' : (evasion) ? 'Evasion' : '') + 'Options'
|
||||
|
||||
new_cont = OptionContainer.new
|
||||
|
@ -776,21 +776,21 @@ protected
|
|||
}
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# Merges advanced options.
|
||||
#
|
||||
def merge_info_advanced_options(info, val)
|
||||
merge_info_options(info, val, true, false)
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# Merges advanced options.
|
||||
#
|
||||
def merge_info_evasion_options(info, val)
|
||||
merge_info_options(info, val, false, true)
|
||||
end
|
||||
|
||||
|
||||
|
||||
attr_accessor :module_info # :nodoc:
|
||||
attr_writer :author, :arch, :platform, :references, :datastore, :options # :nodoc:
|
||||
attr_writer :privileged # :nodoc:
|
||||
|
@ -809,3 +809,4 @@ Platform = Msf::Module::Platform
|
|||
Target = Msf::Module::Target
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class OptBase
|
|||
def evasion?
|
||||
return evasion
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns true if the supplied type is equivalent to this option's type.
|
||||
#
|
||||
|
@ -123,7 +123,7 @@ class OptBase
|
|||
#
|
||||
# The list of potential valid values
|
||||
#
|
||||
attr_accessor :enums
|
||||
attr_accessor :enums
|
||||
|
||||
protected
|
||||
|
||||
|
@ -152,10 +152,10 @@ end
|
|||
#
|
||||
###
|
||||
class OptString < OptBase
|
||||
def type
|
||||
return 'string'
|
||||
def type
|
||||
return 'string'
|
||||
end
|
||||
|
||||
|
||||
def normalize(value)
|
||||
if (value =~ /^file:(.*)/)
|
||||
path = $1
|
||||
|
@ -167,10 +167,10 @@ class OptString < OptBase
|
|||
end
|
||||
value
|
||||
end
|
||||
|
||||
|
||||
def valid?(value=self.value)
|
||||
value = normalize(value)
|
||||
return false if empty_required_value?(value)
|
||||
return false if empty_required_value?(value)
|
||||
return super
|
||||
end
|
||||
end
|
||||
|
@ -184,7 +184,7 @@ class OptRaw < OptBase
|
|||
def type
|
||||
return 'raw'
|
||||
end
|
||||
|
||||
|
||||
def normalize(value)
|
||||
if (value =~ /^file:(.*)/)
|
||||
path = $1
|
||||
|
@ -196,12 +196,12 @@ class OptRaw < OptBase
|
|||
end
|
||||
value
|
||||
end
|
||||
|
||||
|
||||
def valid?(value=self.value)
|
||||
value = normalize(value)
|
||||
return false if empty_required_value?(value)
|
||||
return false if empty_required_value?(value)
|
||||
return super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
|
@ -220,7 +220,7 @@ class OptBool < OptBase
|
|||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
|
||||
if ((value != nil and
|
||||
if ((value != nil and
|
||||
(value.to_s.empty? == false) and
|
||||
(value.to_s.match(/^(y|yes|n|no|t|f|0|1|true|false)$/i) == nil)))
|
||||
return false
|
||||
|
@ -277,7 +277,7 @@ class OptEnum < OptBase
|
|||
|
||||
self.desc
|
||||
end
|
||||
|
||||
|
||||
def desc
|
||||
if self.enums
|
||||
str = self.enums.join(', ')
|
||||
|
@ -298,8 +298,8 @@ end
|
|||
#
|
||||
###
|
||||
class OptPort < OptBase
|
||||
def type
|
||||
return 'port'
|
||||
def type
|
||||
return 'port'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
|
@ -320,8 +320,8 @@ end
|
|||
#
|
||||
###
|
||||
class OptAddress < OptBase
|
||||
def type
|
||||
return 'address'
|
||||
def type
|
||||
return 'address'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
|
@ -345,8 +345,8 @@ end
|
|||
#
|
||||
###
|
||||
class OptAddressRange < OptBase
|
||||
def type
|
||||
return 'addressrange'
|
||||
def type
|
||||
return 'addressrange'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
|
@ -359,20 +359,20 @@ class OptAddressRange < OptBase
|
|||
value = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
sets = []
|
||||
return '' if not value
|
||||
|
||||
ranges = value.split(',')
|
||||
ranges = value.split(',')
|
||||
ranges.each do |range|
|
||||
|
||||
|
||||
tmp = range.split('-')
|
||||
tmp[1] ||= tmp[0]
|
||||
|
||||
|
||||
if(tmp[0] == tmp[1] and tmp[0] =~ /\//)
|
||||
tmp = Rex::Socket.cidr_crack(tmp[0])
|
||||
end
|
||||
|
||||
|
||||
addr_a, addr_b = tmp
|
||||
addr_a, scope = tmp[0].split("%")
|
||||
addr_b, scope = tmp[1].split("%") if not scope
|
||||
|
@ -381,10 +381,10 @@ class OptAddressRange < OptBase
|
|||
sets << tmp
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
sets.map {|i| (i.length == 2 and i[0] != i[1]) ? i[0]+'-'+i[1] : i[0] }.join(",")
|
||||
end
|
||||
|
||||
|
||||
def valid?(value)
|
||||
return false if empty_required_value?(value)
|
||||
|
||||
|
@ -406,8 +406,8 @@ end
|
|||
#
|
||||
###
|
||||
class OptPath < OptBase
|
||||
def type
|
||||
return 'path'
|
||||
def type
|
||||
return 'path'
|
||||
end
|
||||
|
||||
def valid?(value)
|
||||
|
@ -428,8 +428,8 @@ end
|
|||
#
|
||||
###
|
||||
class OptInt < OptBase
|
||||
def type
|
||||
return 'integer'
|
||||
def type
|
||||
return 'integer'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
|
@ -456,7 +456,7 @@ end
|
|||
#
|
||||
# The options purpose in life is to associate named options
|
||||
# with arbitrary values at the most simplistic level. Each
|
||||
# module contains a OptionContainer that is used to hold the
|
||||
# module contains a OptionContainer that is used to hold the
|
||||
# various options that the module depends on. Example of options
|
||||
# that are stored in the OptionContainer are rhost and rport for
|
||||
# payloads or exploits that need to connect to a host and
|
||||
|
@ -499,9 +499,9 @@ class OptionContainer < Hash
|
|||
def has_options?
|
||||
each_option { |name, opt|
|
||||
return true if (opt.advanced? == false)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -516,7 +516,7 @@ class OptionContainer < Hash
|
|||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Returns whether or not the container has any evasion
|
||||
# options.
|
||||
|
@ -528,7 +528,7 @@ class OptionContainer < Hash
|
|||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Removes an option.
|
||||
#
|
||||
|
@ -577,8 +577,8 @@ class OptionContainer < Hash
|
|||
if (option.kind_of?(Array))
|
||||
option = option.shift.new(name, option)
|
||||
elsif (!option.kind_of?(OptBase))
|
||||
raise ArgumentError,
|
||||
"The option named #{name} did not come in a compatible format.",
|
||||
raise ArgumentError,
|
||||
"The option named #{name} did not come in a compatible format.",
|
||||
caller
|
||||
end
|
||||
|
||||
|
@ -611,13 +611,13 @@ class OptionContainer < Hash
|
|||
end
|
||||
|
||||
#
|
||||
# Make sures that each of the options has a value of a compatible
|
||||
# Make sures that each of the options has a value of a compatible
|
||||
# format and that all the required options are set.
|
||||
#
|
||||
def validate(datastore)
|
||||
errors = []
|
||||
|
||||
each_pair { |name, option|
|
||||
each_pair { |name, option|
|
||||
if (!option.valid?(datastore[name]))
|
||||
errors << name
|
||||
# If the option is valid, normalize its format to the correct type.
|
||||
|
@ -625,9 +625,9 @@ class OptionContainer < Hash
|
|||
datastore.update_value(name, val)
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
if (errors.empty? == false)
|
||||
raise OptionValidateError.new(errors),
|
||||
raise OptionValidateError.new(errors),
|
||||
"One or more options failed to validate", caller
|
||||
end
|
||||
|
||||
|
@ -690,7 +690,7 @@ end
|
|||
#
|
||||
module Opt
|
||||
|
||||
@@builtin_opts =
|
||||
@@builtin_opts =
|
||||
{
|
||||
'RHOST' => [ OptAddress, 'nil', true, '"The target address"' ],
|
||||
'RPORT' => [ OptPort, 'nil', true, '"The target port"' ],
|
||||
|
@ -698,8 +698,7 @@ module Opt
|
|||
'LPORT' => [ OptPort, 'nil', true, '"The local port"' ],
|
||||
'CPORT' => [ OptPort, 'nil', false, '"The local client port"' ],
|
||||
'CHOST' => [ OptAddress, 'nil', false, '"The local client address"' ],
|
||||
'SSL' => [ OptBool, 'false', false, '"Use SSL"' ],
|
||||
'Proxies' => [ OptString, 'nil', 'false', '"Use a proxy chain"'],
|
||||
'Proxies' => [ OptString, 'nil', 'false', '"Use a proxy chain"']
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -719,7 +718,7 @@ class <<self
|
|||
}
|
||||
end
|
||||
|
||||
#
|
||||
#
|
||||
# Define the constant versions of the options which are merely redirections to
|
||||
# the class methods.
|
||||
#
|
||||
|
@ -730,3 +729,4 @@ end
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue