2005-10-03 13:51:05 +00:00
|
|
|
require 'rex/proto/smb'
|
|
|
|
require 'rex/proto/dcerpc'
|
|
|
|
|
|
|
|
module Msf
|
|
|
|
|
|
|
|
###
|
|
|
|
#
|
|
|
|
# This mixin provides utility methods for interacting with a SMB/CIFS service on
|
|
|
|
# a remote machine. These methods may generally be useful in the context of
|
|
|
|
# exploitation. This mixin extends the Tcp exploit mixin. Only one SMB
|
|
|
|
# service can be accessed at a time using this class.
|
|
|
|
#
|
|
|
|
###
|
|
|
|
|
|
|
|
module Exploit::Remote::SMB
|
|
|
|
|
|
|
|
include Exploit::Remote::Tcp
|
|
|
|
SIMPLE = Rex::Proto::SMB::SimpleClient
|
|
|
|
XCEPT = Rex::Proto::SMB::Exceptions
|
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
# Alias over the Rex DCERPC protocol modules
|
|
|
|
DCERPCPacket = Rex::Proto::DCERPC::Packet
|
|
|
|
DCERPCClient = Rex::Proto::DCERPC::Client
|
|
|
|
DCERPCResponse = Rex::Proto::DCERPC::Response
|
|
|
|
DCERPCUUID = Rex::Proto::DCERPC::UUID
|
|
|
|
|
2005-10-03 13:51:05 +00:00
|
|
|
def initialize(info = {})
|
|
|
|
super
|
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
register_advanced_options(
|
|
|
|
[
|
|
|
|
OptInt.new('SMBPipeWriteMinSize', [ true, 'Minimum buffer size for pipe writes', 512]),
|
|
|
|
OptInt.new('SMBPipeWriteMaxSize', [ true, 'Maximum buffer size for pipe writes', 512]),
|
|
|
|
OptInt.new('SMBPipeReadMinSize', [ true, 'Minimum buffer size for pipe reads', 512]),
|
|
|
|
OptInt.new('SMBPipeReadMaxSize', [ true, 'Maximum buffer size for pipe reads', 512]),
|
|
|
|
], Msf::Exploit::Remote::SMB)
|
|
|
|
|
2005-10-03 13:51:05 +00:00
|
|
|
register_options(
|
|
|
|
[
|
|
|
|
Opt::RHOST,
|
2005-11-15 23:02:17 +00:00
|
|
|
OptInt.new('RPORT', [ true, 'Set the SMB service port', 445]),
|
|
|
|
OptBool.new('SMBDirect', [ true, 'The target port is a raw SMB service (not NetBIOS)', 'True' ]),
|
|
|
|
OptString.new('SMBUSER', [ false, 'The username to authenticate as', '']),
|
|
|
|
OptString.new('SMBPASS', [ false, 'The password for the specified username', '']),
|
|
|
|
OptString.new('SMBDOM', [ false, 'The Windows domain to use for authentication', 'WORKGROUP']),
|
|
|
|
OptString.new('SMBNAME', [ true, 'The NetBIOS hostname (required for port 139 connections)', '*SMBSERVER'])
|
2005-10-03 13:51:05 +00:00
|
|
|
|
|
|
|
], Msf::Exploit::Remote::SMB)
|
|
|
|
end
|
|
|
|
|
2005-11-16 17:56:07 +00:00
|
|
|
# Convert a standard ASCII string to 16-bit Unicode
|
|
|
|
def unicode (str)
|
|
|
|
str.unpack('C*').pack('v*')
|
|
|
|
end
|
|
|
|
|
2005-10-03 13:51:05 +00:00
|
|
|
def smb_login
|
|
|
|
self.simple = SIMPLE.new(self.sock, datastore['SMBDirect'])
|
|
|
|
|
|
|
|
simple.login(
|
|
|
|
datastore['SMBNAME'],
|
|
|
|
datastore['SMBUSER'],
|
|
|
|
datastore['SMBPASS'],
|
|
|
|
datastore['SMBDOM']
|
|
|
|
)
|
2005-11-15 23:02:17 +00:00
|
|
|
|
|
|
|
simple.connect('IPC$')
|
2005-10-03 13:51:05 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def smb_peer_os
|
|
|
|
self.simple.client.peer_native_os
|
|
|
|
end
|
|
|
|
|
|
|
|
def smb_peer_lm
|
|
|
|
self.simple.client.peer_native_lm
|
|
|
|
end
|
|
|
|
|
|
|
|
def smb_create(pipe)
|
|
|
|
self.simple.create_pipe(pipe)
|
|
|
|
end
|
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
def smb_dcerpc_bind(fid, uuid, vers = nil)
|
|
|
|
|
|
|
|
# Create the bind request
|
|
|
|
bind, ctx = dcerpc_make_bind(uuid, vers)
|
|
|
|
if (bind == nil)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
data = smb_pipe_transaction(fid, bind)
|
|
|
|
return DCERPCResponse.new(data) if data.length > 0
|
2005-10-03 13:51:05 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def smb_dcerpc_call(fid, func, stub = '')
|
2005-11-15 23:02:17 +00:00
|
|
|
# Create the request packets
|
|
|
|
pkts = dcerpc_make_call(func, stub)
|
|
|
|
if (pkts == nil)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
# Verify that the socket exists
|
|
|
|
if (sock == nil)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
data = ''
|
|
|
|
print_status("Sending " + pkts.size.to_s + " DCERPC fragments...")
|
|
|
|
pkts.each { |chunk|
|
|
|
|
data << smb_pipe_transaction(fid, stub)
|
|
|
|
}
|
|
|
|
|
|
|
|
return DCERPCResponse.new(data) if data.length > 0
|
2005-10-03 13:51:05 +00:00
|
|
|
end
|
2005-11-15 23:02:17 +00:00
|
|
|
|
|
|
|
def smb_pipe_transaction(fid, request)
|
2005-10-03 13:51:05 +00:00
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
# Evasion techniques:
|
|
|
|
# 1) Write the bind out a few bytes at a time with a random offset
|
|
|
|
# 2) Read the response back a few bytes at a time with a random offset
|
|
|
|
|
|
|
|
pipe_write_min = datastore['SMBPipeWriteMinSize']
|
|
|
|
pipe_write_max = datastore['SMBPipeWriteMaxSize']
|
|
|
|
pipe_read_min = datastore['SMBPipeReadMinSize']
|
|
|
|
pipe_read_max = datastore['SMBPipeReadMaxSize']
|
|
|
|
|
|
|
|
|
|
|
|
if (pipe_write_min > pipe_write_max)
|
|
|
|
pipe_write_min = pipe_write_max
|
|
|
|
end
|
|
|
|
|
|
|
|
if (pipe_read_min > pipe_read_max)
|
|
|
|
pipe_read_min = pipe_read_max
|
|
|
|
end
|
|
|
|
|
|
|
|
# Write the request out in random chunk sizes
|
|
|
|
while (request.length > 0)
|
|
|
|
wsize = rand(pipe_write_max - pipe_write_min) + pipe_write_min
|
|
|
|
fid.write( request.slice!(0, wsize), rand(1024)+1 )
|
|
|
|
end
|
|
|
|
|
|
|
|
data = ''
|
|
|
|
# Read the response back a few bytes a time
|
|
|
|
begin
|
|
|
|
while(true)
|
|
|
|
rsize = rand(pipe_read_max - pipe_read_min) + pipe_read_min
|
|
|
|
t = (fid.read(rsize, rand(1024)+1))
|
2005-11-16 17:56:07 +00:00
|
|
|
last if t.length == 0
|
2005-11-15 23:02:17 +00:00
|
|
|
data << t
|
|
|
|
end
|
|
|
|
rescue XCEPT::NoReply
|
|
|
|
end
|
2005-10-03 13:51:05 +00:00
|
|
|
|
2005-11-15 23:02:17 +00:00
|
|
|
return data
|
|
|
|
end
|
|
|
|
|
|
|
|
attr_accessor :simple
|
2005-10-03 13:51:05 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
end
|