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-b9f4589650da
unstable
HD Moore 2009-11-03 18:09:05 +00:00
parent 84ebdfa7eb
commit 737dc327a3
6 changed files with 302 additions and 264 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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